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