Skip to content

Commit

Permalink
chore(merge): release-10.2.0 into dev
Browse files Browse the repository at this point in the history
  • Loading branch information
bonita-ci committed Sep 9, 2024
2 parents 910c64c + ccce2b4 commit 67b6ac0
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@

public class HumanTasksIT extends TestWithUser {

final static int INTIALIZING_STATE_ID = 32;
final static int INITIALIZING_STATE_ID = 32;

@Test
public void cannotGetHumanTaskInstances() throws Exception {
Expand Down Expand Up @@ -433,7 +433,7 @@ public void setState() throws Exception {
HumanTaskInstance step1 = waitForUserTaskAndGetIt(processInstance, "step1");

final long activityInstanceId = step1.getId();
getProcessAPI().setActivityStateById(activityInstanceId, INTIALIZING_STATE_ID);
getProcessAPI().setActivityStateById(activityInstanceId, INITIALIZING_STATE_ID);
step1 = getProcessAPI().getHumanTaskInstance(activityInstanceId);
assertEquals(ActivityStates.INITIALIZING_STATE, step1.getState());

Expand Down Expand Up @@ -472,7 +472,7 @@ public void setStateShouldTerminateATaskWithBoundaryEvent() throws Exception {
assertThat(eventInstances.size()).isEqualTo(1);

final long activityInstanceId = step1.getId();
getProcessAPI().setActivityStateById(activityInstanceId, INTIALIZING_STATE_ID);
getProcessAPI().setActivityStateById(activityInstanceId, INITIALIZING_STATE_ID);
step1 = getProcessAPI().getHumanTaskInstance(activityInstanceId);
assertEquals(ActivityStates.INITIALIZING_STATE, step1.getState());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<logger name="org.hibernate.orm.cache" level="WARN" />
<logger name="org.hibernate.SQL_SLOW" level="INFO"/>
<logger name="org.bonitasoft.engine.execution.ProcessStarterVerifierImpl" level="DEBUG"/>
<logger name="org.bonitasoft.engine.execution.ProcessCounterChecker" level="DEBUG"/>

<root level="INFO">
<appender-ref ref="STDOUT" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package org.bonitasoft.engine.execution;

import static java.lang.String.format;
import static java.lang.System.currentTimeMillis;

import java.io.IOException;
import java.security.GeneralSecurityException;
Expand All @@ -26,6 +27,7 @@
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.bonitasoft.engine.core.process.instance.api.ProcessInstanceService;
import org.bonitasoft.engine.core.process.instance.api.exceptions.SProcessInstanceCreationException;
import org.bonitasoft.engine.core.process.instance.model.SProcessInstance;
import org.bonitasoft.engine.platform.PlatformRetriever;
Expand All @@ -51,21 +53,30 @@ public class ProcessStarterVerifierImpl implements ProcessStarterVerifier {

private final PlatformRetriever platformRetriever;
private final PlatformInformationService platformInformationService;
private final TransactionService transactionService;
private final ProcessInstanceService processInstanceService;

private final List<Long> counters = Collections.synchronizedList(new ArrayList<>());

@Autowired
ProcessStarterVerifierImpl(PlatformRetriever platformRetriever,
PlatformInformationService platformInformationService) {
PlatformInformationService platformInformationService,
TransactionService transactionService,
ProcessInstanceService processInstanceService) throws Exception {
this.platformRetriever = platformRetriever;
this.platformInformationService = platformInformationService;
this.transactionService = transactionService;
this.processInstanceService = processInstanceService;
counters.addAll(setupCounters(transactionService));
// clean up old values:
final long oldestValidDate = currentTimeMillis() - PERIOD_IN_MILLIS;
cleanupOldValues(oldestValidDate);
// then check database integrity:
verifyCountersCoherence(counters, oldestValidDate);
}

@Autowired
ProcessStarterVerifierImpl(PlatformRetriever platformRetriever,
PlatformInformationService platformInformationService,
TransactionService transactionService) throws Exception {
this(platformRetriever, platformInformationService);
counters.addAll(transactionService.executeInTransaction(this::readCounters));
List<Long> setupCounters(TransactionService transactionService) throws Exception {
return transactionService.executeInTransaction(this::readCounters);
}

protected List<Long> getCounters() {
Expand All @@ -80,8 +91,9 @@ protected void addCounter(long counter) {

@Override
public void verify(SProcessInstance processInstance) throws SProcessInstanceCreationException {
log.debug("Verifying process instance {}", processInstance.getId());
cleanupOldValues();
log.debug("Verifying the possibility to create process instance {}", processInstance.getId());
final long processStartDate = processInstance.getStartDate();
cleanupOldValues(processStartDate - PERIOD_IN_MILLIS);
log.debug("Found {} cases already started in the last {} days", counters.size(), PERIOD_IN_DAYS);
if (counters.size() >= LIMIT) {
final String nextValidTime = getStringRepresentation(getNextResetTimestamp(counters));
Expand All @@ -91,7 +103,7 @@ public void verify(SProcessInstance processInstance) throws SProcessInstanceCrea
}
try {
synchronized (counters) {
counters.add(System.currentTimeMillis());
counters.add(processStartDate);
}
final String information = encryptDataBeforeSendingToDatabase(counters);
// store in database:
Expand All @@ -104,11 +116,10 @@ public void verify(SProcessInstance processInstance) throws SProcessInstanceCrea
}
}

void cleanupOldValues() {
void cleanupOldValues(long olderThanInMilliseconds) {
log.trace("Cleaning up old values for the last {} days", PERIOD_IN_DAYS);
final long oldestValidTimestamp = System.currentTimeMillis() - PERIOD_IN_MILLIS;
synchronized (counters) {
counters.removeIf(timestamp -> timestamp < oldestValidTimestamp);
counters.removeIf(timestamp -> timestamp < olderThanInMilliseconds);
}
}

Expand Down Expand Up @@ -153,6 +164,24 @@ private static byte[] decrypt(String information) {
}
}

List<Long> fetchLastArchivedProcessInstanceStartDates(Long oldestValidDate) throws Exception {
final List<Long> startDates = transactionService.executeInTransaction(
() -> processInstanceService.getLastArchivedProcessInstanceStartDates(oldestValidDate));
// print the start dates to the log:
log.debug("Last archived process instance start dates: {}", startDates);
return startDates;
}

public void verifyCountersCoherence(List<Long> counters, Long oldestValidDate) throws Exception {
final List<Long> lastArchivedProcessInstanceStartDates = fetchLastArchivedProcessInstanceStartDates(
oldestValidDate);
for (Long startDate : lastArchivedProcessInstanceStartDates) {
if (!counters.contains(startDate)) {
throw new IllegalStateException("Invalid database. Please reset it and restart.");
}
}
}

void logCaseLimitProgressIfThresholdReached() {
var percentBeforeThisNewCase = (float) ((getCounters().size() - 1) * 100) / LIMIT;
var percentWithThisNewCase = (float) ((getCounters().size()) * 100) / LIMIT;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,49 +14,58 @@
package org.bonitasoft.engine.execution;

import static com.github.stefanbirkner.systemlambda.SystemLambda.tapSystemOut;
import static java.lang.System.currentTimeMillis;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.bonitasoft.engine.execution.ProcessStarterVerifierImpl.LIMIT;
import static org.bonitasoft.engine.execution.ProcessStarterVerifierImpl.PERIOD_IN_MILLIS;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.bonitasoft.engine.core.process.instance.api.ProcessInstanceService;
import org.bonitasoft.engine.core.process.instance.api.exceptions.SProcessInstanceCreationException;
import org.bonitasoft.engine.core.process.instance.model.SProcessInstance;
import org.bonitasoft.engine.platform.PlatformRetriever;
import org.bonitasoft.engine.platform.model.SPlatform;
import org.bonitasoft.engine.service.platform.PlatformInformationService;
import org.bonitasoft.engine.transaction.TransactionService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

@ExtendWith(MockitoExtension.class)
class ProcessStarterVerifierTest {
class ProcessStarterVerifierImplTest {

@Mock
private PlatformRetriever platformRetriever;

@Mock
private PlatformInformationService platformInformationService;
@Mock
private TransactionService transactionService;
@Mock
private ProcessInstanceService processInstanceService;

ProcessStarterVerifierImpl processStarterVerifier;
private ProcessStarterVerifierImpl processStarterVerifier;

@BeforeEach
void setUp() {
processStarterVerifier = Mockito
.spy(new ProcessStarterVerifierImpl(platformRetriever, platformInformationService));
public void initMocks() throws Exception {
doReturn(new ArrayList<>()).when(transactionService).executeInTransaction(any());
processStarterVerifier = spy(new ProcessStarterVerifierImpl(platformRetriever, platformInformationService,
transactionService, processInstanceService));
}

@Test
void should_be_able_to_decrypt_encrypted_value() throws Exception {
//given
final long currentTime = System.currentTimeMillis();
final long currentTime = currentTimeMillis();
final var originalValue = List.of(currentTime, currentTime + 1000L, currentTime + 2000L);

//when
Expand All @@ -70,7 +79,7 @@ void should_be_able_to_decrypt_encrypted_value() throws Exception {
@Test
void verify_should_not_remove_still_valid_values_from_counters() throws Exception {
//given
final long validTimestamp = System.currentTimeMillis() - PERIOD_IN_MILLIS + 86400000L; // plus 1 day
final long validTimestamp = currentTimeMillis() - PERIOD_IN_MILLIS + 86400000L; // plus 1 day
processStarterVerifier.addCounter(validTimestamp);
doNothing().when(processStarterVerifier).storeNewValueInDatabase(anyString());

Expand All @@ -85,7 +94,7 @@ void verify_should_not_remove_still_valid_values_from_counters() throws Exceptio
@Test
void verify_should_remove_old_values_from_counters() throws Exception {
//given
final long obsoleteValue = System.currentTimeMillis() - PERIOD_IN_MILLIS - 86400000L; // minus 1 day
final long obsoleteValue = currentTimeMillis() - PERIOD_IN_MILLIS - 86400000L; // minus 1 day
processStarterVerifier.addCounter(obsoleteValue);
doNothing().when(processStarterVerifier).storeNewValueInDatabase(anyString());

Expand All @@ -101,12 +110,14 @@ void verify_should_remove_old_values_from_counters() throws Exception {
void verify_should_throw_exception_if_limit_is_reached() throws Exception {
//given
for (int i = 0; i < LIMIT; i++) {
processStarterVerifier.addCounter(System.currentTimeMillis());
processStarterVerifier.addCounter(currentTimeMillis());
}
final SProcessInstance processInstance = mock(SProcessInstance.class);
doReturn(currentTimeMillis() + 1000L).when(processInstance).getStartDate();

//when - then
assertThatExceptionOfType(SProcessInstanceCreationException.class)
.isThrownBy(() -> processStarterVerifier.verify(new SProcessInstance()))
.isThrownBy(() -> processStarterVerifier.verify(processInstance))
.withMessageContaining("Process start limit");
assertThat(processStarterVerifier.getCounters()).size().isEqualTo(LIMIT);
verify(processStarterVerifier, never()).storeNewValueInDatabase(anyString());
Expand Down Expand Up @@ -187,7 +198,7 @@ void readCounters_should_succeed_if_counters_can_be_decrypted_from_database() th
final String encryptedValue = "encrypted value";
platform.setInformation(encryptedValue);
doReturn(platform).when(platformRetriever).getPlatform();
final List<Long> countersFromDatabase = List.of(System.currentTimeMillis());
final List<Long> countersFromDatabase = List.of(currentTimeMillis());
doReturn(countersFromDatabase).when(processStarterVerifier).decryptDataFromDatabase(encryptedValue);

// when
Expand All @@ -196,4 +207,31 @@ void readCounters_should_succeed_if_counters_can_be_decrypted_from_database() th
// then
assertThat(counters).isEqualTo(countersFromDatabase);
}

@Test
void verify_should_pass_if_all_counters_found_in_archives_are_found_in_counters() throws Exception {
// given
final long shouldBeThereTimestamp = currentTimeMillis();
final long oldestValidDate = 1212000002999L;
doReturn(List.of(shouldBeThereTimestamp)).when(processStarterVerifier)
.fetchLastArchivedProcessInstanceStartDates(oldestValidDate);

// when - then
assertDoesNotThrow(() -> processStarterVerifier
.verifyCountersCoherence(List.of(shouldBeThereTimestamp, 1111252531354L), oldestValidDate));

}

@Test
void verify_should_fail_if_counters_do_not_contains_data_found_in_archives() throws Exception {
// given
final Long oldestValidDate = currentTimeMillis();
doReturn(List.of(currentTimeMillis())).when(processStarterVerifier)
.fetchLastArchivedProcessInstanceStartDates(oldestValidDate);

// when - then
assertThrows(IllegalStateException.class,
() -> processStarterVerifier.verifyCountersCoherence(List.of(), oldestValidDate));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,15 @@ long getNumberOfOpenProcessInstancesInvolvingUsersManagedBy(long managerUserId,
List<SProcessInstance> searchOpenProcessInstancesInvolvingUsersManagedBy(long managerUserId,
QueryOptions queryOptions) throws SBonitaReadException;

/**
* Get the list of all archived process instance start dates since the given date
*
* @param sinceDateInMillis the date since when we want to get the list of start dates (in milliseconds)
* @return the list of all archived process instance start dates, expressed in millis since EPOCH.
* @throws SProcessInstanceReadException if an exception occurs while reading the process instances
*/
List<Long> getLastArchivedProcessInstanceStartDates(long sinceDateInMillis) throws SProcessInstanceReadException;

/**
* Get the list of sourceObjectIds for archived process instances children of process instance identified by
* rootProcessIntanceId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,21 @@ public List<SAProcessInstance> getArchivedProcessInstancesInAllStates(final List
}
}

@Override
public List<Long> getLastArchivedProcessInstanceStartDates(final long sinceDateInMillis)
throws SProcessInstanceReadException {
final ReadPersistenceService persistenceService = archiveService.getDefinitiveArchiveReadPersistenceService();
try {
final Map<String, Object> parameters = Collections.singletonMap("sinceDateInMillis", sinceDateInMillis);
final SelectListDescriptor<Long> saProcessInstances = new SelectListDescriptor<>(
"getLastArchivedProcessInstanceStartDates", parameters, SAProcessInstance.class,
QueryOptions.countQueryOptions());
return persistenceService.selectList(saProcessInstances);
} catch (final SBonitaReadException e) {
throw new SProcessInstanceReadException(e);
}
}

protected Set<Integer> getStateIdsFromStates(final ProcessInstanceState... states) {
if (states.length < 1) {
throw new IllegalArgumentException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,13 @@
WHERE ap.sourceObjectId IN (:sourceObjectIds)
</query>

<query name="getLastArchivedProcessInstanceStartDates">
SELECT DISTINCT ap.startDate
FROM org.bonitasoft.engine.core.process.instance.model.archive.SAProcessInstance AS ap
WHERE ap.stateId = 0
AND ap.startDate &gt;= :sinceDateInMillis
</query>

<query name="getArchivedProcessInstance">
SELECT ap
FROM org.bonitasoft.engine.core.process.instance.model.archive.SAProcessInstance AS ap
Expand Down

0 comments on commit 67b6ac0

Please sign in to comment.