001/**
002 * Copyright 2005-2014 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.xml.export;
017
018import org.apache.commons.lang.StringUtils;
019import org.apache.commons.lang.time.DateUtils;
020import org.junit.Test;
021import org.kuali.rice.core.api.CoreApiServiceLocator;
022import org.kuali.rice.core.api.util.ClasspathOrFileResourceLoader;
023import org.kuali.rice.kew.export.KewExportDataSet;
024import org.kuali.rice.kew.rule.RuleBaseValues;
025import org.kuali.rice.kew.rule.RuleDelegationBo;
026import org.kuali.rice.kew.rule.RuleExtensionBo;
027import org.kuali.rice.kew.rule.RuleExtensionValue;
028import org.kuali.rice.kew.rule.RuleResponsibilityBo;
029import org.kuali.rice.kew.rule.web.WebRuleUtils;
030import org.kuali.rice.kew.service.KEWServiceLocator;
031import org.kuali.rice.test.BaselineTestCase;
032import org.kuali.rice.test.ClearDatabaseLifecycle;
033
034import java.io.BufferedInputStream;
035import java.io.ByteArrayInputStream;
036import java.util.ArrayList;
037import java.util.Calendar;
038import java.util.HashSet;
039import java.util.Iterator;
040import java.util.List;
041import java.util.Set;
042
043import static org.junit.Assert.*;
044
045
046/**
047 * Tests the RuleXmlExporter by importing XML, exporting it, and then re-importing the xml.<br><br>
048 *
049 * NOTE: It's important to note that the success of this test depends on all of the Rules in any
050 * XML having unique descriptions as this is the only way for the test to identify
051 * the rules from the original imported XML and the XML imported from the export.
052 *
053 * @author Kuali Rice Team (rice.collab@kuali.org)
054 */
055@BaselineTestCase.BaselineMode(BaselineTestCase.Mode.NONE)
056public class RuleXmlExporterTest extends XmlExporterTestCase {
057
058        @Test public void testExport() throws Exception {
059        ClasspathOrFileResourceLoader rl = new ClasspathOrFileResourceLoader();
060        loadXmlFile("org/kuali/rice/kew/actions/ActionsConfig.xml");
061        loadXmlStream(rl.getResource("classpath:org/kuali/rice/kew/batch/data/RuleAttributeContent.xml").getInputStream());
062        loadXmlStream(rl.getResource("classpath:org/kuali/rice/kew/batch/data/RuleTemplateContent.xml").getInputStream());
063        loadXmlStream(rl.getResource("classpath:org/kuali/rice/kew/batch/data/DocumentTypeContent.xml").getInputStream());
064        loadXmlStream(rl.getResource("classpath:org/kuali/rice/kew/batch/data/RuleContent.xml").getInputStream());
065        assertRuleBaseValuesStateIndependence();
066        assertExport();
067    }
068
069    /**
070     * Note that the assertion here will fail if you have multiple rules with the same description.
071     */
072    protected void assertExport() throws Exception {
073        // export all existing rules and their dependencies (document types, rule templates, rule attributes)
074        List oldRules = KEWServiceLocator.getRuleService().fetchAllRules(true);
075        assertAllRulesHaveUniqueNames(oldRules);
076        List oldRuleDelegations = KEWServiceLocator.getRuleDelegationService().findAllCurrentRuleDelegations();
077        assertAllRuleDelegationsHaveUniqueNames(oldRuleDelegations);
078
079        KewExportDataSet dataSet = new KewExportDataSet();
080        dataSet.getRules().addAll(oldRules);
081        dataSet.getRuleDelegations().addAll(oldRuleDelegations);
082        dataSet.getDocumentTypes().addAll(KEWServiceLocator.getDocumentTypeService().findAllCurrent());
083        dataSet.getRuleTemplates().addAll(KEWServiceLocator.getRuleTemplateService().findAll());
084        dataSet.getRuleAttributes().addAll(KEWServiceLocator.getRuleAttributeService().findAll());
085        byte[] xmlBytes = CoreApiServiceLocator.getXmlExporterService().export(dataSet.createExportDataSet());
086        assertTrue("XML should be non empty.", xmlBytes != null && xmlBytes.length > 0);
087        
088        // now clear the tables
089        ClearDatabaseLifecycle clearLifeCycle = new ClearDatabaseLifecycle();
090        clearLifeCycle.getTablesToClear().add("KREW_RULE_T");
091        clearLifeCycle.getTablesToClear().add("KREW_RULE_RSP_T");
092        clearLifeCycle.getTablesToClear().add("KREW_DLGN_RSP_T");
093        clearLifeCycle.getTablesToClear().add("KREW_RULE_ATTR_T");
094        clearLifeCycle.getTablesToClear().add("KREW_RULE_TMPL_T");
095        clearLifeCycle.getTablesToClear().add("KREW_DOC_TYP_T");
096        clearLifeCycle.start();
097        new ClearCacheLifecycle().stop();
098
099        // import the exported xml
100        loadXmlStream(new BufferedInputStream(new ByteArrayInputStream(xmlBytes)));
101
102        List newRules = KEWServiceLocator.getRuleService().fetchAllRules(true);
103        assertEquals("Should have same number of old and new Rules.", oldRules.size(), newRules.size());
104        for (Iterator iterator = oldRules.iterator(); iterator.hasNext();) {
105            RuleBaseValues oldRule = (RuleBaseValues) iterator.next();
106            boolean foundRule = false;
107            for (Iterator iterator2 = newRules.iterator(); iterator2.hasNext();) {
108                RuleBaseValues newRule = (RuleBaseValues) iterator2.next();
109                if (oldRule.getDescription().equals(newRule.getDescription())) {
110                    assertRuleExport(oldRule, newRule);
111                    foundRule = true;
112                }
113            }
114            assertTrue("Could not locate the new rule for description " + oldRule.getDescription(), foundRule);
115        }
116        
117        List newRuleDelegations = KEWServiceLocator.getRuleDelegationService().findAllCurrentRuleDelegations();
118        assertDelegations(oldRuleDelegations, newRuleDelegations);
119    }
120    
121    /**
122     * verifies that rule exports are the same regardless of whether the rule is ready for render, or
123     * for persistance.
124     */
125    protected void assertRuleBaseValuesStateIndependence() throws Exception {
126        for (Object o : KEWServiceLocator.getRuleService().fetchAllRules(true)) {
127                RuleBaseValues rule = (RuleBaseValues)o;
128                KewExportDataSet dataSet = new KewExportDataSet();
129                dataSet.getRules().add(rule);
130                
131                // first, do a conversion in the just-loaded state:
132                byte[] saveXmlBytes = CoreApiServiceLocator.getXmlExporterService().export(dataSet.createExportDataSet());
133                String saveStr = new String(saveXmlBytes);
134                
135                // now, convert for render:
136                WebRuleUtils.populateRuleMaintenanceFields(rule);
137                
138                // do another conversion in the ready-for-render state:
139                byte[] loadXmlBytes = CoreApiServiceLocator.getXmlExporterService().export(dataSet.createExportDataSet());
140                String loadStr = new String(loadXmlBytes);
141
142            // FIXME: currently failing due to:
143            // * WebRuleUtils.populateRuleMaintenanceFields clears rule extensions
144            // * RuleXmlExporter detects missing extensions and re-adds them: but in a different order...
145
146                // check that the results are identical:
147                assertTrue("The load/render state of the RuleBaseValues shouldn't effect the export: \n" + 
148                                saveStr + "\n\n != \n\n" + loadStr, 
149                                StringUtils.equals(saveStr, loadStr));
150        }
151    }
152
153    private void assertRuleExport(RuleBaseValues oldRule, RuleBaseValues newRule) {
154        assertFalse("Ids should be different.", oldRule.getId().equals(newRule.getId()));
155        assertEquals(oldRule.isActive(), newRule.isActive());
156        assertEquals(DateUtils.round(oldRule.getActivationDate(), Calendar.DATE), DateUtils.round(newRule.getActivationDate(), Calendar.DATE));
157        assertEquals(oldRule.getName(), newRule.getName());
158        assertEquals(oldRule.getCurrentInd(), newRule.getCurrentInd());
159        assertEquals(oldRule.getDeactivationDate(), newRule.getDeactivationDate());
160        assertEquals(oldRule.getDelegateRule(), newRule.getDelegateRule());
161        assertEquals(oldRule.getDescription(), newRule.getDescription());
162        assertEquals(oldRule.getDocTypeName(), newRule.getDocTypeName());
163        
164        if (oldRule.getFromDateValue() == null) {
165                assertNull(newRule.getFromDateValue());
166        } else {
167                assertEquals(DateUtils.round(oldRule.getFromDateValue(), Calendar.DATE), DateUtils.round(newRule.getFromDateValue(), Calendar.DATE));
168        }
169        if (oldRule.getToDateValue() == null) {
170                assertNull(newRule.getToDateValue());
171        } else {
172                assertEquals(DateUtils.round(oldRule.getToDateValue(), Calendar.DATE), DateUtils.round(newRule.getToDateValue(), Calendar.DATE));
173        }
174        assertEquals(oldRule.getFromDateString(),newRule.getFromDateString() );
175        assertEquals(oldRule.getToDateString(),newRule.getToDateString() );
176        
177        assertEquals(oldRule.isForceAction(), newRule.isForceAction());
178        
179        if(!oldRule.getDelegateRule().booleanValue())
180                assertEquals(oldRule.getPreviousRuleId(), newRule.getPreviousRuleId());
181        
182        assertEquals(oldRule.getDocumentId(), newRule.getDocumentId());
183        
184        if (oldRule.getRuleTemplate() == null) {
185            assertNull(newRule.getRuleTemplate());
186        } else {
187            assertEquals(oldRule.getRuleTemplate().getName(), newRule.getRuleTemplate().getName());
188        }
189        if (oldRule.getRuleExpressionDef() == null) {
190            assertNull(newRule.getRuleExpressionDef());
191        } else {
192            assertEquals(oldRule.getRuleExpressionDef().getExpression(), newRule.getRuleExpressionDef().getExpression());
193            assertEquals(oldRule.getRuleExpressionDef().getType(), newRule.getRuleExpressionDef().getType());
194        }
195        if(!oldRule.getDelegateRule().booleanValue())
196                assertEquals(oldRule.getVersionNbr(), newRule.getVersionNbr());
197
198        assertRuleExtensions(oldRule.getRuleExtensions(), newRule.getRuleExtensions());
199        assertResponsibilities(oldRule.getRuleResponsibilities(), newRule.getRuleResponsibilities());
200
201
202    }
203
204    private void assertRuleExtensions(List oldRuleExtensions, List newRuleExtensions) {
205        assertEquals(oldRuleExtensions.size(), newRuleExtensions.size());
206        for (Iterator iterator = oldRuleExtensions.iterator(); iterator.hasNext();) {
207            RuleExtensionBo oldExtension = (RuleExtensionBo) iterator.next();
208            boolean foundExtension = false;
209            for (Iterator iterator2 = newRuleExtensions.iterator(); iterator2.hasNext();) {
210                RuleExtensionBo newExtension = (RuleExtensionBo) iterator2.next();
211                if (oldExtension.getRuleTemplateAttribute().getRuleAttribute().getName().equals(newExtension.getRuleTemplateAttribute().getRuleAttribute().getName()) &&
212                        oldExtension.getRuleTemplateAttribute().getRuleTemplate().getName().equals(newExtension.getRuleTemplateAttribute().getRuleTemplate().getName())) {
213                        assertExtensionValues(oldExtension.getExtensionValues(), newExtension.getExtensionValues());
214                        foundExtension = true;
215                        break;
216                }
217            }
218            assertTrue("Could not locate rule extension.", foundExtension);
219        }
220    }
221
222    private void assertExtensionValues(List oldExtensionValues, List newExtensionValues) {
223        assertEquals(oldExtensionValues.size(), newExtensionValues.size());
224        for (Iterator iterator = oldExtensionValues.iterator(); iterator.hasNext();) {
225            RuleExtensionValue oldValue = (RuleExtensionValue) iterator.next();
226            boolean foundValue = false;
227            for (Iterator iterator2 = oldExtensionValues.iterator(); iterator2.hasNext();) {
228                RuleExtensionValue newValue = (RuleExtensionValue) iterator2.next();
229                if (oldValue.getKey().equals(newValue.getKey())) {
230                    assertEquals(oldValue.getValue(), newValue.getValue());
231                    foundValue = true;
232                    break;
233                }
234            }
235            assertTrue("Could not locate extension value.", foundValue);
236        }
237    }
238
239    private void assertResponsibilities(List oldResps, List newResps) {
240        assertEquals(oldResps.size(), newResps.size());
241        for (Iterator iterator = oldResps.iterator(); iterator.hasNext();) {
242            RuleResponsibilityBo oldResp = (RuleResponsibilityBo) iterator.next();
243            boolean foundResp = false;
244            for (Iterator iterator2 = newResps.iterator(); iterator2.hasNext();) {
245                RuleResponsibilityBo newResp = (RuleResponsibilityBo) iterator2.next();
246                if (oldResp.getRuleResponsibilityName().equals(newResp.getRuleResponsibilityName())) {
247                    assertEquals(oldResp.getActionRequestedCd(), newResp.getActionRequestedCd());
248                    assertEquals(oldResp.getApprovePolicy(), newResp.getApprovePolicy());
249                    assertEquals(oldResp.getResolvedRoleName(), newResp.getResolvedRoleName());
250                    assertEquals(oldResp.getRole(), newResp.getRole());
251                    assertEquals(oldResp.getRuleResponsibilityType(), newResp.getRuleResponsibilityType());
252                    assertEquals(oldResp.getPriority(), newResp.getPriority());
253                    foundResp = true;
254                    break;
255                }
256            }
257            assertTrue("Could not locate responsibility "+oldResp.getRuleResponsibilityName()+" on rule "+oldResp.getRuleBaseValues().getDescription(), foundResp);
258        }
259    }
260
261    private void assertDelegations(List oldDelegations, List newDelegations) {
262        assertEquals(oldDelegations.size(), newDelegations.size());
263        for (Iterator iterator = oldDelegations.iterator(); iterator.hasNext();) {
264            RuleDelegationBo oldDelegation = (RuleDelegationBo) iterator.next();
265            boolean foundDelegation = false;
266            for (Iterator iterator2 = newDelegations.iterator(); iterator2.hasNext();) {
267                RuleDelegationBo newDelegation = (RuleDelegationBo) iterator2.next();
268                if (oldDelegation.getDelegationRule().getName().equals(newDelegation.getDelegationRule().getName())) {
269                    assertEquals(oldDelegation.getDelegationType(), newDelegation.getDelegationType());
270                    assertFalse(oldDelegation.getResponsibilityId().equals(newDelegation.getResponsibilityId()));
271                    assertRuleExport(oldDelegation.getDelegationRule(), newDelegation.getDelegationRule());
272                    foundDelegation = true;
273                    break;
274                }
275            }
276            assertTrue("Could not locate delegation.", foundDelegation);
277        }
278    }
279
280    private void assertAllRulesHaveUniqueNames(List rules) throws Exception {
281        Set<String> ruleDescriptions = new HashSet<String>();
282        for (Iterator iterator = rules.iterator(); iterator.hasNext();) {
283                        RuleBaseValues rule = (RuleBaseValues) iterator.next();
284                        assertFalse("Found 2 rules with the same description '" + rule.getDescription() + "'.  " +
285                                        "In order for this test to work, all rules in the configuration files must have unique descriptions.",
286                                        ruleDescriptions.contains(rule.getDescription()));
287                        ruleDescriptions.add(rule.getDescription());
288                }
289    }
290    
291    private void assertAllRuleDelegationsHaveUniqueNames(List<RuleDelegationBo> ruleDelegations) throws Exception {
292        List<RuleBaseValues> rules = new ArrayList<RuleBaseValues>();
293        for (RuleDelegationBo ruleDelegation : ruleDelegations) {
294                rules.add(ruleDelegation.getDelegationRule());
295        }
296        assertAllRulesHaveUniqueNames(rules);
297    }
298
299}