/*
* Copyright 2016 Red Hat, Inc. and/or 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.drools.testcoverage.regression;
import java.util.Collection;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
import org.assertj.core.api.Assertions;
import org.kie.api.time.SessionPseudoClock;
import org.drools.testcoverage.common.listener.TrackingAgendaEventListener;
import org.drools.testcoverage.common.model.Event;
import org.drools.testcoverage.common.model.EventA;
import org.drools.testcoverage.common.model.EventB;
import org.drools.testcoverage.common.model.Message;
import org.drools.testcoverage.common.model.MessageEvent;
import org.drools.testcoverage.common.util.KieBaseTestConfiguration;
import org.drools.testcoverage.common.util.KieBaseUtil;
import org.drools.testcoverage.common.util.TestConstants;
import org.drools.testcoverage.common.util.TestParametersUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.kie.api.KieBase;
import org.kie.api.KieServices;
import org.kie.api.io.Resource;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.KieSession;
import org.kie.api.runtime.KieSessionConfiguration;
import org.kie.api.runtime.conf.ClockTypeOption;
import org.kie.api.runtime.rule.EntryPoint;
import org.kie.internal.KnowledgeBaseFactory;
import org.kie.internal.utils.KieHelper;
/**
* Test to verify BRMS-582 (use of 'after' and 'before' operators ends with NPE)
* is fixed.
*/
@RunWith(Parameterized.class)
public class FusionAfterBeforeTest {
private final KieBaseTestConfiguration kieBaseTestConfiguration;
public FusionAfterBeforeTest(final KieBaseTestConfiguration kieBaseTestConfiguration) {
this.kieBaseTestConfiguration = kieBaseTestConfiguration;
}
@Parameters
public static Collection<Object[]> getParameters() {
return TestParametersUtil.getKieBaseStreamConfigurations();
}
@Test
public void testAfterBeforeOperators() {
final Resource drlResource =
KieServices.Factory.get().getResources().newClassPathResource("fusionAfterBeforeTest.drl", getClass());
final KieBase kieBase = KieBaseUtil.getKieBaseAndBuildInstallModule(TestConstants.PACKAGE_REGRESSION,
kieBaseTestConfiguration, drlResource);
final KieSessionConfiguration ksconf = KnowledgeBaseFactory.newKnowledgeSessionConfiguration();
ksconf.setOption(ClockTypeOption.get("pseudo"));
final KieSession ksession = kieBase.newKieSession(ksconf, null);
final TrackingAgendaEventListener listener = new TrackingAgendaEventListener();
ksession.addEventListener(listener);
final EntryPoint stream = ksession.getEntryPoint("EventStream");
SessionPseudoClock clock = ksession.getSessionClock();
try {
for (int i = 0; i < 3; i++) {
final MessageEvent tc = new MessageEvent(MessageEvent.Type.received, new Message());
stream.insert(tc);
ksession.fireAllRules();
clock.advanceTime(8, TimeUnit.SECONDS);
}
ksession.fireAllRules();
} finally {
ksession.dispose();
}
Assertions.assertThat(listener.isRuleFired("AfterMessageEvent")).as("Rule 'AfterMessageEvent' was no fired!").isTrue();
Assertions.assertThat(listener.isRuleFired("BeforeMessageEvent")).as("Rule 'BeforeMessageEvent' was no fired!").isTrue();
// each rules should be fired 2 times
int firedCount = 2;
int actuallyFired = listener.ruleFiredCount("AfterMessageEvent");
Assertions.assertThat(firedCount).as("Rule 'AfterMessageEvent' should be fired 2 times, but was fired "
+ firedCount + " time(s)!").isEqualTo(actuallyFired);
firedCount = listener.ruleFiredCount("BeforeMessageEvent");
Assertions.assertThat(firedCount).as("Rule 'BeforeMessageEvent' should be fired 2 times, but was fired "
+ firedCount + " time(s)!").isEqualTo(actuallyFired);
}
@Test(timeout = 10000)
public void testExpireEventsWhenSharingAllRules() throws InstantiationException, IllegalAccessException {
final StringBuilder drlBuilder = new StringBuilder();
for (int i = 0; i < 64; i++) {
drlBuilder.append(" import " + EventA.class.getCanonicalName() + ";\n");
drlBuilder.append(" import " + EventB.class.getCanonicalName() + ";\n");
drlBuilder.append(" declare " + EventA.class.getName() + " @role( event ) @duration(duration) end");
drlBuilder.append(" declare " + EventB.class.getName() + " @role( event ) @duration(duration) end");
drlBuilder.append(" rule R" + i + " when \n");
drlBuilder.append(" $event1: " + EventA.class.getName() + "()\n");
drlBuilder.append(" $event2: " + EventB.class.getName() + "(this != $event1, this after [1,10] $event1)\n");
drlBuilder.append( "then end\n" );
}
final SortedSet<Event> events = new TreeSet<Event>();
events.addAll(getEvents(EventA.class, 64 / 2, 2, 100, 0));
events.addAll(getEvents(EventB.class, 64 / 2, 5, 100, 0));
final KieSessionConfiguration sessionConf = KnowledgeBaseFactory.newKnowledgeSessionConfiguration();
sessionConf.setOption(ClockTypeOption.get("pseudo"));
final KieSession kieSession =
new KieHelper().addContent(drlBuilder.toString(), ResourceType.DRL).build(kieBaseTestConfiguration.getKieBaseConfiguration()).newKieSession(sessionConf, null);
Assertions.assertThat(insertEventsAndFire(kieSession, events)).isEqualTo(2048);
}
private <T extends Event> SortedSet<T> getEvents(final Class<T> eventClass, final int eventsCount,
final long startTime, final long timeIncrement, long duration) throws IllegalAccessException, InstantiationException {
final SortedSet<T> resultList = new TreeSet<T>();
long actualTime = startTime;
for (int i = 0; i < eventsCount; i++) {
final T event = eventClass.newInstance();
event.setTimeValue(actualTime);
event.setDuration(duration);
resultList.add(event);
actualTime = actualTime + timeIncrement;
}
return resultList;
}
private int insertEventsAndFire(final KieSession kieSession, final SortedSet<Event> events) {
final SessionPseudoClock sessionClock = kieSession.getSessionClock();
final long startTime = sessionClock.getCurrentTime();
int fireCount = 0;
for (Event event : events) {
final long eventTime = startTime + event.getTimeValue();
sessionClock.advanceTime(eventTime - sessionClock.getCurrentTime(), TimeUnit.MILLISECONDS);
kieSession.insert(event);
fireCount += kieSession.fireAllRules();
}
return fireCount;
}
}