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 */
016package org.kuali.rice.kew.rule;
017
018import org.apache.log4j.Logger;
019import org.junit.Test;
020import org.kuali.rice.core.api.CoreApiServiceLocator;
021import org.kuali.rice.core.api.config.property.ConfigContext;
022import org.kuali.rice.core.api.util.xml.XmlException;
023import org.kuali.rice.kew.batch.KEWXmlDataLoader;
024import org.kuali.rice.kew.exception.WorkflowServiceErrorException;
025import org.kuali.rice.kew.rule.service.RuleServiceInternal;
026import org.kuali.rice.kew.service.KEWServiceLocator;
027import org.kuali.rice.kew.test.KEWTestCase;
028import org.kuali.rice.kew.test.TestUtilities;
029import org.kuali.rice.kew.api.KewApiConstants;
030import org.kuali.rice.kew.xml.RuleXmlParser;
031
032import java.io.IOException;
033import java.io.InputStream;
034import java.util.ArrayList;
035import java.util.List;
036
037import static org.junit.Assert.*;
038
039public class RuleXmlParserTest extends KEWTestCase {
040    private static final Logger LOG = Logger.getLogger(RuleXmlParserTest.class);
041
042    protected void loadTestData() throws Exception {
043        loadXmlFile("RouteTemplateConfig.xml");
044        loadXmlFile("DuplicateRuleToImport.xml");
045    }
046
047    @Test public void testRuleXmlParserCacheUpdate() throws Exception {
048        RuleServiceInternal ruleService = KEWServiceLocator.getRuleService();
049        int ruleSize = ruleService.fetchAllCurrentRulesForTemplateDocCombination("TestRuleTemplate", "TestDocumentType").size();
050
051        List collections = new ArrayList();
052        //ultimately it is the content of RulesToImport that determines whether or not we're
053        //going to hit the rules xml parser
054        InputStream xmlFile = TestUtilities.loadResource(this.getClass(), "RulesToImport.xml");
055        collections.add(KEWXmlDataLoader.getFileXmlDocCollection(xmlFile, "WorkflowUnitTestTemp"));
056        CoreApiServiceLocator.getXmlIngesterService().ingest(collections, null);
057
058        Thread.sleep(5000);//give cache time to reload;
059        int newRuleSize = ruleService.fetchAllCurrentRulesForTemplateDocCombination("TestRuleTemplate", "TestDocumentType").size();
060        assertEquals("Three more rules should have been returned from the cached service", ruleSize + 3, newRuleSize);
061    }
062
063    @Test public void testDuplicateRule() throws IOException, XmlException {
064        InputStream stream = getClass().getResourceAsStream("DuplicateRuleToImport.xml");
065        assertNotNull(stream);
066        log.info("Importing duplicate again");
067        try {
068            KEWServiceLocator.getRuleService().loadXml(stream, null);
069        } catch (WorkflowServiceErrorException wsee) {
070            assertNotNull(TestUtilities.findExceptionInStack(wsee, XmlException.class));
071        }
072    }
073
074    @Test public void testDuplicateRuleWithExpression() throws IOException, XmlException {
075        InputStream stream = getClass().getResourceAsStream("DuplicateRuleToImportWithExpression.xml");
076        assertNotNull(stream);
077        log.info("Importing duplicate again");
078        try {
079            KEWServiceLocator.getRuleService().loadXml(stream, null);
080        } catch (WorkflowServiceErrorException wsee) {
081            assertNotNull(TestUtilities.findExceptionInStack(wsee, XmlException.class));
082        }
083    }
084
085    @Test public void testNotDuplicateRule() throws IOException, XmlException {
086        InputStream stream = getClass().getResourceAsStream("NotADuplicateRuleToImport.xml");
087        assertNotNull(stream);
088        log.info("Importing a unique rule");
089        // load the unique template first
090        KEWServiceLocator.getRuleTemplateService().loadXml(stream, null);
091        stream = getClass().getResourceAsStream("NotADuplicateRuleToImport.xml");
092        // then the rule
093        KEWServiceLocator.getRuleService().loadXml(stream, null);
094    }
095
096    @Test public void testNotDuplicateRuleWithExpression() throws IOException, XmlException {
097        InputStream stream = getClass().getResourceAsStream("NotADuplicateRuleToImportWithExpression.xml");
098        assertNotNull(stream);
099        log.info("Importing a unique rule");
100        // load the unique template first
101        KEWServiceLocator.getRuleTemplateService().loadXml(stream, null);
102        stream = getClass().getResourceAsStream("NotADuplicateRuleToImportWithExpression.xml");
103        // then the rule
104        KEWServiceLocator.getRuleService().loadXml(stream, null);
105    }
106
107    private static RuleExtensionValue getExtensionValue(List<RuleExtensionValue> list, String name) {
108        for (RuleExtensionValue extensionValue: list) {
109            if (name.equals(extensionValue.getKey())) return extensionValue;
110        }
111        return null;
112    }
113
114    @Test public void testNamedRule() {
115        loadXmlFile("NamedRule.xml");
116        RuleServiceInternal ruleService = KEWServiceLocator.getRuleService();
117        RuleBaseValues rule = ruleService.getRuleByName("ANamedRule");
118        assertNotNull(rule);
119        assertEquals("ANamedRule", rule.getName());
120        assertEquals("A named rule", rule.getDescription());
121        LOG.info("Before Testing  To and From Dates : " + rule.getToDateString()+" "+rule.getFromDateString());
122        assertNull(rule.getToDateString());
123        assertNull(rule.getFromDateString());
124        LOG.info("Rule To and From Dates : " + rule.getDocTypeName()+" "+rule.getName());
125        List extensions = rule.getRuleExtensions();
126        assertEquals(1, extensions.size());
127        RuleExtensionBo extension = (RuleExtensionBo) extensions.get(0);
128        assertEquals("TestRuleAttribute", extension.getRuleTemplateAttribute().getRuleAttribute().getName());
129        List extensionValues = extension.getExtensionValues();
130        assertEquals(2, extensionValues.size());
131        //RuleExtensionValue extensionValue = (RuleExtensionValue) extensionValues.get(0);
132        RuleExtensionValue extensionValue = getExtensionValue(extensionValues, "color");
133        assertEquals("color", extensionValue.getKey());
134        assertEquals("green", extensionValue.getValue());
135        //extensionValue = (RuleExtensionValue) extensionValues.get(1);
136        extensionValue = getExtensionValue(extensionValues, "shape");
137        assertEquals("shape", extensionValue.getKey());
138        assertEquals("square", extensionValue.getValue());
139        List responsibilities = rule.getRuleResponsibilities();
140        assertEquals(1, responsibilities.size());
141        RuleResponsibilityBo responsibility = (RuleResponsibilityBo) responsibilities.get(0);
142        assertEquals("user1", responsibility.getPrincipal().getPrincipalName());
143        assertEquals("A", responsibility.getActionRequestedCd());
144    }
145
146    @Test public void testNamedRuleWithExpression() {
147        loadXmlFile("NamedRuleWithExpression.xml");
148        RuleServiceInternal ruleService = KEWServiceLocator.getRuleService();
149        RuleBaseValues rule = ruleService.getRuleByName("ANamedRule");
150        assertNotNull(rule);
151        assertEquals("ANamedRule", rule.getName());
152        assertEquals("A named rule", rule.getDescription());
153        List extensions = rule.getRuleExtensions();
154        assertEquals(1, extensions.size());
155        RuleExtensionBo extension = (RuleExtensionBo) extensions.get(0);
156        assertEquals("TestRuleAttribute", extension.getRuleTemplateAttribute().getRuleAttribute().getName());
157        List extensionValues = extension.getExtensionValues();
158        assertEquals(2, extensionValues.size());
159        //RuleExtensionValue extensionValue = (RuleExtensionValue) extensionValues.get(0);
160        RuleExtensionValue extensionValue = getExtensionValue(extensionValues, "color");
161        assertEquals("color", extensionValue.getKey());
162        assertEquals("green", extensionValue.getValue());
163        //extensionValue = (RuleExtensionValue) extensionValues.get(1);
164        extensionValue = getExtensionValue(extensionValues, "shape");
165        assertEquals("shape", extensionValue.getKey());
166        assertEquals("square", extensionValue.getValue());
167        List responsibilities = rule.getRuleResponsibilities();
168        assertEquals(1, responsibilities.size());
169        RuleResponsibilityBo responsibility = (RuleResponsibilityBo) responsibilities.get(0);
170        assertEquals("user1", responsibility.getPrincipal().getPrincipalName());
171        assertEquals("A", responsibility.getActionRequestedCd());
172        assertNotNull(rule.getRuleExpressionDef());
173        assertEquals("someType", rule.getRuleExpressionDef().getType());
174        assertEquals("some expression", rule.getRuleExpressionDef().getExpression());
175    }
176
177    @Test public void testUpdatedRule() {
178        testNamedRule();
179        
180        RuleServiceInternal ruleService = KEWServiceLocator.getRuleService();
181        // let's grab the responsibility id from the original named rule
182        RuleBaseValues rule = ruleService.getRuleByName("ANamedRule");
183        String responsibilityId = rule.getRuleResponsibilities().get(0).getResponsibilityId();
184        String ruleId = rule.getId();
185        Integer versionNumber = rule.getVersionNbr();
186        
187        loadXmlFile("UpdatedNamedRule.xml");
188        rule = ruleService.getRuleByName("ANamedRule");
189        assertNotNull(rule);
190        assertEquals("ANamedRule", rule.getName());
191        assertTrue("Rule should be current.", rule.getCurrentInd());
192        assertFalse("Rule should not be a delegate rule.", rule.getDelegateRule());
193        assertFalse("Rule should not be a template rule.", rule.getTemplateRuleInd());
194        assertNull("Rule should not have a from date.", rule.getFromDateValue());
195        assertNull("Rule should not have a to date.", rule.getToDateValue());
196        
197        // check that the previous versions line up and that the rule is not the same
198        assertFalse("Rule ids should be different", ruleId.equals(rule.getId()));
199        assertEquals("Previous version id should be correct", ruleId, rule.getPreviousRuleId());
200        assertEquals("Version ids are incorrect", new Integer(versionNumber + 1), rule.getVersionNbr());
201        // fetch the original rule and verify that it's no longer current
202        RuleBaseValues oldRule = ruleService.findRuleBaseValuesById(ruleId);
203        assertFalse("Old rule should no longer be current.", oldRule.getCurrentInd());
204        
205        assertEquals("A named rule with an updated description, rule extension values, and responsibilities", rule.getDescription());
206        List extensions = rule.getRuleExtensions();
207        assertEquals(1, extensions.size());
208        RuleExtensionBo extension = (RuleExtensionBo) extensions.get(0);
209        assertEquals("TestRuleAttribute", extension.getRuleTemplateAttribute().getRuleAttribute().getName());
210        List extensionValues = extension.getExtensionValues();
211        assertEquals(2, extensionValues.size());
212        //RuleExtensionValue extensionValue = (RuleExtensionValue) extensionValues.get(0);
213        RuleExtensionValue extensionValue = getExtensionValue(extensionValues, "flavor");
214        assertEquals("flavor", extensionValue.getKey());
215        assertEquals("vanilla", extensionValue.getValue());
216        //extensionValue = (RuleExtensionValue) extensionValues.get(1);
217        extensionValue = getExtensionValue(extensionValues, "value");
218        assertEquals("value", extensionValue.getKey());
219        assertEquals("10", extensionValue.getValue());
220        List responsibilities = rule.getRuleResponsibilities();
221        assertEquals(2, responsibilities.size());
222        
223        // responsibility should have the same id as our original responsibility
224        RuleResponsibilityBo responsibility = (RuleResponsibilityBo) responsibilities.get(0);
225        assertEquals(responsibilityId, responsibility.getResponsibilityId());
226        assertEquals("user1", responsibility.getPrincipal().getPrincipalName());
227        assertEquals("A", responsibility.getActionRequestedCd());
228        assertEquals(new Integer(1), responsibility.getPriority());
229        
230        responsibility = (RuleResponsibilityBo) responsibilities.get(1);
231        assertFalse(responsibilityId.equals(responsibility.getResponsibilityId()));
232        assertEquals("user2", responsibility.getPrincipal().getPrincipalName());
233        assertEquals("F", responsibility.getActionRequestedCd());
234        assertEquals(new Integer(1), responsibility.getPriority());
235    }
236
237    @Test public void testUpdatedRuleWithExpression() {
238        testNamedRule();
239        loadXmlFile("UpdatedNamedRuleWithExpression.xml");
240        RuleServiceInternal ruleService = KEWServiceLocator.getRuleService();
241        RuleBaseValues rule = ruleService.getRuleByName("ANamedRule");
242        assertNotNull(rule);
243        assertEquals("ANamedRule", rule.getName());
244        assertEquals("A named rule with an updated description, rule extension values, and responsibilities", rule.getDescription());
245        List extensions = rule.getRuleExtensions();
246        assertEquals(1, extensions.size());
247        RuleExtensionBo extension = (RuleExtensionBo) extensions.get(0);
248        assertEquals("TestRuleAttribute", extension.getRuleTemplateAttribute().getRuleAttribute().getName());
249        List extensionValues = extension.getExtensionValues();
250        assertEquals(2, extensionValues.size());
251        //RuleExtensionValue extensionValue = (RuleExtensionValue) extensionValues.get(0);
252        RuleExtensionValue extensionValue = getExtensionValue(extensionValues, "flavor");
253        assertEquals("flavor", extensionValue.getKey());
254        assertEquals("vanilla", extensionValue.getValue());
255        //extensionValue = (RuleExtensionValue) extensionValues.get(1);
256        extensionValue = getExtensionValue(extensionValues, "value");
257        assertEquals("value", extensionValue.getKey());
258        assertEquals("10", extensionValue.getValue());
259        List responsibilities = rule.getRuleResponsibilities();
260        assertEquals(1, responsibilities.size());
261        RuleResponsibilityBo responsibility = (RuleResponsibilityBo) responsibilities.get(0);
262        assertEquals("user2", responsibility.getPrincipal().getPrincipalName());
263        assertEquals("F", responsibility.getActionRequestedCd());
264    }
265
266    /**
267     * This test tests that an anonymous rule will still be checked against named rules for duplication.
268     */
269    @Test
270    public void testAnonymousDuplicatesNamed() {
271        testNamedRule();
272
273        final InputStream stream = getClass().getResourceAsStream("DuplicateAnonymousRule.xml");
274        assertNotNull(stream);
275        log.info("Importing anonymous duplicate rule");
276        try {
277            KEWServiceLocator.getRuleService().loadXml(stream, null);
278            fail("Expected exception was not thrown");
279        } catch (WorkflowServiceErrorException e) {
280            assertNotNull("Expected exception was not thrown", TestUtilities.findExceptionInStack(e.getCause(), XmlException.class));
281        }
282    }
283
284    /**
285     * This test tests that an anonymous rule will still be checked against named rules for duplication.
286     */
287    @Test public void testAnonymousWithExpressionDuplicatesNamed() {
288        testNamedRuleWithExpression();
289
290        final InputStream stream = getClass().getResourceAsStream("DuplicateAnonymousRuleWithExpression.xml");
291        assertNotNull(stream);
292        log.info("Importing anonymous duplicate rule");
293        try {
294            KEWServiceLocator.getRuleService().loadXml(stream, null);
295            fail("Expected exception was not thrown");
296        } catch (WorkflowServiceErrorException e) {
297            assertNotNull("Expected exception was not thrown", TestUtilities.findExceptionInStack(e.getCause(), XmlException.class));
298        }
299    }
300
301    @Test public void testParameterReplacement() throws IOException, XmlException {
302        ConfigContext.getCurrentContextConfig().putProperty("test.replacement.user", "user3");
303        ConfigContext.getCurrentContextConfig().putProperty("test.replacement.workgroup", "WorkflowAdmin");
304        List<RuleBaseValues> rules = new RuleXmlParser().parseRules(getClass().getResourceAsStream("ParameterizedRule.xml"));
305        assertEquals(1, rules.size());
306        RuleBaseValues rule = rules.get(0);
307        assertEquals(2, rule.getRuleResponsibilities().size());
308        RuleResponsibilityBo resp = (RuleResponsibilityBo) rule.getRuleResponsibilities().get(0);
309
310        if (resp.isUsingPrincipal()) {
311            assertEquals("user3", resp.getPrincipal().getPrincipalName());
312        } else {
313            assertEquals("WorkflowAdmin", resp.getGroup().getName());
314        }
315
316        ConfigContext.getCurrentContextConfig().putProperty("test.replacement.user", "user1");
317        ConfigContext.getCurrentContextConfig().putProperty("test.replacement.workgroup", "TestWorkgroup");
318        rules = new RuleXmlParser().parseRules(getClass().getResourceAsStream("ParameterizedRule.xml"));
319        assertEquals(1, rules.size());
320        rule = rules.get(0);
321        assertEquals(2, rule.getRuleResponsibilities().size());
322        resp = (RuleResponsibilityBo) rule.getRuleResponsibilities().get(0);
323
324        if (resp.isUsingPrincipal())
325        {
326            assertEquals("user1", resp.getPrincipal().getPrincipalName());   
327        } 
328        else 
329        {
330            assertEquals("TestWorkgroup", resp.getGroup().getName());
331        }
332    }
333
334    @Test public void removeTemplateFromNamedRule() {
335        RuleServiceInternal ruleService = KEWServiceLocator.getRuleService();
336        int originalRuleCount = ruleService.fetchAllCurrentRulesForTemplateDocCombination("TestRuleTemplate", "TestDocumentType").size();
337
338        testNamedRule();
339
340        LOG.debug("Rules for doctype/template combo:");
341        int ruleCount = 0;
342        List<RuleBaseValues> list = ruleService.fetchAllCurrentRulesForTemplateDocCombination("TestRuleTemplate", "TestDocumentType");
343        if (list != null) {
344            ruleCount = list.size();
345            for (RuleBaseValues rbv: list) {
346                LOG.info(rbv);
347            }
348        }
349
350        loadXmlFile("NamedRuleWithoutTemplate.xml");
351
352        LOG.debug("Rules for doctype/template combo after import of named rule:");
353        int ruleCountAfter = 0;
354        list = ruleService.fetchAllCurrentRulesForTemplateDocCombination("TestRuleTemplate", "TestDocumentType");
355        if (list != null) {
356            ruleCountAfter = list.size();
357            for (RuleBaseValues rbv: list) {
358                LOG.info(rbv);
359            }
360        }
361
362        RuleBaseValues rule = ruleService.getRuleByName("ANamedRule");
363
364        assertNotNull(rule);
365        LOG.info("Rule id of latest version: " + rule.getId());
366        assertEquals("ANamedRule", rule.getName());
367        assertEquals("A named rule with previously defined template removed", rule.getDescription());
368
369        assertEquals("The rules for template/doctype combo should have been decreased by one after reimport of named rule without template", ruleCount - 1, ruleCountAfter);
370        assertEquals("Rule count should be original template/doctype combo rule count after removing template from named rule", originalRuleCount, ruleCountAfter);
371
372        assertNull(rule.getRuleTemplate());
373
374        // templateless rules cannot have extensions, so these should be removed
375        List extensions = rule.getRuleExtensions();
376        assertEquals(0, extensions.size());
377
378        List responsibilities = rule.getRuleResponsibilities();
379        assertEquals(1, responsibilities.size());
380        RuleResponsibilityBo responsibility = (RuleResponsibilityBo) responsibilities.get(0);
381        assertEquals("user2", responsibility.getPrincipal().getPrincipalName());
382        assertEquals("F", responsibility.getActionRequestedCd());
383    }
384
385    @Test public void testInvalidTemplatelessNamedRule() {
386        testNamedRule();
387        try {
388                loadXmlFile("InvalidTemplatelessNamedRule.xml");
389                fail("Rule should have failed to load because it attempts to define extensions on a templateless rule.");
390        } catch (Exception e) {}
391    }
392    
393    @Test public void testRulesWithDifferentResponsibilityTypes() throws Exception {
394        loadXmlFile("RulesWithDifferentResponsibilityTypes.xml");
395        RuleServiceInternal ruleService = KEWServiceLocator.getRuleService();
396        
397        RuleBaseValues rule = ruleService.getRuleByName("RespTypeTest1");
398        assertNotNull(rule);
399        assertEquals("Rule should have a principal responsibility", KewApiConstants.RULE_RESPONSIBILITY_WORKFLOW_ID, rule.getRuleResponsibilities().get(0).getRuleResponsibilityType());
400        assertEquals("Rule should have a principal id of user1", "user1", rule.getRuleResponsibilities().get(0).getRuleResponsibilityName());
401        
402        rule = ruleService.getRuleByName("RespTypeTest2");
403        assertNotNull(rule);
404        assertEquals("Rule should have a principal responsibility", KewApiConstants.RULE_RESPONSIBILITY_WORKFLOW_ID, rule.getRuleResponsibilities().get(0).getRuleResponsibilityType());
405        assertEquals("Rule should have a principal id of user1", "user1", rule.getRuleResponsibilities().get(0).getRuleResponsibilityName());
406        
407        rule = ruleService.getRuleByName("RespTypeTest3");
408        assertNotNull(rule);
409        assertEquals("Rule should have a group responsibility", KewApiConstants.RULE_RESPONSIBILITY_GROUP_ID, rule.getRuleResponsibilities().get(0).getRuleResponsibilityType());
410        assertEquals("Rule should have a group id of 3001", "3001", rule.getRuleResponsibilities().get(0).getRuleResponsibilityName());
411
412        rule = ruleService.getRuleByName("RespTypeTest4");
413        assertNotNull(rule);
414        assertEquals("Rule should have a group responsibility", KewApiConstants.RULE_RESPONSIBILITY_GROUP_ID, rule.getRuleResponsibilities().get(0).getRuleResponsibilityType());
415        assertEquals("Rule should have a group id of 1", "1", rule.getRuleResponsibilities().get(0).getRuleResponsibilityName());
416
417        rule = ruleService.getRuleByName("RespTypeTest5");
418        assertNotNull(rule);
419        assertEquals("Rule should have a role responsibility", KewApiConstants.RULE_RESPONSIBILITY_ROLE_ID, rule.getRuleResponsibilities().get(0).getRuleResponsibilityType());
420        assertEquals("Invalid role name", "org.kuali.rice.kew.rule.TestRuleAttribute!TEST", rule.getRuleResponsibilities().get(0).getRuleResponsibilityName());
421
422        rule = ruleService.getRuleByName("RespTypeTest6");
423        assertNotNull(rule);
424        assertEquals("Rule should have a role responsibility", KewApiConstants.RULE_RESPONSIBILITY_ROLE_ID, rule.getRuleResponsibilities().get(0).getRuleResponsibilityType());
425        assertEquals("Invalid role name", "org.kuali.rice.kew.rule.TestRuleAttribute!TEST", rule.getRuleResponsibilities().get(0).getRuleResponsibilityName());
426    }
427}