/* * Copyright 2017 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.functional.oopath; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; import org.assertj.core.api.Assertions; import org.kie.api.time.SessionPseudoClock; 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.KieSessionUtil; import org.junit.After; import org.junit.Test; import org.kie.api.KieBase; 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 static org.drools.compiler.TestUtil.assertDrlHasCompilationError; /** * Tests usage of OOPath expressions with CEP (events, event windows, event streams). */ public class OOPathCepTest { private static final String MODULE_GROUP_ID = "oopath-cep-test"; private static final String ENTRY_POINT_NAME = "test-entry-point"; private static final long DEFAULT_DURATION_IN_SECS = 2000; private KieSession kieSession; private List<MessageEvent> events; private List<Message> messages; @After public void disposeKieSession() { if (this.kieSession != null) { this.kieSession.dispose(); this.kieSession = null; this.events = null; this.messages = null; } } @Test public void testEventWithOOPath() { final String drl = "import org.drools.testcoverage.common.model.Message;\n" + "import org.drools.testcoverage.common.model.MessageEvent;\n" + "global java.util.List events\n" + "global java.util.List messages\n" + "\n" + "declare org.drools.testcoverage.common.model.MessageEvent\n" + " @role( event )\n" + "end\n" + "rule R when\n" + " MessageEvent( $message: /msg[ message == 'Hello' ] )\n" + "then\n" + " messages.add( $message );\n" + "end\n"; final KieBase kieBase = KieBaseUtil.getKieBaseAndBuildInstallModuleFromDrl(MODULE_GROUP_ID, KieBaseTestConfiguration.STREAM_IDENTITY, drl); this.initKieSession(kieBase); this.populateAndVerifyEventCase(this.kieSession); } @Test public void testEntryPointWithOOPath() { final String drl = "import org.drools.testcoverage.common.model.Message;\n" + "import org.drools.testcoverage.common.model.MessageEvent;\n" + "global java.util.List events\n" + "global java.util.List messages\n" + "\n" + "declare org.drools.testcoverage.common.model.MessageEvent\n" + " @role( event )\n" + "end\n" + "rule R when\n" + String.format(" MessageEvent( $message: /msg[ message == 'Hello' ] ) from entry-point \"%s\"\n", ENTRY_POINT_NAME) + "then\n" + " messages.add( $message );\n" + "end\n"; final KieBase kieBase = KieBaseUtil.getKieBaseAndBuildInstallModuleFromDrl(MODULE_GROUP_ID, KieBaseTestConfiguration.STREAM_IDENTITY, drl); this.initKieSession(kieBase); this.populateAndVerifyEventCase(this.kieSession.getEntryPoint(ENTRY_POINT_NAME)); } private void populateAndVerifyEventCase(final EntryPoint entryPoint) { final Message helloMessage = new Message("Hello"); final MessageEvent helloEvent = new MessageEvent(MessageEvent.Type.sent, helloMessage); entryPoint.insert(helloEvent); final MessageEvent anotherEvent = new MessageEvent(MessageEvent.Type.sent, new Message("Not a hello")); entryPoint.insert(anotherEvent); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).containsExactlyInAnyOrder(helloMessage); } @Test public void testTemporalOperatorAfterWithOOPath() { final String drl = "import org.drools.testcoverage.common.model.Message;\n" + "import org.drools.testcoverage.common.model.MessageEvent;\n" + "global java.util.List events\n" + "global java.util.List messages\n" + "\n" + "declare org.drools.testcoverage.common.model.MessageEvent\n" + " @role( event )\n" + "end\n" + "rule R when\n" + " ev1: MessageEvent( /msg[ message == 'Ping' ] )\n" + " ev2: MessageEvent( $message: /msg[ message == 'Pong' ], this after ev1 )\n" + "then\n" + " messages.add( $message );\n" + "end\n"; final KieBase kieBase = KieBaseUtil.getKieBaseAndBuildInstallModuleFromDrl(MODULE_GROUP_ID, KieBaseTestConfiguration.STREAM_IDENTITY, drl); final SessionPseudoClock clock = this.initKieSessionWithPseudoClock(kieBase); this.insertEventAndAdvanceClock(new MessageEvent(MessageEvent.Type.sent, new Message("Pong")), clock, 1); this.insertEventAndAdvanceClock(new MessageEvent(MessageEvent.Type.sent, new Message("Ping")), clock, 1); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The first sequence of events should NOT make the rule fire").isEmpty(); final Message pongMessage = this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Pong"))); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The last event should make the rule fire").containsExactlyInAnyOrder(pongMessage); } @Test public void testTemporalOperatorBeforeWithOOPath() { final String drl = "import org.drools.testcoverage.common.model.Message;\n" + "import org.drools.testcoverage.common.model.MessageEvent;\n" + "global java.util.List events\n" + "global java.util.List messages\n" + "\n" + "declare org.drools.testcoverage.common.model.MessageEvent\n" + " @role( event )\n" + "end\n" + "rule R when\n" + " ev1: MessageEvent( /msg[ message == 'Ping' ] )\n" + " ev2: MessageEvent( $message: /msg[ message == 'Pong' ], this before ev1 )\n" + "then\n" + " messages.add( $message );\n" + "end\n"; final KieBase kieBase = KieBaseUtil.getKieBaseAndBuildInstallModuleFromDrl(MODULE_GROUP_ID, KieBaseTestConfiguration.STREAM_IDENTITY, drl); final SessionPseudoClock clock = this.initKieSessionWithPseudoClock(kieBase); this.insertEventAndAdvanceClock(new MessageEvent(MessageEvent.Type.sent, new Message("Ping")), clock, 1); final Message pongMessage = this.insertEventAndAdvanceClock(new MessageEvent(MessageEvent.Type.sent, new Message("Pong")), clock, 1); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The first sequence of events should NOT make the rule fire").isEmpty(); this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Ping"))); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The last event should make the rule fire").containsExactlyInAnyOrder(pongMessage); } @Test public void testTemporalOperatorCoincidesWithOOPath() { final String drl = "import org.drools.testcoverage.common.model.Message;\n" + "import org.drools.testcoverage.common.model.MessageEvent;\n" + "global java.util.List events\n" + "global java.util.List messages\n" + "\n" + "declare org.drools.testcoverage.common.model.MessageEvent\n" + " @role( event )\n" + "end\n" + "rule R when\n" + " ev1: MessageEvent( /msg[ message == 'Ping' ] )\n" + " ev2: MessageEvent( $message: /msg[ message == 'Pong' ], this coincides[1s] ev1 )\n" + "then\n" + " messages.add( $message );\n" + "end\n"; final KieBase kieBase = KieBaseUtil.getKieBaseAndBuildInstallModuleFromDrl(MODULE_GROUP_ID, KieBaseTestConfiguration.STREAM_IDENTITY, drl); final SessionPseudoClock clock = this.initKieSessionWithPseudoClock(kieBase); this.insertEventAndAdvanceClock(new MessageEvent(MessageEvent.Type.sent, new Message("Pong")), clock, 2); this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Ping"))); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The first sequence of events should NOT make the rule fire").isEmpty(); final Message pongMessage = this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Pong"))); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The last event should make the rule fire").containsExactlyInAnyOrder(pongMessage); } @Test public void testTemporalOperatorDuringWithOOPath() { final String drl = "import org.drools.testcoverage.common.model.Message;\n" + "import org.drools.testcoverage.common.model.MessageEvent;\n" + "global java.util.List events\n" + "global java.util.List messages\n" + "\n" + "declare org.drools.testcoverage.common.model.MessageEvent\n" + " @role( event )\n" + " @duration( duration )\n" + "end\n" + "rule R when\n" + " ev1: MessageEvent( /msg[ message == 'Ping' ] )\n" + " ev2: MessageEvent( $message: /msg[ message == 'Pong' ], this during ev1 )\n" + "then\n" + " messages.add( $message );\n" + "end\n"; final KieBase kieBase = KieBaseUtil.getKieBaseAndBuildInstallModuleFromDrl(MODULE_GROUP_ID, KieBaseTestConfiguration.STREAM_IDENTITY, drl); final SessionPseudoClock clock = this.initKieSessionWithPseudoClock(kieBase); this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Ping"), DEFAULT_DURATION_IN_SECS)); this.insertEventAndAdvanceClock(new MessageEvent(MessageEvent.Type.sent, new Message("Pong"), DEFAULT_DURATION_IN_SECS), clock, 1); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The first sequence of events should NOT make the rule fire").isEmpty(); final Message pongMessage = this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Pong"), DEFAULT_DURATION_IN_SECS - 1500)); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The last event should make the rule fire").containsExactlyInAnyOrder(pongMessage); } @Test public void testTemporalOperatorFinishesWithOOPath() { final String drl = "import org.drools.testcoverage.common.model.Message;\n" + "import org.drools.testcoverage.common.model.MessageEvent;\n" + "global java.util.List events\n" + "global java.util.List messages\n" + "\n" + "declare org.drools.testcoverage.common.model.MessageEvent\n" + " @role( event )\n" + " @duration( duration )\n" + "end\n" + "rule R when\n" + " ev1: MessageEvent( /msg[ message == 'Ping' ] )\n" + " ev2: MessageEvent( $message: /msg[ message == 'Pong' ], this finishes ev1 )\n" + "then\n" + " messages.add( $message );\n" + "end\n"; final KieBase kieBase = KieBaseUtil.getKieBaseAndBuildInstallModuleFromDrl(MODULE_GROUP_ID, KieBaseTestConfiguration.STREAM_IDENTITY, drl); final SessionPseudoClock clock = this.initKieSessionWithPseudoClock(kieBase); this.insertEventAndAdvanceClock(new MessageEvent(MessageEvent.Type.sent, new Message("Pong"), DEFAULT_DURATION_IN_SECS), clock, 1); this.insertEventAndAdvanceClock(new MessageEvent(MessageEvent.Type.sent, new Message("Ping"), DEFAULT_DURATION_IN_SECS), clock, 1); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The first sequence of events should NOT make the rule fire").isEmpty(); final Message pongMessage = this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Pong"), DEFAULT_DURATION_IN_SECS - 1000)); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The last event should make the rule fire").containsExactlyInAnyOrder(pongMessage); } @Test public void testTemporalOperatorFinishedByWithOOPath() { final String drl = "import org.drools.testcoverage.common.model.Message;\n" + "import org.drools.testcoverage.common.model.MessageEvent;\n" + "global java.util.List events\n" + "global java.util.List messages\n" + "\n" + "declare org.drools.testcoverage.common.model.MessageEvent\n" + " @role( event )\n" + " @duration( duration )\n" + "end\n" + "rule R when\n" + " ev1: MessageEvent( /msg[ message == 'Ping' ] )\n" + " ev2: MessageEvent( $message: /msg[ message == 'Pong' ], this finishedby ev1 )\n" + "then\n" + " messages.add( $message );\n" + "end\n"; final KieBase kieBase = KieBaseUtil.getKieBaseAndBuildInstallModuleFromDrl(MODULE_GROUP_ID, KieBaseTestConfiguration.STREAM_IDENTITY, drl); final SessionPseudoClock clock = this.initKieSessionWithPseudoClock(kieBase); this.insertEventAndAdvanceClock(new MessageEvent(MessageEvent.Type.sent, new Message("Ping"), DEFAULT_DURATION_IN_SECS), clock, 1); final Message pongMessage = this.insertEventAndAdvanceClock(new MessageEvent(MessageEvent.Type.sent, new Message("Pong"), DEFAULT_DURATION_IN_SECS), clock, 1); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The first sequence of events should NOT make the rule fire").isEmpty(); this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Ping"), DEFAULT_DURATION_IN_SECS - 1000)); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The last event should make the rule fire").containsExactlyInAnyOrder(pongMessage); } @Test public void testTemporalOperatorIncludesWithOOPath() { final String drl = "import org.drools.testcoverage.common.model.Message;\n" + "import org.drools.testcoverage.common.model.MessageEvent;\n" + "global java.util.List events\n" + "global java.util.List messages\n" + "\n" + "declare org.drools.testcoverage.common.model.MessageEvent\n" + " @role( event )\n" + " @duration( duration )\n" + "end\n" + "rule R when\n" + " ev1: MessageEvent( /msg[ message == 'Ping' ] )\n" + " ev2: MessageEvent( $message: /msg[ message == 'Pong' ], this includes ev1 )\n" + "then\n" + " messages.add( $message );\n" + "end\n"; final KieBase kieBase = KieBaseUtil.getKieBaseAndBuildInstallModuleFromDrl(MODULE_GROUP_ID, KieBaseTestConfiguration.STREAM_IDENTITY, drl); final SessionPseudoClock clock = this.initKieSessionWithPseudoClock(kieBase); final Message pongMessage = this.insertEventAndAdvanceClock(new MessageEvent(MessageEvent.Type.sent, new Message("Pong"), DEFAULT_DURATION_IN_SECS), clock, 1); this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Pong"), DEFAULT_DURATION_IN_SECS - 1500)); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The first sequence of events should NOT make the rule fire").isEmpty(); this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Ping"), DEFAULT_DURATION_IN_SECS - 1500)); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The last event should make the rule fire").containsExactlyInAnyOrder(pongMessage); } @Test public void testTemporalOperatorMeetsWithOOPath() { final String drl = "import org.drools.testcoverage.common.model.Message;\n" + "import org.drools.testcoverage.common.model.MessageEvent;\n" + "global java.util.List events\n" + "global java.util.List messages\n" + "\n" + "declare org.drools.testcoverage.common.model.MessageEvent\n" + " @role( event )\n" + "end\n" + "rule R when\n" + " ev1: MessageEvent( /msg[ message == 'Ping' ] )\n" + " ev2: MessageEvent( $message: /msg[ message == 'Pong' ], this meets[ 1s ] ev1 )\n" + "then\n" + " messages.add( $message );\n" + "end\n"; final KieBase kieBase = KieBaseUtil.getKieBaseAndBuildInstallModuleFromDrl(MODULE_GROUP_ID, KieBaseTestConfiguration.STREAM_IDENTITY, drl); final SessionPseudoClock clock = this.initKieSessionWithPseudoClock(kieBase); this.insertEventAndAdvanceClock(new MessageEvent(MessageEvent.Type.sent, new Message("Pong")), clock, 2); this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Ping"))); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The first sequence of events should NOT make the rule fire").isEmpty(); final Message pongMessage = this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Pong"))); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The last event should make the rule fire").containsExactlyInAnyOrder(pongMessage); } @Test public void testTemporalOperatorMetByWithOOPath() { final String drl = "import org.drools.testcoverage.common.model.Message;\n" + "import org.drools.testcoverage.common.model.MessageEvent;\n" + "global java.util.List events\n" + "global java.util.List messages\n" + "\n" + "declare org.drools.testcoverage.common.model.MessageEvent\n" + " @role( event )\n" + "end\n" + "rule R when\n" + " ev1: MessageEvent( /msg[ message == 'Ping' ] )\n" + " ev2: MessageEvent( $message: /msg[ message == 'Pong' ], this metby[ 1s ] ev1 )\n" + "then\n" + " messages.add( $message );\n" + "end\n"; final KieBase kieBase = KieBaseUtil.getKieBaseAndBuildInstallModuleFromDrl(MODULE_GROUP_ID, KieBaseTestConfiguration.STREAM_IDENTITY, drl); final SessionPseudoClock clock = this.initKieSessionWithPseudoClock(kieBase); this.insertEventAndAdvanceClock(new MessageEvent(MessageEvent.Type.sent, new Message("Pong")), clock, 2); this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Ping"))); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The first sequence of events should NOT make the rule fire").isEmpty(); final Message pongMessage = this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Pong"))); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The last event should make the rule fire").containsExactlyInAnyOrder(pongMessage); } @Test public void testTemporalOperatorOverlapsWithOOPath() { final String drl = "import org.drools.testcoverage.common.model.Message;\n" + "import org.drools.testcoverage.common.model.MessageEvent;\n" + "global java.util.List events\n" + "global java.util.List messages\n" + "\n" + "declare org.drools.testcoverage.common.model.MessageEvent\n" + " @role( event )\n" + " @duration( duration )\n" + "end\n" + "rule R when\n" + " ev1: MessageEvent( /msg[ message == 'Ping' ] )\n" + " ev2: MessageEvent( $message: /msg[ message == 'Pong' ], this overlaps[ 1s ] ev1 )\n" + "then\n" + " messages.add( $message );\n" + "end\n"; final KieBase kieBase = KieBaseUtil.getKieBaseAndBuildInstallModuleFromDrl(MODULE_GROUP_ID, KieBaseTestConfiguration.STREAM_IDENTITY, drl); final SessionPseudoClock clock = this.initKieSessionWithPseudoClock(kieBase); this.insertEventAndAdvanceClock(new MessageEvent(MessageEvent.Type.sent, new Message("Pong"), 1), clock, 2); this.insertEventAndAdvanceClock(new MessageEvent(MessageEvent.Type.sent, new Message("Ping"), 1), clock, 1); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The first sequence of events should NOT make the rule fire").isEmpty(); final Message pongMessage = this.insertEventAndAdvanceClock(new MessageEvent(MessageEvent.Type.sent, new Message("Pong"), DEFAULT_DURATION_IN_SECS), clock, 1); this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Ping"), DEFAULT_DURATION_IN_SECS)); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The last event should make the rule fire").containsExactlyInAnyOrder(pongMessage); } @Test public void testTemporalOperatorOverlappedByWithOOPath() { final String drl = "import org.drools.testcoverage.common.model.Message;\n" + "import org.drools.testcoverage.common.model.MessageEvent;\n" + "global java.util.List events\n" + "global java.util.List messages\n" + "\n" + "declare org.drools.testcoverage.common.model.MessageEvent\n" + " @role( event )\n" + " @duration( duration )\n" + "end\n" + "rule R when\n" + " ev1: MessageEvent( /msg[ message == 'Ping' ] )\n" + " ev2: MessageEvent( $message: /msg[ message == 'Pong' ], this overlappedby[ 1s ] ev1 )\n" + "then\n" + " messages.add( $message );\n" + "end\n"; final KieBase kieBase = KieBaseUtil.getKieBaseAndBuildInstallModuleFromDrl(MODULE_GROUP_ID, KieBaseTestConfiguration.STREAM_IDENTITY, drl); final SessionPseudoClock clock = this.initKieSessionWithPseudoClock(kieBase); this.insertEventAndAdvanceClock(new MessageEvent(MessageEvent.Type.sent, new Message("Pong"), DEFAULT_DURATION_IN_SECS), clock, 1); this.insertEventAndAdvanceClock(new MessageEvent(MessageEvent.Type.sent, new Message("Ping"), DEFAULT_DURATION_IN_SECS), clock, 1); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The first sequence of events should NOT make the rule fire").isEmpty(); final Message pongMessage = this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Pong"), DEFAULT_DURATION_IN_SECS)); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The last event should make the rule fire").containsExactlyInAnyOrder(pongMessage); } @Test public void testTemporalOperatorStartsWithOOPath() { final String drl = "import org.drools.testcoverage.common.model.Message;\n" + "import org.drools.testcoverage.common.model.MessageEvent;\n" + "global java.util.List events\n" + "global java.util.List messages\n" + "\n" + "declare org.drools.testcoverage.common.model.MessageEvent\n" + " @role( event )\n" + " @duration( duration )\n" + "end\n" + "rule R when\n" + " ev1: MessageEvent( /msg[ message == 'Ping' ] )\n" + " ev2: MessageEvent( $message: /msg[ message == 'Pong' ], this starts[ 1s ] ev1 )\n" + "then\n" + " messages.add( $message );\n" + "end\n"; final KieBase kieBase = KieBaseUtil.getKieBaseAndBuildInstallModuleFromDrl(MODULE_GROUP_ID, KieBaseTestConfiguration.STREAM_IDENTITY, drl); this.initKieSessionWithPseudoClock(kieBase); this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Pong"), DEFAULT_DURATION_IN_SECS)); this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Ping"), DEFAULT_DURATION_IN_SECS)); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The first sequence of events should NOT make the rule fire").isEmpty(); final Message pongMessage = this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Pong"), DEFAULT_DURATION_IN_SECS - 1000)); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The last event should make the rule fire").containsExactlyInAnyOrder(pongMessage); } @Test public void testTemporalOperatorStartedByWithOOPath() { final String drl = "import org.drools.testcoverage.common.model.Message;\n" + "import org.drools.testcoverage.common.model.MessageEvent;\n" + "global java.util.List events\n" + "global java.util.List messages\n" + "\n" + "declare org.drools.testcoverage.common.model.MessageEvent\n" + " @role( event )\n" + " @duration( duration )\n" + "end\n" + "rule R when\n" + " ev1: MessageEvent( /msg[ message == 'Ping' ] )\n" + " ev2: MessageEvent( $message: /msg[ message == 'Pong' ], this startedby[ 1s ] ev1 )\n" + "then\n" + " messages.add( $message );\n" + "end\n"; final KieBase kieBase = KieBaseUtil.getKieBaseAndBuildInstallModuleFromDrl(MODULE_GROUP_ID, KieBaseTestConfiguration.STREAM_IDENTITY, drl); this.initKieSessionWithPseudoClock(kieBase); this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Pong"), DEFAULT_DURATION_IN_SECS)); this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Ping"), DEFAULT_DURATION_IN_SECS)); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The first sequence of events should NOT make the rule fire").isEmpty(); final Message pongMessage = this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Pong"), DEFAULT_DURATION_IN_SECS + 1000)); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The last event should make the rule fire").containsExactlyInAnyOrder(pongMessage); } @Test public void testLengthWindowWithOOPath() { final String drl = "import org.drools.testcoverage.common.model.Message;\n" + "import org.drools.testcoverage.common.model.MessageEvent;\n" + "global java.util.List events\n" + "global java.util.List messages\n" + "\n" + "declare org.drools.testcoverage.common.model.MessageEvent\n" + " @role( event )\n" + "end\n" + "rule R when\n" + " $messageEvent: MessageEvent( /msg[ message == 'Ping' ] ) over window:length( 2 )\n" + "then\n" + " events.add( $messageEvent );\n" + "end\n"; final KieBase kieBase = KieBaseUtil.getKieBaseAndBuildInstallModuleFromDrl(MODULE_GROUP_ID, KieBaseTestConfiguration.STREAM_EQUALITY, drl); this.populateAndVerifyLengthWindowCase(kieBase); } @Test public void testDeclaredLengthWindowWithOOPathInRule() { final String drl = "import org.drools.testcoverage.common.model.Message;\n" + "import org.drools.testcoverage.common.model.MessageEvent;\n" + "global java.util.List events\n" + "global java.util.List messages\n" + "\n" + "declare org.drools.testcoverage.common.model.MessageEvent\n" + " @role( event )\n" + "end\n" + "\n" + "declare window Pings\n" + " MessageEvent() over window:length( 2 )\n" + "end\n" + "rule R when\n" + " $messageEvent: MessageEvent( /msg[ message == 'Ping' ] ) from window Pings\n" + "then\n" + " events.add( $messageEvent );\n" + "end\n"; final KieBase kieBase = KieBaseUtil.getKieBaseAndBuildInstallModuleFromDrl(MODULE_GROUP_ID, KieBaseTestConfiguration.STREAM_EQUALITY, drl); this.populateAndVerifyLengthWindowCase(kieBase); } @Test public void testOOPathNotAllowedInDeclaredWindow() { final String drl = "import org.drools.testcoverage.common.model.Message;\n" + "import org.drools.testcoverage.common.model.MessageEvent;\n" + "global java.util.List events\n" + "global java.util.List messages\n" + "\n" + "declare org.drools.testcoverage.common.model.MessageEvent\n" + " @role( event )\n" + "end\n" + "\n" + "declare window Pings\n" + " MessageEvent( /msg[ message == 'Ping' ] ) over window:length( 2 )\n" + "end\n" + "rule R when\n" + " $messageEvent: MessageEvent() from window Pings\n" + "then\n" + " events.add( $messageEvent );\n" + "end\n"; assertDrlHasCompilationError(drl, 2); } private void populateAndVerifyLengthWindowCase(final KieBase kieBase) { this.initKieSession(kieBase); final MessageEvent pingEvent = new MessageEvent(MessageEvent.Type.sent, new Message("Ping")); this.kieSession.insert(pingEvent); final MessageEvent ping2Event = new MessageEvent(MessageEvent.Type.received, new Message("Ping")); this.kieSession.insert(ping2Event); final MessageEvent ping3Event = new MessageEvent(MessageEvent.Type.received, new Message("Ping")); this.kieSession.insert(ping3Event); this.kieSession.fireAllRules(); Assertions.assertThat(this.events).as("The rule should have fired for 2 events").contains(ping2Event, ping3Event); this.events.clear(); final MessageEvent pongEvent = new MessageEvent(MessageEvent.Type.sent, new Message("Pong")); this.kieSession.insert(pongEvent); final MessageEvent ping4Event = new MessageEvent(MessageEvent.Type.received, new Message("Ping")); this.kieSession.insert(ping4Event); this.kieSession.fireAllRules(); Assertions.assertThat(this.events).as("The rule should have fired for ping event only").contains(ping4Event); } @Test public void testTimeWindowWithOOPath() { final String drl = "import org.drools.testcoverage.common.model.Message;\n" + "import org.drools.testcoverage.common.model.MessageEvent;\n" + "global java.util.List events\n" + "global java.util.List messages\n" + "\n" + "declare org.drools.testcoverage.common.model.MessageEvent\n" + " @role( event )\n" + "end\n" + "rule R when\n" + " $messageEvent: MessageEvent( /msg[ message == 'Ping' ] ) over window:time( 3s )\n" + "then\n" + " events.add( $messageEvent );\n" + "end\n"; final KieBase kieBase = KieBaseUtil.getKieBaseAndBuildInstallModuleFromDrl(MODULE_GROUP_ID, KieBaseTestConfiguration.STREAM_IDENTITY, drl); this.populateAndVerifyTimeWindowCase(kieBase); } @Test public void testDeclaredTimeWindowWithOOPathInRule() { final String drl = "import org.drools.testcoverage.common.model.Message;\n" + "import org.drools.testcoverage.common.model.MessageEvent;\n" + "global java.util.List events\n" + "global java.util.List messages\n" + "\n" + "declare org.drools.testcoverage.common.model.MessageEvent\n" + " @role( event )\n" + "end\n" + "\n" + "declare window Pings\n" + " MessageEvent() over window:time( 3s )\n" + "end\n" + "rule R when\n" + " $messageEvent: MessageEvent( /msg[ message == 'Ping' ] ) from window Pings\n" + "then\n" + " events.add( $messageEvent );\n" + "end\n"; final KieBase kieBase = KieBaseUtil.getKieBaseAndBuildInstallModuleFromDrl(MODULE_GROUP_ID, KieBaseTestConfiguration.STREAM_IDENTITY, drl); this.populateAndVerifyTimeWindowCase(kieBase); } private void populateAndVerifyTimeWindowCase(final KieBase kieBase) { final KieSessionConfiguration sessionConfiguration = KieSessionUtil.getKieSessionConfigurationWithClock(ClockTypeOption.get("pseudo"), null); this.initKieSession(kieBase, sessionConfiguration); final SessionPseudoClock clock = this.kieSession.getSessionClock(); final MessageEvent pingEvent = new MessageEvent(MessageEvent.Type.sent, new Message("Ping")); this.kieSession.insert(pingEvent); clock.advanceTime(1, TimeUnit.SECONDS); final MessageEvent ping2Event = new MessageEvent(MessageEvent.Type.received, new Message("Ping")); this.kieSession.insert(ping2Event); clock.advanceTime(1, TimeUnit.SECONDS); final MessageEvent ping3Event = new MessageEvent(MessageEvent.Type.received, new Message("Ping")); this.kieSession.insert(ping3Event); clock.advanceTime(1, TimeUnit.SECONDS); this.kieSession.fireAllRules(); Assertions.assertThat(this.events).as("The rule should have fired for 2 events").containsExactlyInAnyOrder(ping2Event, ping3Event); this.events.clear(); final MessageEvent pongEvent = new MessageEvent(MessageEvent.Type.sent, new Message("Pong")); this.kieSession.insert(pongEvent); clock.advanceTime(1, TimeUnit.SECONDS); final MessageEvent ping4Event = new MessageEvent(MessageEvent.Type.received, new Message("Ping")); this.kieSession.insert(ping4Event); clock.advanceTime(1, TimeUnit.SECONDS); this.kieSession.fireAllRules(); Assertions.assertThat(this.events).as("The rule should have fired for ping event only").contains(ping4Event); } @Test public void testEventExplicitExpirationWithOOPath() { final String drl = "import org.drools.testcoverage.common.model.Message;\n" + "import org.drools.testcoverage.common.model.MessageEvent;\n" + "global java.util.List events\n" + "global java.util.List messages\n" + "\n" + "declare org.drools.testcoverage.common.model.MessageEvent\n" + " @role( event )\n" + " @expires( 2s )\n" + "end\n" + "rule R when\n" + " MessageEvent( /msg[ message == 'Ping' ] )\n" + " MessageEvent( $message: /msg[ message == 'Pong' ] )\n" + "then\n" + " messages.add( $message );\n" + "end\n"; final KieBase kieBase = KieBaseUtil.getKieBaseAndBuildInstallModuleFromDrl(MODULE_GROUP_ID, KieBaseTestConfiguration.STREAM_IDENTITY, drl); final SessionPseudoClock clock = this.initKieSessionWithPseudoClock(kieBase); this.insertEventAndAdvanceClock(new MessageEvent(MessageEvent.Type.sent, new Message("Ping")), clock, 3); final Message pongMessage = this.insertEventAndAdvanceClock(new MessageEvent(MessageEvent.Type.sent, new Message("Pong")), clock, 1); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The first sequence of events should NOT make the rule fire").isEmpty(); this.insertEvent(new MessageEvent(MessageEvent.Type.sent, new Message("Ping"))); this.kieSession.fireAllRules(); Assertions.assertThat(this.messages).as("The last event should make the rule fire").containsExactlyInAnyOrder(pongMessage); } private SessionPseudoClock initKieSessionWithPseudoClock(final KieBase kieBase) { final KieSessionConfiguration sessionConfiguration = KieSessionUtil.getKieSessionConfigurationWithClock(ClockTypeOption.get("pseudo"), null); this.initKieSession(kieBase, sessionConfiguration); return this.kieSession.getSessionClock(); } private void initKieSession(final KieBase kieBase) { this.initKieSession(kieBase, null); } private void initKieSession(final KieBase kieBase, final KieSessionConfiguration kieSessionConfiguration) { this.kieSession = kieBase.newKieSession(kieSessionConfiguration, null); this.messages = new ArrayList<>(); this.kieSession.setGlobal("messages", messages); this.events = new ArrayList<>(); this.kieSession.setGlobal("events", events); } private Message insertEventAndAdvanceClock(final MessageEvent messageEvent, final SessionPseudoClock clock, final long timeInSeconds) { final Message result = this.insertEvent(messageEvent); clock.advanceTime(timeInSeconds, TimeUnit.SECONDS); return result; } private Message insertEvent(final MessageEvent messageEvent) { this.kieSession.insert(messageEvent); return messageEvent.getMsg(); } }