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.actionrequest.service.impl;
017
018import static org.junit.Assert.assertEquals;
019import static org.junit.Assert.assertFalse;
020import static org.junit.Assert.assertNotNull;
021import static org.junit.Assert.assertTrue;
022
023import java.util.ArrayList;
024import java.util.List;
025
026import mocks.MockDocumentRefreshQueueImpl;
027import mocks.MockEmailNotificationService;
028
029import org.apache.commons.collections.CollectionUtils;
030import org.apache.commons.lang.StringUtils;
031import org.junit.Test;
032import org.kuali.rice.core.api.config.CoreConfigHelper;
033import org.kuali.rice.core.api.delegation.DelegationType;
034import org.kuali.rice.kew.actionitem.ActionItem;
035import org.kuali.rice.kew.actionrequest.ActionRequestValue;
036import org.kuali.rice.kew.api.WorkflowDocument;
037import org.kuali.rice.kew.api.WorkflowDocumentFactory;
038import org.kuali.rice.kew.api.action.ActionRequest;
039import org.kuali.rice.kew.engine.node.RouteNodeInstance;
040import org.kuali.rice.kew.messaging.MessageServiceNames;
041import org.kuali.rice.kew.rule.RuleBaseValues;
042import org.kuali.rice.kew.rule.RuleDelegationBo;
043import org.kuali.rice.kew.rule.RuleResponsibilityBo;
044import org.kuali.rice.kew.rule.bo.RuleTemplateBo;
045import org.kuali.rice.kew.service.KEWServiceLocator;
046import org.kuali.rice.kew.test.KEWTestCase;
047import org.kuali.rice.kew.api.KewApiConstants;
048
049/**
050 * This is a description of what this class does - gilesp don't forget to fill this in.
051 * 
052 * @author Kuali Rice Team (rice.collab@kuali.org)
053 * 
054 */
055public class NotificationSuppressionTest extends KEWTestCase {
056
057    private static final String TEST_RULE_TEMPLATE = "WorkflowDocumentTemplate";
058
059    protected void loadTestData() throws Exception {
060        loadXmlFile("NotificationSuppressionTestConfig.xml");
061    }
062
063    private static final String TEST_DOC_TYPE = "NotificationSuppressionTestDocType";
064
065    /**
066     * Tests that the notification suppression keys work equivalently for ActionRequestDTO and
067     * ActionRequestValue
068     * 
069     * @throws Exception
070     */
071    @Test
072    public void testNotificationSuppressionKeys() throws Exception {
073        WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"),
074                TEST_DOC_TYPE);
075        document.route("");
076        List<ActionRequest> requests = document.getRootActionRequests();
077        assertTrue("there must be ActionRequestDTOs to test!", requests != null && requests.size() > 0);
078
079        NotificationSuppression notificationSuppression = new NotificationSuppression();
080
081        boolean atLeastOne = false;
082        for (ActionRequest reqDTO : requests)
083            if (reqDTO.getParentActionRequestId() == null) {
084                atLeastOne = true;
085                ActionRequestValue reqVal = ActionRequestValue.from(reqDTO);
086                assertTrue(CollectionUtils.isEqualCollection(
087                        notificationSuppression.getSuppressNotifyNodeStateKeys(reqVal),
088                        notificationSuppression.getSuppressNotifyNodeStateKeys(reqDTO)));
089
090                // test that changing the responsible party changes the key
091
092                ActionRequest.Builder builder = ActionRequest.Builder.create(reqDTO);
093                builder.setPrincipalId("asdf");
094                reqDTO = builder.build();
095                assertFalse(CollectionUtils.isEqualCollection(
096                        notificationSuppression.getSuppressNotifyNodeStateKeys(reqVal),
097                        notificationSuppression.getSuppressNotifyNodeStateKeys(reqDTO)));
098            }
099        assertTrue(atLeastOne);
100
101    }
102
103    /**
104     * test that ActionItemS are filtered when a corresponding notification suppression NodeState is
105     * present in the related RouteNodeInstance
106     * 
107     * @throws Exception
108     */
109    @Test
110    public void testActionItemFiltering() throws Exception {
111        WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"),
112                TEST_DOC_TYPE);
113        document.route("");
114        List<ActionRequest> requests = document.getRootActionRequests();
115        assertTrue("there must be ActionRequestDTOs to test!", requests != null && requests.size() > 0);
116
117        NotificationSuppression notificationSuppression = new NotificationSuppression();
118
119        boolean atLeastOne = false;
120        for (ActionRequest reqDTO : requests) {
121            if (reqDTO.getParentActionRequestId() == null) {
122                atLeastOne = true;
123
124                ActionRequestValue reqVal = ActionRequestValue.from(reqDTO);
125
126                List<ActionItem> actionItems = new ArrayList<ActionItem>();
127                actionItems.add(KEWServiceLocator.getActionListService().createActionItemForActionRequest(reqVal));
128
129                RouteNodeInstance routeNodeInstance = new RouteNodeInstance();
130
131                // if there is no notification suppression state, nothing should be filtered
132                int actionItemsCount = actionItems.size();
133                notificationSuppression.filterNotificationSuppressedActionItems(actionItems, routeNodeInstance);
134                assertTrue(actionItemsCount == actionItems.size());
135
136                // if there is a suppression state for this ActionRequestValue, the ActionItem(s) should be filtered
137                notificationSuppression.addNotificationSuppression(routeNodeInstance, reqVal);
138                notificationSuppression.filterNotificationSuppressedActionItems(actionItems, routeNodeInstance);
139                assertTrue(actionItems.size() == 0);
140            }
141        }
142        assertTrue(atLeastOne);
143
144    }
145
146    /**
147     * This method tests email suppression soup to nuts by routing / requeueing documents and
148     * meddling with the responsible parties.
149     * 
150     * @throws Exception
151     */
152    @Test
153    public void testSuppression() throws Exception {
154        WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"),
155                TEST_DOC_TYPE);
156        document.route("");
157
158        assertTrue("the responsible party should have been notified",
159                1 == getMockEmailService().immediateReminderEmailsSent("user1", document.getDocumentId(),
160                        KewApiConstants.ACTION_REQUEST_COMPLETE_REQ));
161
162        getMockEmailService().resetReminderCounts();
163
164        List<RuleBaseValues> existingRules =
165                KEWServiceLocator.getRuleService().fetchAllCurrentRulesForTemplateDocCombination(TEST_RULE_TEMPLATE,
166                        TEST_DOC_TYPE);
167        assertNotNull(existingRules);
168        assertEquals(1, existingRules.size());
169
170        RuleBaseValues originalRule = existingRules.get(0);
171        assertTrue("Original rule should be current.", originalRule.getCurrentInd());
172
173        List<RuleResponsibilityBo> originalResps = originalRule.getRuleResponsibilities();
174        assertEquals(1, originalResps.size());
175
176        RuleResponsibilityBo originalResp = originalResps.get(0);
177
178        RuleTemplateBo ruleTemplate = KEWServiceLocator.getRuleTemplateService().findByRuleTemplateName(
179                TEST_RULE_TEMPLATE);
180        assertNotNull(ruleTemplate);
181        assertNotNull(ruleTemplate.getId());
182        assertFalse(StringUtils.isEmpty(ruleTemplate.getName()));
183
184        // save a new rule delegation
185        RuleDelegationBo ruleDelegation = new RuleDelegationBo();
186        ruleDelegation.setResponsibilityId(originalResp.getResponsibilityId());
187        ruleDelegation.setDelegationType(DelegationType.PRIMARY);
188        RuleBaseValues rule = new RuleBaseValues();
189        ruleDelegation.setDelegationRule(rule);
190        rule.setDelegateRule(true);
191        rule.setActive(true);
192        rule.setCurrentInd(true);
193        rule.setDocTypeName(originalRule.getDocTypeName());
194        rule.setRuleTemplateId(ruleTemplate.getDelegationTemplateId());
195        rule.setRuleTemplate(ruleTemplate);
196        rule.setDescription("Description of this delegate rule");
197        rule.setForceAction(true);
198        RuleResponsibilityBo delegationResponsibility = new RuleResponsibilityBo();
199        rule.getRuleResponsibilities().add(delegationResponsibility);
200        delegationResponsibility.setRuleBaseValues(rule);
201        delegationResponsibility.setRuleResponsibilityName("user2");
202        delegationResponsibility.setRuleResponsibilityType(KewApiConstants.RULE_RESPONSIBILITY_WORKFLOW_ID);
203
204        // reset mock service test data
205        getMockEmailService().resetReminderCounts();
206        MockDocumentRefreshQueueImpl.clearRequeuedDocumentIds();
207
208        // this *SHOULD* requeue
209        KEWServiceLocator.getRuleService().saveRuleDelegation(ruleDelegation, true);
210
211        assertTrue("document should have been requeued",
212                MockDocumentRefreshQueueImpl.getRequeuedDocumentIds().contains(document.getDocumentId()));
213
214        assertTrue("should have notified user2",
215                1 == getMockEmailService().immediateReminderEmailsSent("user2", document.getDocumentId(),
216                        KewApiConstants.ACTION_REQUEST_COMPLETE_REQ));
217        assertTrue("the responsible party that is delegating should not be notified",
218                0 == getMockEmailService().immediateReminderEmailsSent("user1", document.getDocumentId(),
219                        KewApiConstants.ACTION_REQUEST_COMPLETE_REQ));
220
221        getMockEmailService().resetReminderCounts();
222
223        // now if we requeue, nobody should get notified
224        MockDocumentRefreshQueueImpl.clearRequeuedDocumentIds();
225        String applicationId = KEWServiceLocator.getRouteHeaderService().getApplicationIdByDocumentId(
226                document.getDocumentId());
227        MessageServiceNames.getDocumentRequeuerService(
228                (applicationId != null) ? applicationId : CoreConfigHelper.getApplicationId(),
229                document.getDocumentId(), 0).refreshDocument(document.getDocumentId());
230
231        assertTrue("nobody should have been notified",
232                0 == getMockEmailService().immediateReminderEmailsSent("user2", document.getDocumentId(),
233                        KewApiConstants.ACTION_REQUEST_COMPLETE_REQ));
234        assertTrue("nobody should have been notified",
235                0 == getMockEmailService().immediateReminderEmailsSent("user1", document.getDocumentId(),
236                        KewApiConstants.ACTION_REQUEST_COMPLETE_REQ));
237
238        getMockEmailService().resetReminderCounts();
239    }
240
241    private MockEmailNotificationService getMockEmailService() {
242        return (MockEmailNotificationService) KEWServiceLocator.getActionListEmailService();
243    }
244}