diff --git a/drools-reliability/drools-reliability-infinispan/src/test/java/org/drools/reliability/infinispan/CachePersistenceTest.java b/drools-reliability/drools-reliability-infinispan/src/test/java/org/drools/reliability/infinispan/CachePersistenceTest.java index e84ca1b99e5..535542aa876 100644 --- a/drools-reliability/drools-reliability-infinispan/src/test/java/org/drools/reliability/infinispan/CachePersistenceTest.java +++ b/drools-reliability/drools-reliability-infinispan/src/test/java/org/drools/reliability/infinispan/CachePersistenceTest.java @@ -19,6 +19,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; +import org.kie.api.runtime.KieSession; import org.kie.api.runtime.conf.PersistedSessionOption; import org.test.domain.Person; @@ -74,24 +75,43 @@ void ksessionDispose_shouldRemoveCache(PersistedSessionOption.PersistenceStrateg @ParameterizedTest @MethodSource("strategyProviderStoresOnly") - void missingDispose_shouldNotReuseOrphanedCache(PersistedSessionOption.PersistenceStrategy strategy) { - createSession(EMPTY_RULE, strategy); // sessionId = 0 - insertNonMatchingPerson("Toshiya", 10); + void missingDispose_shouldNotReuseOrphanedCache(PersistedSessionOption.PersistenceStrategy strategy, PersistedSessionOption.SafepointStrategy safepointStrategy) { + KieSession firstSession = createSession(EMPTY_RULE, strategy, safepointStrategy); + assertThat(persistedSessionIds.get(firstSession.getIdentifier())) + .as("firstSession's persisted session id = 0") + .isEqualTo(0); + + insertNonMatchingPerson(firstSession,"Toshiya", 10); - // disposeSession() is missing + Optional toshiyaInFirstSession = getPersonByName(firstSession, "Toshiya"); + assertThat(toshiyaInFirstSession).isNotEmpty(); + + // disposeSession() for the first session is missing. Simulating that the first session is completely lost from client side. failover(); - createSession(EMPTY_RULE, strategy); // new session. If sessionId = 0, it will potentially reuse the orphaned cache + // create a new session. + KieSession secondSession = createSession(EMPTY_RULE, strategy, safepointStrategy); + assertThat(persistedSessionIds.get(secondSession.getIdentifier())) + .as("second session's persisted session id = 1. Don't reuse the orphaned cache") + .isEqualTo(1); - Optional toshiya = getPersonByName("Toshiya"); - assertThat(toshiya).isEmpty(); // new session doesn't trigger re-propagation + Optional toshiyaInSecondSession = getPersonByName(secondSession, "Toshiya"); + assertThat(toshiyaInSecondSession) + .as("new session doesn't have the fact") + .isEmpty(); failover(); - restoreSession(EMPTY_RULE, strategy); // restoreSession triggers re-propagation + // restore secondSession + KieSession thirdSession = restoreSession(secondSession.getIdentifier(), EMPTY_RULE, strategy, safepointStrategy); + assertThat(persistedSessionIds.get(thirdSession.getIdentifier())) + .as("third session's persisted session id = 1. Don't reuse the orphaned cache") + .isEqualTo(1); - toshiya = getPersonByName("Toshiya"); - assertThat(toshiya).isEmpty(); // should not reuse the orphaned cache + Optional toshiyaInThirdSession = getPersonByName(thirdSession, "Toshiya"); + assertThat(toshiyaInThirdSession) + .as("thirdSession takes over the secondSession's cache. It doesn't have the fact") + .isEmpty(); } @ParameterizedTest diff --git a/drools-reliability/drools-reliability-infinispan/src/test/java/org/drools/reliability/infinispan/ReliabilityTest.java b/drools-reliability/drools-reliability-infinispan/src/test/java/org/drools/reliability/infinispan/ReliabilityTest.java index 611a408534f..5382d728408 100644 --- a/drools-reliability/drools-reliability-infinispan/src/test/java/org/drools/reliability/infinispan/ReliabilityTest.java +++ b/drools-reliability/drools-reliability-infinispan/src/test/java/org/drools/reliability/infinispan/ReliabilityTest.java @@ -308,7 +308,7 @@ void insertNonMatching_Failover_UpdateWithMatching_ShouldFiredMatch(PersistedSes } @ParameterizedTest - @MethodSource("strategyProviderStoresOnlyWithExplicitSafepoints") // FAILS in STORES_ONLY, EXPLICIT + @MethodSource("strategyProviderStoresOnlyWithExplicitSafepoints") void multipleKieSessions_BasicTest(PersistedSessionOption.PersistenceStrategy persistenceStrategy, PersistedSessionOption.SafepointStrategy safepointStrategy) { KieSession session1 = createSession(BASIC_RULE, persistenceStrategy, safepointStrategy); KieSession session2 = createSession(BASIC_RULE, persistenceStrategy, safepointStrategy); @@ -338,4 +338,187 @@ void multipleKieSessions_BasicTest(PersistedSessionOption.PersistenceStrategy pe assertThat(fireAllRules(session2)).isEqualTo(1); } + @ParameterizedTest + @MethodSource("strategyProviderStoresOnlyWithExplicitSafepoints") // FULL fails with "ReliablePropagationList; no valid constructor" + void multipleKieSessions_insertFailoverInsertFire_shouldRecoverFromFailover(PersistedSessionOption.PersistenceStrategy persistenceStrategy, PersistedSessionOption.SafepointStrategy safepointStrategy) { + KieSession session1 = createSession(BASIC_RULE, persistenceStrategy, safepointStrategy); + KieSession session2 = createSession(BASIC_RULE, persistenceStrategy, safepointStrategy); + + insert(session1,"M"); + insertMatchingPerson(session1, "Mike", 37); + insert(session2,"N"); + insertNonMatchingPerson(session2,"Helen",33); + + failover(); + + session1 = restoreSession(session1.getIdentifier(), BASIC_RULE, persistenceStrategy, safepointStrategy); + session2 = restoreSession(session2.getIdentifier(), BASIC_RULE, persistenceStrategy, safepointStrategy); + + insertNonMatchingPerson(session1,"Toshiya", 35); + insertMatchingPerson(session2,"Nicole", 40); + + assertThat(fireAllRules(session1)).isEqualTo(1); + assertThat(fireAllRules(session2)).isEqualTo(1); + + assertThat(getResults(session1)).containsExactlyInAnyOrder("Mike"); + assertThat(getResults(session2)).containsExactlyInAnyOrder("Nicole"); + } + + @ParameterizedTest + @MethodSource("strategyProviderStoresOnlyWithExplicitSafepoints") // With Remote, FULL fails with "ReliablePropagationList; no valid constructor" even without failover + void multipleKieSessions_noFailover(PersistedSessionOption.PersistenceStrategy persistenceStrategy, PersistedSessionOption.SafepointStrategy safepointStrategy) { + + KieSession session1 = createSession(BASIC_RULE, persistenceStrategy, safepointStrategy); + KieSession session2 = createSession(BASIC_RULE, persistenceStrategy, safepointStrategy); + + insert(session1,"M"); + insertMatchingPerson(session1,"Matching Person One", 37); + insert(session2, new Person("Mary",32)); + + if (safepointStrategy == PersistedSessionOption.SafepointStrategy.EXPLICIT) { + safepoint(); + } + + session1 = restoreSession(session1.getIdentifier(), BASIC_RULE, persistenceStrategy, safepointStrategy); + session2 = restoreSession(session2.getIdentifier(), BASIC_RULE, persistenceStrategy, safepointStrategy); + + insertNonMatchingPerson(session1,"Toshiya", 41); + insertMatchingPerson(session1,"Matching Person Two", 40); + insert(session2, "H"); + insert(session2,new Person("Helen",43)); + + fireAllRules(session1); + assertThat(getResults(session1)).containsExactlyInAnyOrder("Matching Person One", "Matching Person Two"); + + assertThat(fireAllRules(session2)).isEqualTo(1); + } + + @ParameterizedTest + @MethodSource("strategyProviderStoresOnlyWithExplicitSafepoints") // FULL fails with "ReliablePropagationList; no valid constructor" + void multipleKieSessions_insertFireInsertFailoverInsertFire_shouldMatchFactInsertedBeforeFailover(PersistedSessionOption.PersistenceStrategy persistenceStrategy, PersistedSessionOption.SafepointStrategy safepointStrategy) { + + KieSession session1 = createSession(BASIC_RULE, persistenceStrategy, safepointStrategy); + KieSession session2 = createSession(BASIC_RULE, persistenceStrategy, safepointStrategy); + + insert(session1,"M"); + insertMatchingPerson(session1,"Matching Person One", 37); + insert(session2, "N"); + insertMatchingPerson(session2, "Nicole",34); + + fireAllRules(session1); + fireAllRules(session2); + + insertMatchingPerson(session1,"Matching Person Two", 40); + insertMatchingPerson(session2, "Nancy",23); + + failover(); + + session1 = restoreSession(session1.getIdentifier(),BASIC_RULE, persistenceStrategy, safepointStrategy); + session2 = restoreSession(session2.getIdentifier(), BASIC_RULE, persistenceStrategy, safepointStrategy); + + clearResults(session1); + clearResults(session2); + + insertNonMatchingPerson(session1,"Nora", 35); + insertMatchingPerson(session1,"Matching Person Three", 41); + insertNonMatchingPerson(session2,"Mike", 35); + insertMatchingPerson(session2,"Noah", 41); + + fireAllRules(session1); + fireAllRules(session2); + + assertThat(getResults(session1)).containsExactlyInAnyOrder("Matching Person Two", "Matching Person Three"); + assertThat(getResults(session2)).containsExactlyInAnyOrder("Nancy", "Noah"); + } + + @ParameterizedTest + @MethodSource("strategyProviderStoresOnlyWithExplicitSafepoints") // FULL fails with "ReliablePropagationList; no valid constructor" + void multipleKieSessions_updateBeforeFailover_shouldRecoverFromFailover(PersistedSessionOption.PersistenceStrategy persistenceStrategy, PersistedSessionOption.SafepointStrategy safepointStrategy) { + KieSession session1 = createSession(BASIC_RULE, persistenceStrategy, safepointStrategy); + KieSession session2 = createSession(BASIC_RULE, persistenceStrategy, safepointStrategy); + + insert(session1,"M"); + Person p1 = new Person("Mario", 49); + FactHandle fh1 = insert(session1,p1); + Person p2 = new Person("Toshiya", 45); + FactHandle fh2 = insert(session1, p2); + insert(session2,new Person("Toshiya", 45)); + + assertThat(fireAllRules(session1)).isEqualTo(1); + assertThat(getResults(session1)).containsExactlyInAnyOrder("Mario"); + assertThat(fireAllRules(session2)).isEqualTo(0); + + insert(session2, "T"); + p1.setName("SuperMario"); + update(session1, fh1, p1); + p2.setName("MegaToshiya"); + update(session1, fh2, p2); + + failover(); + session1 = restoreSession(session1.getIdentifier(), BASIC_RULE, persistenceStrategy, safepointStrategy); + session2 = restoreSession(session2.getIdentifier(), BASIC_RULE, persistenceStrategy, safepointStrategy); + + assertThat(fireAllRules(session1)).isEqualTo(1); + assertThat(getResults(session1)).containsExactlyInAnyOrder("Mario", "MegaToshiya"); + assertThat(fireAllRules(session2)).isEqualTo(1); + assertThat(getResults(session2)).containsExactlyInAnyOrder("Toshiya"); + + failover(); + session1 = restoreSession(session1.getIdentifier(), BASIC_RULE, persistenceStrategy, safepointStrategy); + session2 = restoreSession(session2.getIdentifier(), BASIC_RULE, persistenceStrategy, safepointStrategy); + clearResults(session1); + clearResults(session2); + + assertThat(fireAllRules(session1)).isZero(); + assertThat(getResults(session1)).isEmpty(); + + assertThat(fireAllRules(session2)).isZero(); + assertThat(getResults(session2)).isEmpty(); + } + + @ParameterizedTest + @MethodSource("strategyProviderStoresOnlyWithExplicitSafepoints") // FULL fails with "ReliablePropagationList; no valid constructor" + void multipleKieSessions_deleteBeforeFailover_shouldRecoverFromFailover(PersistedSessionOption.PersistenceStrategy persistenceStrategy, PersistedSessionOption.SafepointStrategy safepointStrategy) { + + KieSession session1 = createSession(BASIC_RULE, persistenceStrategy, safepointStrategy); + KieSession session2 = createSession(BASIC_RULE, persistenceStrategy, safepointStrategy); + + FactHandle fhStringM = insert(session1,"M"); + insertMatchingPerson(session1,"Matching Person One",37); + insertNonMatchingPerson(session1,"Toshiya",37); + insert(session2,"N"); + FactHandle fhN = insertMatchingPerson(session2,"Nicole",35); + + assertThat(fireAllRules(session1)).isEqualTo(1); + assertThat(getResults(session1)).containsExactlyInAnyOrder("Matching Person One"); + + delete(session1,fhStringM); + delete(session2, fhN); + + failover(); + + session1 = restoreSession(session1.getIdentifier(), BASIC_RULE, persistenceStrategy, safepointStrategy); + session2 = restoreSession(session2.getIdentifier(), BASIC_RULE, persistenceStrategy, safepointStrategy); + clearResults(session1); + clearResults(session2); + + insertMatchingPerson(session1,"Matching Person Two",40); + insertMatchingPerson(session2,"Nancy", 25); + + assertThat(fireAllRules(session1)).isZero(); + assertThat(getResults(session1)).isEmpty(); + assertThat(fireAllRules(session2)).isEqualTo(1); + assertThat(getResults(session2)).containsExactlyInAnyOrder("Nancy"); + + insert(session1,"T"); + + failover(); + session1 = restoreSession(session1.getIdentifier(), BASIC_RULE, persistenceStrategy, safepointStrategy); + session2 = restoreSession(session2.getIdentifier(), BASIC_RULE, persistenceStrategy, safepointStrategy); + + assertThat(fireAllRules(session1)).isEqualTo(1); + assertThat(getResults(session1)).containsExactlyInAnyOrder("Toshiya"); + } + + } diff --git a/drools-reliability/drools-reliability-infinispan/src/test/java/org/drools/reliability/infinispan/ReliabilityTestBasics.java b/drools-reliability/drools-reliability-infinispan/src/test/java/org/drools/reliability/infinispan/ReliabilityTestBasics.java index 8161df6e0a6..3612104b4e1 100644 --- a/drools-reliability/drools-reliability-infinispan/src/test/java/org/drools/reliability/infinispan/ReliabilityTestBasics.java +++ b/drools-reliability/drools-reliability-infinispan/src/test/java/org/drools/reliability/infinispan/ReliabilityTestBasics.java @@ -15,13 +15,6 @@ package org.drools.reliability.infinispan; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.TimeUnit; -import java.util.stream.Stream; - import org.drools.base.facttemplates.Event; import org.drools.core.ClassObjectFilter; import org.drools.model.Model; @@ -53,6 +46,14 @@ import org.slf4j.LoggerFactory; import org.test.domain.Person; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; + import static org.drools.reliability.infinispan.InfinispanStorageManagerFactory.INFINISPAN_STORAGE_MARSHALLER; import static org.drools.reliability.infinispan.util.PrototypeUtils.createEvent; import static org.drools.util.Config.getConfig; @@ -68,8 +69,7 @@ public abstract class ReliabilityTestBasics { private InfinispanContainer container; protected final List sessions = new ArrayList<>(); - - private long persistedSessionId = -1; + protected final HashMap persistedSessionIds = new HashMap<>(); protected PersistedSessionOption.SafepointStrategy safepointStrategy; @@ -239,11 +239,13 @@ protected KieSession restoreSession(String drl, PersistedSessionOption.Persisten } protected KieSession restoreSession(String drl, PersistedSessionOption.PersistenceStrategy persistenceStrategy, PersistedSessionOption.SafepointStrategy safepointStrategy, Option... options) { - return restoreSession(persistedSessionId, drl, persistenceStrategy, safepointStrategy, options); + Long sessionIdToRestoreFrom = (Long)this.persistedSessionIds.values().toArray()[0]; + return restoreSession(sessionIdToRestoreFrom, drl, persistenceStrategy, safepointStrategy, options); } protected KieSession restoreSession(Long sessionId, String drl, PersistedSessionOption.PersistenceStrategy persistenceStrategy, PersistedSessionOption.SafepointStrategy safepointStrategy, Option... options) { - return getKieSession(drl, PersistedSessionOption.fromSession(sessionId).withPersistenceStrategy(persistenceStrategy).withSafepointStrategy(safepointStrategy), options); + Long sessionIdToRestoreFrom = this.persistedSessionIds.get(sessionId); + return getKieSession(drl, PersistedSessionOption.fromSession(sessionIdToRestoreFrom).withPersistenceStrategy(persistenceStrategy).withSafepointStrategy(safepointStrategy), options); } protected int fireAllRules() { @@ -255,7 +257,8 @@ protected int fireAllRules(KieSession session) { } protected KieSession restoreSession(Model ruleModel, PersistedSessionOption.PersistenceStrategy persistenceStrategy, PersistedSessionOption.SafepointStrategy safepointStrategy, Option... options) { - return getKieSession(ruleModel, PersistedSessionOption.fromSession(persistedSessionId).withPersistenceStrategy(persistenceStrategy).withSafepointStrategy(safepointStrategy), options); + Long sessionIdToRestoreFrom = (Long)this.persistedSessionIds.values().toArray()[0]; + return getKieSession(ruleModel, PersistedSessionOption.fromSession(sessionIdToRestoreFrom).withPersistenceStrategy(persistenceStrategy).withSafepointStrategy(safepointStrategy), options); } protected void disposeSession() { @@ -314,12 +317,12 @@ private KieSession getKieSessionFromKieBase(KieBase kbase, PersistedSessionOptio } Stream.of(optionsFilter.getKieSessionOption()).forEach(conf::setOption); KieSession session = kbase.newKieSession(conf, null); - sessions.add(session); if (persistedSessionOption == null || persistedSessionOption.isNewSession()) { List results = new ArrayList<>(); session.setGlobal("results", results); - persistedSessionId = session.getIdentifier(); } + sessions.add(session); + persistedSessionIds.put(session.getIdentifier(),persistedSessionOption == null || persistedSessionOption.isNewSession() ? session.getIdentifier() : persistedSessionOption.getSessionId()); return session; }