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 }