001    /**
002     * Copyright 2005-2013 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.kew.rule.service.impl;
017    
018    import static org.junit.Assert.assertEquals;
019    import static org.junit.Assert.assertFalse;
020    import static org.junit.Assert.assertNotNull;
021    import static org.junit.Assert.assertNull;
022    import static org.junit.Assert.assertTrue;
023    import static org.junit.Assert.fail;
024    
025    import java.util.Iterator;
026    import java.util.List;
027    
028    import javax.persistence.PersistenceException;
029    
030    import org.junit.Test;
031    import org.kuali.rice.kew.rule.RuleBaseValues;
032    import org.kuali.rice.kew.rule.RuleExtensionBo;
033    import org.kuali.rice.kew.rule.RuleExtensionValue;
034    import org.kuali.rice.kew.service.KEWServiceLocator;
035    import org.kuali.rice.kew.test.KEWTestCase;
036    import org.kuali.rice.krad.util.LegacyUtils;
037    import org.kuali.rice.test.BaselineTestCase;
038    import org.springframework.dao.DataIntegrityViolationException;
039    
040    @BaselineTestCase.BaselineMode(BaselineTestCase.Mode.NONE)
041    public class RuleServiceTest extends KEWTestCase {
042    
043        protected void loadTestData() throws Exception {
044            loadXmlFile("org/kuali/rice/kew/rule/RouteTemplateConfig.xml");
045        }
046    
047        /**
048         * Tests the effect of adding a rule with an extension that has an empty value.
049         * Currently, depending on database, this may yield a constraint violation as the empty
050         * string may be interpreted as a NULL value by the database.
051         * @see https://test.kuali.org/jira/browse/KULRNE-6182
052         */
053        @Test
054        public void testEmptyRuleExtension() throws Exception {
055            final RuleBaseValues rbv = new RuleBaseValues();
056            rbv.setActive(Boolean.TRUE);
057            rbv.setCurrentInd(Boolean.TRUE);
058            rbv.setDescription("A test rule");
059            rbv.setDocTypeName("TestDocumentType");
060            rbv.setForceAction(Boolean.FALSE);
061    
062            RuleExtensionBo ext = new RuleExtensionBo();
063            RuleExtensionValue val = new RuleExtensionValue();
064            val.setKey("emptyvalue");
065            val.setValue("");
066            ext.getExtensionValues().add(val);
067            rbv.getRuleExtensions().add(ext);
068    
069            /*
070             * The AssertThrows below should work with OJB, but some problems are occurring when using JPA/Hibernate (see below).
071             * 
072             * FIXME: When the operation below throws the expected exception (when JPA/Hibernate is used), it appears to do so while returning from the method call
073             * (at which time the expected-to-fail saving operation gets committed by Hibernate). Unfortunately, the exception gets thrown at the wrong time when returning,
074             * because any attempts to run subsequent unit tests or unit test methods during the same JUnit test run will fail, due to NOWAIT exceptions
075             * during test case startup.
076             * 
077             * A temporary hack to bypass this problem is to add the following line at the end of the 3-argument RuleServiceImpl.save2() method, which will force the
078             * bad saving operation to take place at the right time for a proper rollback to occur:
079             * 
080             * getRuleDAO().findRuleBaseValuesById(ruleBaseValues.getId());
081             * 
082             * However, a longer-term solution will be needed in case there are similar areas in the system with these kinds of problems.
083             */
084            // TODO: this isn't really the same test as isJpaEnabled
085            // i.e. JPA will be present even when the legacy data framework is enabled
086            // what do we do in this case?
087            //final boolean isKewJpaEnabled = OrmUtils.isJpaEnabled("rice.kew");
088            final boolean isKewJpaEnabled = !LegacyUtils.isLegacyDataFrameworkEnabled();
089            try {
090                KEWServiceLocator.getRuleService().save2(rbv);
091                fail("exception did not happen");
092            } catch (RuntimeException e) {
093                boolean fail = !isKewJpaEnabled ? e instanceof PersistenceException : e instanceof DataIntegrityViolationException;
094                if (fail) {
095                    fail("Did not throw exception as expected.  If rule service behavior has changed, update this test.");
096                }
097            }
098    
099            //fail("Saving a rule extension value with an empty string as the value yields a constraint violation");
100        }
101        
102        /**
103         * Tests the RuleService's ability to retrieve RuleBaseValues instances that lack an associated rule responsibility. 
104         * @see https://test.kuali.org/jira/browse/KULRICE-3513
105         */
106        @Test
107        public void testRetrievalOfRulesWithoutResponsibilities() throws Exception {
108            loadXmlFile("org/kuali/rice/kew/rule/RulesWithoutResponsibilities.xml");
109            final String NULL_ID = null;
110            final String[] expectedRuleNames = {"NoResponsibilitiesRule1", "NoResponsibilitiesRule2", "NoResponsibilitiesRule3"};
111            final String[] expectedRuleDocTypes = {"RiceDocument.RuleDocument", "RiceDocument.child1", "RiceDocument.child1child"};
112            final String[] expectedRuleDescriptions = {"A rule with no responsibilities", "Another rule without responsibilities", "A third rule lacking responsibilities"};
113            final String[] personResponsibilities = {"rkirkend", "rkirkend", "user1"};
114            final String[] groupResponsibilities = {"TestWorkgroup", "NonSIT", "TestWorkgroup"};
115            int actualResponsibilitylessRuleCount = 0;
116            List<?> ruleList = null;
117            
118            // First, check that a blank search will retrieve all of the expected responsibility-less rules above.
119            ruleList = KEWServiceLocator.getRuleService().search(null, NULL_ID, null, null, null, null, null, null, null, "");
120            assertNotNull("The returned rule list should not be null", ruleList);
121            for (Iterator<?> ruleIter = ruleList.iterator(); ruleIter.hasNext();) {
122                    RuleBaseValues rBaseValues = (RuleBaseValues) ruleIter.next();
123                    if (rBaseValues.getRuleResponsibilities() == null || rBaseValues.getRuleResponsibilities().isEmpty()) {
124                                    actualResponsibilitylessRuleCount++;
125                    }
126            }
127            assertEquals("Wrong number of responsibility-less rules found", expectedRuleNames.length, actualResponsibilitylessRuleCount);
128            
129            // Next, test the retrieval of each of these rules independently.
130            for (int i = 0; i < expectedRuleNames.length; i++) {
131                    ruleList = KEWServiceLocator.getRuleService().search(expectedRuleDocTypes[i], NULL_ID, null, expectedRuleDescriptions[i], null, null, null, null, null, "");
132                    assertNotNull("The returned rule list should not be null when searching for rule '" + expectedRuleNames[i] + "'", ruleList);
133                    assertEquals("Exactly one rule should have been retrieved when searching for rule '" + expectedRuleNames[i] + "'", 1, ruleList.size());
134                    RuleBaseValues rBaseValues = (RuleBaseValues) ruleList.get(0);
135                    assertEquals("The retrieved rule has the wrong name", expectedRuleNames[i], rBaseValues.getName());
136                    assertEquals("Rule '" + expectedRuleNames[i] + "' has the wrong doc type name", expectedRuleDocTypes[i], rBaseValues.getDocTypeName());
137                    assertEquals("Rule '" + expectedRuleNames[i] + "' has the wrong description", expectedRuleDescriptions[i], rBaseValues.getDescription());
138                    assertTrue("Rule '" + expectedRuleNames[i] + "' should not have any responsibilities",
139                                    rBaseValues.getRuleResponsibilities() == null || rBaseValues.getRuleResponsibilities().isEmpty());
140            }
141            
142            // Verify that when searching for rules with the same doc types but with a person responsibility specified, the responsibility-less rules are not retrieved.
143            for (int i = 0; i < expectedRuleNames.length; i++) {
144                    ruleList = KEWServiceLocator.getRuleService().search(expectedRuleDocTypes[i], NULL_ID, null, null, null,
145                                    KEWServiceLocator.getIdentityHelperService().getPrincipalByPrincipalName(personResponsibilities[i]).getPrincipalId(), null, null, null, "user");
146                    assertNotNull("The returned rule list should not be null for doc type '" + expectedRuleDocTypes[i] + "'", ruleList);
147                    assertFalse("The returned rule list should not be empty for doc type '" + expectedRuleDocTypes[i] + "'", ruleList.isEmpty());
148                    for (Iterator<?> ruleIter = ruleList.iterator(); ruleIter.hasNext();) {
149                            RuleBaseValues rBaseValues = (RuleBaseValues) ruleIter.next();
150                            assertTrue((new StringBuilder()).append("Found a rule without responsibilities for doc type '").append(
151                                            expectedRuleDocTypes[i]).append("' and principal '").append(personResponsibilities[i]).append("'").toString(),
152                                                    rBaseValues.getRuleResponsibilities() != null && !rBaseValues.getRuleResponsibilities().isEmpty());
153                    }
154            }
155            
156            // Verify that when searching for rules with the same doc types but with a group responsibility specified, the responsibility-less rules are not retrieved.
157            for (int i = 0; i < expectedRuleNames.length; i++) {
158                    ruleList = KEWServiceLocator.getRuleService().search(expectedRuleDocTypes[i], NULL_ID, null, null,
159                                    KEWServiceLocator.getIdentityHelperService().getGroupByName("KR-WKFLW", groupResponsibilities[i]).getId(), null, null, null, null, "");
160                    assertNotNull("The returned rule list should not be null for doc type '" + expectedRuleDocTypes[i] + "'", ruleList);
161                    assertFalse("The returned rule list should not be empty for doc type '" + expectedRuleDocTypes[i] + "'", ruleList.isEmpty());
162                    for (Iterator<?> ruleIter = ruleList.iterator(); ruleIter.hasNext();) {
163                            RuleBaseValues rBaseValues = (RuleBaseValues) ruleIter.next();
164                            assertTrue((new StringBuilder()).append("Found a rule without responsibilities for doc type '").append(
165                                            expectedRuleDocTypes[i]).append("' and group '").append(groupResponsibilities[i]).append("' with namespace 'KR-WKFLW'").toString(),
166                                                    rBaseValues.getRuleResponsibilities() != null && !rBaseValues.getRuleResponsibilities().isEmpty());
167                    }
168            }
169        }
170    }