001    /**
002     * Copyright 2005-2014 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.rice.krms.test;
017    
018    import org.apache.commons.lang.exception.ExceptionUtils;
019    import org.joda.time.DateTime;
020    import org.junit.Before;
021    import org.junit.Test;
022    import org.kuali.rice.kew.util.PerformanceLogger;
023    import org.kuali.rice.krms.api.KrmsApiServiceLocator;
024    import org.kuali.rice.krms.api.engine.EngineResults;
025    import org.kuali.rice.krms.api.engine.ExecutionFlag;
026    import org.kuali.rice.krms.api.engine.ExecutionOptions;
027    import org.kuali.rice.krms.api.engine.Facts;
028    import org.kuali.rice.krms.api.engine.ResultEvent;
029    import org.kuali.rice.krms.api.engine.SelectionCriteria;
030    import org.kuali.rice.krms.api.repository.agenda.AgendaDefinition;
031    import org.kuali.rice.krms.api.repository.context.ContextDefinition;
032    import org.kuali.rice.krms.impl.repository.KrmsRepositoryServiceLocator;
033    import org.kuali.rice.test.BaselineTestCase.BaselineMode;
034    import org.kuali.rice.test.BaselineTestCase.Mode;
035    import org.springframework.transaction.annotation.Transactional;
036    
037    import java.util.Collections;
038    import java.util.HashMap;
039    import java.util.List;
040    import java.util.Map;
041    
042    import static org.junit.Assert.*;
043    
044    @BaselineMode(Mode.CLEAR_DB)
045    public class RepositoryCreateAndExecuteIntegrationTest extends AbstractAgendaBoTest {
046    
047        static final String NAME = "name";
048        static final String PREREQ_TERM_VALUE = "prereqValue";
049        static final String NAMESPACE_CODE = "namespaceCode";
050    
051        static boolean localInitNeeded = true;
052    
053        /**
054         *   Override of setup of AbstractAgendaBoTest (not setUp) to ensure correct test values
055         */
056        @Override
057        @Before
058        public void setup() {
059            // Reset TestActionTypeService
060            TestActionTypeService.resetActionsFired();
061    
062            termBoService = KrmsRepositoryServiceLocator.getTermBoService();
063            contextRepository = KrmsRepositoryServiceLocator.getContextBoService();
064            krmsTypeRepository = KrmsRepositoryServiceLocator.getKrmsTypeRepositoryService();
065    
066            ruleBoService = KrmsRepositoryServiceLocator.getRuleBoService();
067            agendaBoService = KrmsRepositoryServiceLocator.getAgendaBoService();
068            actionBoService = KrmsRepositoryServiceLocator.getBean("actionBoService");
069            functionBoService = KrmsRepositoryServiceLocator.getBean("functionRepositoryService");
070            krmsAttributeDefinitionService = KrmsRepositoryServiceLocator.getKrmsAttributeDefinitionService();
071    
072            ContextDefinition contextDefintion1 = contextRepository.getContextByNameAndNamespace(CONTEXT1, NAMESPACE1);
073    
074            // only set this stuff up if we don't already have Context1 (we don't clear out KRMS tables between test methods)
075            // run at least once in case previous tests have used this context and to ensure correct values
076            if (contextDefintion1 == null || localInitNeeded) {
077                localInitNeeded = false;
078                PerformanceLogger perfLog = new PerformanceLogger();
079                perfLog.log("starting agenda creation");
080    
081                contextDefintion1 = createContextDefinition(NAMESPACE1, CONTEXT1, Collections.singletonMap(CONTEXT1_QUALIFIER,
082                        CONTEXT1_QUALIFIER_VALUE));
083                createAgendaDefinition(AGENDA1, contextDefintion1, TSUNAMI_EVENT, NAMESPACE1);
084    
085                ContextDefinition contextDefinition2 = createContextDefinition(NAMESPACE2, CONTEXT2,
086                        Collections.singletonMap(CONTEXT2_QUALIFIER, CONTEXT2_QUALIFIER_VALUE));
087    
088                ContextDefinition contextDefinition3 = createContextDefinition(NAMESPACE1, CONTEXT3,
089                        Collections.<String,String>emptyMap());
090    
091                // Create multiple agendas so that we can test selection
092                createAgendaDefinition(AGENDA2, contextDefinition2, EARTHQUAKE_EVENT, NAMESPACE2);
093                createAgendaDefinition(AGENDA3, contextDefinition2, EARTHQUAKE_EVENT, NAMESPACE2);
094                createAgendaDefinition(AGENDA4, contextDefinition2, TSUNAMI_EVENT, NAMESPACE2);
095                createAgendaDefinition2(AGENDA5, contextDefinition3, NAMESPACE1);
096    
097                perfLog.log("finished agenda creation", true);
098            }
099        }
100    
101        @Transactional
102        @Test
103        public void testNullFact() {
104    
105            Map<String,String> contextQualifiers = new HashMap<String,String>();
106            contextQualifiers.put(NAMESPACE_CODE, NAMESPACE1);
107            contextQualifiers.put(NAME, CONTEXT3);
108    
109            Map<String,String> agendaQualifiers = new HashMap<String,String>();
110            agendaQualifiers.put(NAME, AGENDA5);
111    
112            DateTime now = new DateTime();
113    
114            SelectionCriteria sc1 = SelectionCriteria.createCriteria(now, contextQualifiers, agendaQualifiers);
115    
116            Facts.Builder factsBuilder1 = Facts.Builder.create();
117            factsBuilder1.addFact(NULL_FACT, null);
118    
119            ExecutionOptions xOptions1 = new ExecutionOptions();
120            xOptions1.setFlag(ExecutionFlag.LOG_EXECUTION, true);
121    
122            PerformanceLogger perfLog = new PerformanceLogger();
123            perfLog.log("starting rule execution");
124            EngineResults eResults1 = KrmsApiServiceLocator.getEngine().execute(sc1, factsBuilder1.build(), xOptions1);
125            perfLog.log("finished rule execution", true);
126            List<ResultEvent> rEvents1 = executeEngineResults(eResults1);
127    
128            List<ResultEvent> ruleEvaluationResults1 = eResults1.getResultsOfType(ResultEvent.RULE_EVALUATED.toString());
129    
130            assertEquals("1 rules should have been evaluated", 1, ruleEvaluationResults1.size());
131    
132            assertTrue("rule 0 should have evaluated to true", ruleEvaluationResults1.get(0).getResult());
133    
134            // ONLY agenda 5 should have been selected
135            assertTrue(TestActionTypeService.actionFired("Agenda5::Rule5::TestAction"));
136    
137            assertAgendaDidNotExecute(AGENDA1);
138            assertAgendaDidNotExecute(AGENDA2);
139            assertAgendaDidNotExecute(AGENDA3);
140            assertAgendaDidNotExecute(AGENDA4);
141        }    
142    
143        @Transactional
144        @Test
145        public void testSelectAgendaByAttributeAndName() {
146    
147            Map<String,String> contextQualifiers = new HashMap<String,String>();
148            contextQualifiers.put(NAMESPACE_CODE, NAMESPACE1);
149            contextQualifiers.put(NAME, CONTEXT1);
150            contextQualifiers.put(CONTEXT1_QUALIFIER, CONTEXT1_QUALIFIER_VALUE);
151    
152            Map<String,String> agendaQualifiers = new HashMap<String,String>();
153            agendaQualifiers.put(AgendaDefinition.Constants.EVENT, TSUNAMI_EVENT);
154            agendaQualifiers.put(NAME, AGENDA1);
155    
156            DateTime now = new DateTime();
157    
158            SelectionCriteria sc1 = SelectionCriteria.createCriteria(now, contextQualifiers,
159                    Collections.singletonMap(AgendaDefinition.Constants.EVENT, TSUNAMI_EVENT));
160    
161            Facts.Builder factsBuilder1 = Facts.Builder.create();
162            factsBuilder1.addFact(CAMPUS_CODE_TERM_NAME, "BL");
163            factsBuilder1.addFact(BOOL1, "true");
164            factsBuilder1.addFact(BOOL2, Boolean.TRUE);
165            factsBuilder1.addFact(PREREQ_TERM_NAME, PREREQ_TERM_VALUE);
166    
167            ExecutionOptions xOptions1 = new ExecutionOptions();
168            xOptions1.setFlag(ExecutionFlag.LOG_EXECUTION, true);
169    
170            PerformanceLogger perfLog = new PerformanceLogger();
171            perfLog.log("starting rule execution");
172            EngineResults eResults1 = KrmsApiServiceLocator.getEngine().execute(sc1, factsBuilder1.build(), xOptions1);
173            perfLog.log("finished rule execution", true);
174            List<ResultEvent> rEvents1 = executeEngineResults(eResults1);
175    
176            List<ResultEvent> ruleEvaluationResults1 = eResults1.getResultsOfType(ResultEvent.RULE_EVALUATED.toString());
177    
178            assertEquals("4 rules should have been evaluated", 4, ruleEvaluationResults1.size());
179    
180            assertTrue("rule 0 should have evaluated to true", ruleEvaluationResults1.get(0).getResult());
181            assertFalse("rule 1 should have evaluated to false", ruleEvaluationResults1.get(1).getResult());
182            assertTrue("rule 2 should have evaluated to true", ruleEvaluationResults1.get(2).getResult());
183    
184            // ONLY agenda 1 should have been selected
185            assertTrue(TestActionTypeService.actionFired("TestAgenda1::Rule1::TestAction"));
186            assertFalse(TestActionTypeService.actionFired("TestAgenda1::Rule2::TestAction"));
187            assertTrue(TestActionTypeService.actionFired("TestAgenda1::Rule3::TestAction"));
188    
189            assertAgendaDidNotExecute(AGENDA2);
190            assertAgendaDidNotExecute(AGENDA3);
191            assertAgendaDidNotExecute(AGENDA4);
192            assertAgendaDidNotExecute(AGENDA5);
193        }
194    
195        @Transactional
196        @Test
197        public void testSelectAgendaByName() {
198            Map<String,String> contextQualifiers = new HashMap<String,String>();
199            contextQualifiers.put(NAMESPACE_CODE, NAMESPACE2);
200            contextQualifiers.put(NAME, CONTEXT2);
201            contextQualifiers.put(CONTEXT2_QUALIFIER, CONTEXT2_QUALIFIER_VALUE);
202            Map<String,String> agendaQualifiers = new HashMap<String,String>();
203    
204            /*
205             * We'll specifically NOT select this attribute to make sure that matching only takes place against qualifiers
206             * in the selection criteria
207             */
208            // agendaQualifiers.put(AgendaDefinition.Constants.EVENT, EARTHQUAKE_EVENT);
209    
210            agendaQualifiers.put(NAME, AGENDA3);
211            DateTime now = new DateTime();
212    
213            SelectionCriteria selectionCriteria = SelectionCriteria.createCriteria(now, contextQualifiers, agendaQualifiers);
214    
215            Facts.Builder factsBuilder2 = Facts.Builder.create();
216            factsBuilder2.addFact(BOOL1, "true");
217            factsBuilder2.addFact(BOOL2, Boolean.TRUE);
218            factsBuilder2.addFact(CAMPUS_CODE_TERM_NAME, "BL");
219            factsBuilder2.addFact(PREREQ_TERM_NAME, PREREQ_TERM_VALUE);
220    
221            ExecutionOptions xOptions2 = new ExecutionOptions();
222            xOptions2.setFlag(ExecutionFlag.LOG_EXECUTION, true);
223    
224    
225            PerformanceLogger perfLog = new PerformanceLogger();
226            perfLog.log("starting rule execution 1");
227            EngineResults eResults1 = KrmsApiServiceLocator.getEngine().execute(selectionCriteria, factsBuilder2.build(), xOptions2);
228            perfLog.log("finished rule execution 1");
229            List<ResultEvent> rEvents1 = executeEngineResults(eResults1);
230    
231            List<ResultEvent> ruleEvaluationResults1 = eResults1.getResultsOfType(ResultEvent.RULE_EVALUATED.toString());
232    
233            selectionCriteria = SelectionCriteria.createCriteria(now, contextQualifiers, agendaQualifiers);
234    
235            assertEquals("4 rules should have been evaluated", 4, ruleEvaluationResults1.size());
236    
237            assertAgendaDidNotExecute(AGENDA1);
238            assertAgendaDidNotExecute(AGENDA2);
239    
240            // ONLY agenda 3 should have been selected
241            assertTrue(TestActionTypeService.actionFired("Agenda3::Rule1::TestAction"));
242            assertFalse(TestActionTypeService.actionFired("Agenda3::Rule2::TestAction"));
243            assertTrue(TestActionTypeService.actionFired("Agenda3::Rule3::TestAction"));
244    
245            assertAgendaDidNotExecute(AGENDA4);
246            assertAgendaDidNotExecute(AGENDA5);
247        }
248    
249    
250        @Transactional
251        @Test
252        public void testSelectMultipleAgendasByAttribute() {
253            Map<String,String> contextQualifiers = new HashMap<String,String>();
254            contextQualifiers.put(NAMESPACE_CODE, NAMESPACE2);
255            contextQualifiers.put(NAME, CONTEXT2);
256            contextQualifiers.put(CONTEXT2_QUALIFIER, CONTEXT2_QUALIFIER_VALUE);
257    
258            Map<String,String> agendaQualifiers = new HashMap<String,String>();
259            agendaQualifiers.put(AgendaDefinition.Constants.EVENT, EARTHQUAKE_EVENT);
260    
261            DateTime now = new DateTime();
262    
263            SelectionCriteria selectionCriteria = SelectionCriteria.createCriteria(now, contextQualifiers, agendaQualifiers);
264    
265            Facts.Builder factsBuilder2 = Facts.Builder.create();
266            factsBuilder2.addFact(BOOL1, "true");
267            factsBuilder2.addFact(BOOL2, Boolean.TRUE);
268            factsBuilder2.addFact(CAMPUS_CODE_TERM_NAME, "BL");
269            factsBuilder2.addFact(PREREQ_TERM_NAME, PREREQ_TERM_VALUE);
270    
271            ExecutionOptions xOptions2 = new ExecutionOptions();
272            xOptions2.setFlag(ExecutionFlag.LOG_EXECUTION, true);
273    
274    
275            PerformanceLogger perfLog = new PerformanceLogger();
276            perfLog.log("starting rule execution 1");
277            EngineResults eResults1 = KrmsApiServiceLocator.getEngine().execute(selectionCriteria, factsBuilder2.build(), xOptions2);
278            perfLog.log("finished rule execution 1");
279            List<ResultEvent> rEvents1 = executeEngineResults(eResults1);
280    
281            List<ResultEvent> ruleEvaluationResults1 = eResults1.getResultsOfType(ResultEvent.RULE_EVALUATED.toString());
282    
283            selectionCriteria = SelectionCriteria.createCriteria(now, contextQualifiers, agendaQualifiers);
284    
285            assertEquals("8 rules should have been evaluated", 8, ruleEvaluationResults1.size());
286    
287            assertAgendaDidNotExecute(AGENDA1);
288    
289            // ONLY agendas 2 & 3 should have been selected
290    
291            assertTrue(TestActionTypeService.actionFired("Agenda2::Rule1::TestAction"));
292            assertFalse(TestActionTypeService.actionFired("Agenda2::Rule2::TestAction"));
293            assertTrue(TestActionTypeService.actionFired("Agenda2::Rule3::TestAction"));
294    
295            assertTrue(TestActionTypeService.actionFired("Agenda3::Rule1::TestAction"));
296            assertFalse(TestActionTypeService.actionFired("Agenda3::Rule2::TestAction"));
297            assertTrue(TestActionTypeService.actionFired("Agenda3::Rule3::TestAction"));
298    
299            assertAgendaDidNotExecute(AGENDA4);
300            assertAgendaDidNotExecute(AGENDA5);
301        }
302    
303        private List<ResultEvent> executeEngineResults(EngineResults eResults1) {
304            try {
305                return eResults1.getAllResults(); // CI NPE
306            } catch (NullPointerException npe) {
307                fail("https://jira.kuali.org/browse/KULRICE-8625 KRMS RepositoryCreateAndExecuteIntegrationTest fails with NPE in CI passes locally." + ExceptionUtils.getStackTrace(npe));
308            }
309            return null;
310        }
311    
312        private void assertAgendaDidNotExecute(String agendaName) {
313            assertFalse(TestActionTypeService.actionFired(agendaName+"::Rule1::TestAction"));
314            assertFalse(TestActionTypeService.actionFired(agendaName+"::Rule2::TestAction"));
315            assertFalse(TestActionTypeService.actionFired(agendaName+"::Rule3::TestAction"));
316        }
317    
318    }