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 }