001    /**
002     * Copyright 2005-2011 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.framework;
017    
018    import static junit.framework.Assert.assertFalse;
019    import static junit.framework.Assert.assertNotNull;
020    import static junit.framework.Assert.assertTrue;
021    
022    import java.util.ArrayList;
023    import java.util.Arrays;
024    import java.util.Collections;
025    import java.util.HashMap;
026    import java.util.List;
027    import java.util.Map;
028    
029    import org.junit.Before;
030    import org.junit.Test;
031    import org.kuali.rice.krms.api.engine.EngineResults;
032    import org.kuali.rice.krms.api.engine.ExecutionOptions;
033    import org.kuali.rice.krms.api.engine.ExecutionFlag;
034    import org.kuali.rice.krms.api.engine.Facts;
035    import org.kuali.rice.krms.api.engine.SelectionCriteria;
036    import org.kuali.rice.krms.api.engine.Term;
037    import org.kuali.rice.krms.api.engine.TermResolver;
038    import org.kuali.rice.krms.api.repository.agenda.AgendaDefinition;
039    import org.kuali.rice.krms.framework.engine.Action;
040    import org.kuali.rice.krms.framework.engine.Agenda;
041    import org.kuali.rice.krms.framework.engine.AgendaTreeEntry;
042    import org.kuali.rice.krms.framework.engine.BasicAgenda;
043    import org.kuali.rice.krms.framework.engine.BasicAgendaTree;
044    import org.kuali.rice.krms.framework.engine.BasicAgendaTreeEntry;
045    import org.kuali.rice.krms.framework.engine.BasicContext;
046    import org.kuali.rice.krms.framework.engine.BasicRule;
047    import org.kuali.rice.krms.framework.engine.ComparableTermBasedProposition;
048    import org.kuali.rice.krms.framework.engine.expression.ComparisonOperator;
049    import org.kuali.rice.krms.framework.engine.Context;
050    import org.kuali.rice.krms.framework.engine.ContextProvider;
051    import org.kuali.rice.krms.framework.engine.Proposition;
052    import org.kuali.rice.krms.framework.engine.ProviderBasedEngine;
053    import org.kuali.rice.krms.framework.engine.ResultLogger;
054    import org.kuali.rice.krms.framework.engine.Rule;
055    
056    public class AgendaTest {
057            private static final ResultLogger LOG = ResultLogger.getInstance();
058    
059            @Before
060            public void setUp() {
061                    ActionMock.resetActionsFired();
062            }
063    
064            // totalCostTerm will resolve to the Integer value 5
065            private Proposition trueProp = new ComparableTermBasedProposition(ComparisonOperator.GREATER_THAN, totalCostTerm, Integer.valueOf(1));
066            private Proposition falseProp = new ComparableTermBasedProposition(ComparisonOperator.GREATER_THAN, totalCostTerm, Integer.valueOf(1000));
067            
068            @Test
069            public void testAllRulesAgenda() {
070    
071                    Rule rule1 = new BasicRule("r1", trueProp, Collections.<Action>singletonList(new ActionMock("a1")));
072                    Rule rule2 = new BasicRule("r2", falseProp, Collections.<Action>singletonList(new ActionMock("a2")));
073                    Rule rule3 = new BasicRule("r3", trueProp, Collections.<Action>singletonList(new ActionMock("a3")));
074                    
075                    AgendaTreeEntry entry1 = new BasicAgendaTreeEntry(rule1);
076                    AgendaTreeEntry entry2 = new BasicAgendaTreeEntry(rule2);
077                    AgendaTreeEntry entry3 = new BasicAgendaTreeEntry(rule3);
078                    BasicAgendaTree agendaTree = new BasicAgendaTree(entry1, entry2, entry3); 
079                    Agenda agenda = new BasicAgenda(Collections.singletonMap(AgendaDefinition.Constants.EVENT, "test"), agendaTree);
080                    
081                    execute(agenda);
082    
083                    assertTrue(ActionMock.actionFired("a1"));
084                    assertFalse(ActionMock.actionFired("a2"));
085                    assertTrue(ActionMock.actionFired("a3"));
086            }
087            
088            @Test
089            public void testIfTrueSubAgenda() {
090    
091                    Rule rule1 = new BasicRule("r1", trueProp, Collections.<Action>singletonList(new ActionMock("a1")));
092                    Rule rule2 = new BasicRule("r2", falseProp, Collections.<Action>singletonList(new ActionMock("a2")));
093                    Rule subRule1 = new BasicRule("r1s1", trueProp, Collections.<Action>singletonList(new ActionMock("a3")));
094                    
095                    BasicAgendaTree subAgendaTree1 = new BasicAgendaTree(new BasicAgendaTreeEntry(subRule1));
096                    BasicAgendaTree agendaTree1 = new BasicAgendaTree(new BasicAgendaTreeEntry(rule1, subAgendaTree1, null)); 
097                    Agenda agenda1 = new BasicAgenda(Collections.singletonMap(AgendaDefinition.Constants.EVENT, "test"), agendaTree1);
098                    
099                    execute(agenda1);
100    
101                    assertTrue(ActionMock.actionFired("a1"));
102                    assertTrue(ActionMock.actionFired("a3"));
103                    
104                    // RESET
105                    ActionMock.resetActionsFired();
106                    
107                    BasicAgendaTree subAgendaTree2 = new BasicAgendaTree(new BasicAgendaTreeEntry(subRule1));
108                    BasicAgendaTree agendaTree2 = new BasicAgendaTree(new BasicAgendaTreeEntry(rule2, subAgendaTree2, null)); 
109                    Agenda agenda2 = new BasicAgenda(Collections.singletonMap(AgendaDefinition.Constants.EVENT, "test"), agendaTree2);
110                    
111                    execute(agenda2);
112    
113                    assertFalse(ActionMock.actionFired("a2"));
114                    assertFalse(ActionMock.actionFired("a3"));
115            }
116    
117            @Test
118            public void testIfFalseSubAgenda() {
119    
120                    Rule rule1 = new BasicRule("r1", trueProp, Collections.<Action>singletonList(new ActionMock("a1")));
121                    Rule rule2 = new BasicRule("r2", falseProp, Collections.<Action>singletonList(new ActionMock("a2")));
122                    Rule subRule1 = new BasicRule("r1s1", trueProp, Collections.<Action>singletonList(new ActionMock("a3")));
123                    
124                    BasicAgendaTree subAgendaTree1 = new BasicAgendaTree(new BasicAgendaTreeEntry(subRule1));
125                    BasicAgendaTree agendaTree1 = new BasicAgendaTree(new BasicAgendaTreeEntry(rule1, null, subAgendaTree1)); 
126                    Agenda agenda1 = new BasicAgenda(Collections.singletonMap(AgendaDefinition.Constants.EVENT, "test"), agendaTree1);
127                    
128                    execute(agenda1);
129    
130                    assertTrue(ActionMock.actionFired("a1"));
131                    assertFalse(ActionMock.actionFired("a3"));
132                    
133                    // RESET
134                    ActionMock.resetActionsFired();
135                    
136                    BasicAgendaTree subAgendaTree2 = new BasicAgendaTree(new BasicAgendaTreeEntry(subRule1));
137                    BasicAgendaTree agendaTree2 = new BasicAgendaTree(new BasicAgendaTreeEntry(rule2, null, subAgendaTree2)); 
138                    Agenda agenda2 = new BasicAgenda(Collections.singletonMap(AgendaDefinition.Constants.EVENT, "test"), agendaTree2);
139                    
140                    execute(agenda2);
141    
142                    assertFalse(ActionMock.actionFired("a2"));
143                    assertTrue(ActionMock.actionFired("a3"));
144            }
145            
146            @Test
147            public void testAfterAgenda() {
148    
149                    Rule rule1 = new BasicRule("r1", trueProp, Collections.<Action>singletonList(new ActionMock("a1")));
150                    Rule rule2 = new BasicRule("r2", falseProp, Collections.<Action>singletonList(new ActionMock("a2")));
151                    Rule subRule1 = new BasicRule("r1s1", trueProp, Collections.<Action>singletonList(new ActionMock("a3")));
152                    
153                    BasicAgendaTree agendaTree1 = new BasicAgendaTree(new BasicAgendaTreeEntry(rule1), new BasicAgendaTreeEntry(subRule1)); 
154                    Agenda agenda1 = new BasicAgenda(Collections.singletonMap(AgendaDefinition.Constants.EVENT, "test"), agendaTree1);
155                    
156                    execute(agenda1);
157    
158                    assertTrue(ActionMock.actionFired("a1"));
159                    assertTrue(ActionMock.actionFired("a3"));
160                    
161                    // RESET
162                    ActionMock.resetActionsFired();
163                    
164                    BasicAgendaTree agendaTree2 = new BasicAgendaTree(new BasicAgendaTreeEntry(rule2), new BasicAgendaTreeEntry(subRule1)); 
165                    Agenda agenda2 = new BasicAgenda(Collections.singletonMap(AgendaDefinition.Constants.EVENT, "test"), agendaTree2);
166                    
167                    execute(agenda2);
168    
169                    assertFalse(ActionMock.actionFired("a2"));
170                    assertTrue(ActionMock.actionFired("a3"));
171            }
172    
173        /**
174         * Make sure agenda qualifier matching is based on the provided qualifiers
175         * see https://jira.kuali.org/browse/KULRICE-6098
176         */
177        public void testQualifierMissingFromAgenda() {
178            // RESET
179                    ActionMock.resetActionsFired();
180    
181            Rule rule1 = new BasicRule("r1", trueProp, Collections.<Action>singletonList(new ActionMock("a1")));
182    
183            BasicAgendaTree agendaTree1 = new BasicAgendaTree(new BasicAgendaTreeEntry(rule1));
184            Agenda agenda1 = new BasicAgenda(Collections.<String, String>emptyMap(), agendaTree1);
185    
186            // this shouldn't select any agendas, so no rules will really get executed
187            execute(agenda1, Collections.singletonMap(AgendaDefinition.Constants.EVENT, "test"));
188    
189            // Expected: the agenda didn't get selected, so the action didn't fire
190            assertFalse("the agenda should not have been selected and executed", ActionMock.actionFired("a1"));
191        }
192    
193        /**
194         * execute the engine against a trivial context containing the given agenda.
195         * a default agenda qualifier of Event=test will be used.
196         * @param agenda
197         */
198        private void execute(Agenda agenda) {
199            execute(agenda, Collections.singletonMap(AgendaDefinition.Constants.EVENT, "test"));
200        }
201    
202        /**
203         * execute the engine against a trivial context containing the given agenda.
204         * the given agenda qualifier will be used.
205         * @param agenda
206         * @param agendaQualifiers
207         */
208            private void execute(Agenda agenda, Map<String, String> agendaQualifiers) {
209                    Map<String, String> contextQualifiers = new HashMap<String, String>();
210                    contextQualifiers.put("docTypeName", "Proposal");
211    
212                    List<TermResolver<?>> testResolvers = new ArrayList<TermResolver<?>>();
213                    testResolvers.add(testResolver);
214                    
215                    Context context = new BasicContext(Arrays.asList(agenda), testResolvers);
216                    ContextProvider contextProvider = new ManualContextProvider(context);
217                    
218                    SelectionCriteria selectionCriteria = SelectionCriteria.createCriteria(null, contextQualifiers,
219                    agendaQualifiers);
220                    
221                    ProviderBasedEngine engine = new ProviderBasedEngine();
222                    engine.setContextProvider(contextProvider);
223    
224                    // Set execution options to log execution
225                    ExecutionOptions executionOptions = new ExecutionOptions().setFlag(ExecutionFlag.LOG_EXECUTION, true);
226                    
227                    EngineResults results = engine.execute(selectionCriteria, Facts.EMPTY_FACTS, executionOptions);
228                    assertNotNull(results);
229            }
230            
231            private static final Term totalCostTerm = new Term("totalCost");
232            
233            private static final TermResolver<Integer> testResolver = new TermResolverMock<Integer>(totalCostTerm.getName(), 10);
234    }