001/**
002 * Copyright 2004-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.hr.time.roles.web;
017
018import com.gargoylesoftware.htmlunit.html.DomElement;
019import com.gargoylesoftware.htmlunit.html.HtmlForm;
020import com.gargoylesoftware.htmlunit.html.HtmlPage;
021import org.apache.commons.collections.CollectionUtils;
022import org.apache.log4j.Logger;
023import org.joda.time.DateTime;
024import org.joda.time.DateTimeZone;
025import org.json.simple.JSONArray;
026import org.json.simple.JSONObject;
027import org.json.simple.JSONValue;
028import org.junit.Assert;
029import org.junit.Test;
030import org.kuali.hr.time.util.TimeDetailTestUtils;
031import org.kuali.hr.time.workflow.TimesheetWebTestBase;
032import org.kuali.hr.util.HtmlUnitUtil;
033import org.kuali.kpme.core.FunctionalTest;
034import org.kuali.kpme.core.api.assignment.Assignment;
035import org.kuali.kpme.core.api.calendar.entry.CalendarEntry;
036import org.kuali.kpme.core.api.earncode.EarnCode;
037import org.kuali.kpme.core.role.KPMERole;
038import org.kuali.kpme.core.service.HrServiceLocator;
039import org.kuali.kpme.core.util.HrContext;
040import org.kuali.kpme.core.util.TKUtils;
041import org.kuali.kpme.tklm.time.detail.web.TimeDetailActionFormBase;
042import org.kuali.kpme.tklm.time.service.TkServiceLocator;
043import org.kuali.kpme.tklm.time.timesheet.TimesheetDocument;
044
045import java.util.ArrayList;
046import java.util.HashMap;
047import java.util.List;
048import java.util.Map;
049
050/**
051 * See: https://wiki.kuali.org/display/KPME/Role+Security+Grid
052 */
053@FunctionalTest
054public class RoleTimesheetWebIntegrationTest extends TimesheetWebTestBase {
055
056    private static final Logger LOG = Logger.getLogger(RoleTimesheetWebIntegrationTest.class);
057
058    // Non Time Entry users (for this test) who have some access to 'fred's'
059    // Time Sheet.
060    private List<String> VALID_NON_ENTRY_USERS = new ArrayList<String>() {{
061        //add fred too.
062        /*add("testuser6");*/ add("frank"); add("fran"); add("edna"); add("fred"); }};
063
064    // Users with incorrect Department or Work Area for Time Sheet privilege.
065    private List<String> INVALID_NON_ENTRY_USERS = new ArrayList<String>(){{
066        add("testuser1"); add("testuser2"); add("testuser3"); add("testuser4"); }};
067
068    private TimesheetDocument fredsDocument = null;
069    DateTime asOfDate = new DateTime(2011, 3, 1, 12, 0, 0, 0, TKUtils.getSystemDateTimeZone());
070
071    @Override
072    /**
073     * This code is called before each test below - allows us to control how far
074     * into the routing process we are for any given level of testing.
075     */
076    public void setUp() throws Exception {
077        super.setUp();
078
079        String userId = "fred";
080        DateTimeZone dateTimeZone = DateTimeZone.forID(HrServiceLocator.getTimezoneService().getUserTimezone(userId));
081        
082        CalendarEntry pcd =  HrServiceLocator.getCalendarEntryService().getCurrentCalendarDates(userId, asOfDate);
083        Assert.assertNotNull("No PayCalendarDates", pcd);
084        fredsDocument = TkServiceLocator.getTimesheetService().openTimesheetDocument(userId, pcd);
085        String tdocId = fredsDocument.getDocumentId();
086
087        // Verify the non time entry logins.
088        verifyLogins(fredsDocument);
089
090        // Verify Fred, and Add Timeblocks
091        HtmlPage page = loginAndGetTimeDetailsHtmlPage(getWebClient(), userId, tdocId, true);
092        Assert.assertTrue("Calendar not loaded.", page.asText().contains("March 2011"));
093
094        HtmlForm form = page.getFormByName("TimeDetailActionForm");
095        Assert.assertNotNull(form);
096        List<Assignment> assignments = HrServiceLocator.getAssignmentService().getAssignments(userId, JAN_AS_OF_DATE.toLocalDate());
097        Assignment assignment = assignments.get(0);
098
099        List<EarnCode> earnCodes = TkServiceLocator.getTimesheetService().getEarnCodesForTime(assignment, JAN_AS_OF_DATE.toLocalDate());
100        EarnCode earnCode = earnCodes.get(0);
101        Assert.assertEquals("There should be no existing time blocks.", 0, fredsDocument.getTimeBlocks().size());
102
103        // 2. Set Timeblock Start and End time
104        // 3/02/2011 - 8:00a to 6:00pm
105        // OVT - 0 Hrs Expected
106        final DateTime start = new DateTime(2011, 3, 2, 8, 0, 0, 0, dateTimeZone);
107        final DateTime end = new DateTime(2011, 3, 2, 13, 0, 0, 0, dateTimeZone);
108
109        TimeDetailActionFormBase tdaf = TimeDetailTestUtils.buildDetailActionForm(fredsDocument, assignment, earnCode, start, end, null, false, null, true, null, null, null, null, null, null);
110        List<String> errors = TimeDetailTestUtils.setTimeBlockFormDetails(form, tdaf);
111
112        Assert.assertEquals("There should be no errors in this time detail submission", 0, errors.size());
113        page = TimeDetailTestUtils.submitTimeDetails(getWebClient(), getTimesheetDocumentUrl(tdocId), tdaf);
114        Assert.assertNotNull(page);
115        page = loginAndGetTimeDetailsHtmlPage(getWebClient(), userId, tdocId, true);
116
117        String pageAsText = page.asText();
118        DomElement element = page.getElementById("timeBlockString");
119        Assert.assertNotNull(element);
120        String elementAsText = element.asText();
121        String dataText = page.getElementById("timeBlockString").getFirstChild().getNodeValue();
122        JSONArray jsonData = (JSONArray) JSONValue.parse(dataText);
123        final JSONObject jsonDataObject = (JSONObject) jsonData.get(0);
124        Assert.assertTrue("TimeBlock Data Missing.", checkJSONValues(new JSONObject() {{ put("outer", jsonDataObject); }},
125                new ArrayList<Map<String, Object>>() {{
126                    add(new HashMap<String, Object>() {{
127                        put("earnCode", "RGN");
128                        put("hours", "5.0");
129                        put("amount", null);
130                    }});
131                }},
132                new HashMap<String, Object>() {{
133                    put("earnCode", "RGN");
134                    start.toString();
135                    put("startNoTz", start.toString("yyyy-MM-dd'T'HH:mm:ss"));
136                    put("endNoTz", end.toString("yyyy-MM-dd'T'HH:mm:ss"));
137                    put("title", "SDR1 Work Area");
138                    put("assignment", "IU-BL_30_30_30");
139                }}
140        ));
141
142        // Set freds timesheet to have updated info.
143        fredsDocument = TkServiceLocator.getTimesheetService().openTimesheetDocument(userId, pcd);
144    }
145
146    /*
147     * Tests while Timesheet is in INITIATED state.
148     */
149
150    @Test
151    public void testInitiatedTimesheetIsVisibleByAll() throws Exception {
152        // test valid users
153        for (String uid : VALID_NON_ENTRY_USERS) {
154            LOG.info("Testing visibility for " + uid);
155            HtmlPage page = loginAndGetTimeDetailsHtmlPage(getWebClient(), uid, fredsDocument.getDocumentId(), true);
156            Assert.assertTrue("Calendar not loaded.", page.asText().contains("March 2011"));
157        }
158    }
159
160    @Test
161    //@Ignore
162    public void testInitiatedTimesheetIsNotVisible() throws Exception {
163        for (String uid : INVALID_NON_ENTRY_USERS) {
164            LOG.info("Testing visibility for " + uid);
165            HtmlPage page = loginAndGetTimeDetailsHtmlPage(getWebClient(), uid, fredsDocument.getDocumentId(), false);
166            //HtmlUnitUtil.createTempFile(page, "badlogin");
167            Assert.assertTrue(uid + " should not have access" , page.asText().contains("You are not authorized to access this portion of the application."));
168        }
169    }
170
171    public void testInitiatedTimesheetEditable(String userId) throws Exception {
172        // admin, add one timeblock
173        String tdocId = fredsDocument.getDocumentId();
174        HtmlPage page = loginAndGetTimeDetailsHtmlPage(getWebClient(), userId, tdocId, true);
175        LOG.debug(page.asText());
176        //HtmlUnitUtil.createTempFile(page, "loggedin");
177        Assert.assertTrue("Calendar not loaded.", page.asText().contains("March 2011"));
178
179        HtmlForm form = page.getFormByName("TimeDetailActionForm");
180        Assert.assertNotNull(form);
181        List<Assignment> assignments = HrServiceLocator.getAssignmentService().getAssignments("fred", JAN_AS_OF_DATE.toLocalDate());
182        Assignment assignment = assignments.get(0);
183
184        List<EarnCode> earnCodes = TkServiceLocator.getTimesheetService().getEarnCodesForTime(assignment, JAN_AS_OF_DATE.toLocalDate());
185        EarnCode earnCode = earnCodes.get(0);
186
187        Assert.assertEquals("There should be one existing time block.", 1, fredsDocument.getTimeBlocks().size());
188
189
190        String targetedTimesheetUrl = getTargetedTimesheetDocumentUrl(tdocId,"fred");
191        HrContext.setTargetPrincipalId("fred");
192        page = getWebClient().getPage(targetedTimesheetUrl);
193        Assert.assertNotNull(page);
194
195        DateTimeZone dateTimeZone = DateTimeZone.forID(HrServiceLocator.getTimezoneService().getUserTimezone("fred"));
196        final DateTime start = new DateTime(2011, 3, 2, 13, 0, 0, 0, dateTimeZone);
197        final DateTime end = new DateTime(2011, 3, 2, 18, 0, 0, 0, dateTimeZone);
198        TimeDetailActionFormBase tdaf = TimeDetailTestUtils.buildDetailActionForm(fredsDocument, assignment, earnCode, start, end, null, false, null, true, null, null, null, null, null, null);
199
200        List<String> errors = TimeDetailTestUtils.setTimeBlockFormDetails(form, tdaf);
201
202        if (CollectionUtils.isNotEmpty(errors)) {
203            for (String error : errors) {
204                LOG.error(error);
205            }
206        }
207        Assert.assertEquals("There should be no errors in this time detail submission", 0, errors.size());
208
209        String submitDetailsUrl = BASE_DETAIL_URL + tdocId;
210        //The following page does not contain timeBlockString data after KPME-2959.
211        page = TimeDetailTestUtils.submitTimeDetails(getWebClient(), submitDetailsUrl, tdaf);
212        Assert.assertNotNull(page);
213        //This extra page get was needed for KPME-2959.
214        page = getWebClient().getPage(targetedTimesheetUrl);
215        HtmlUnitUtil.createTempFile(page, "initiatetest");
216        String dataText = page.getElementById("timeBlockString").getFirstChild().getNodeValue();
217        JSONArray jsonData = (JSONArray) JSONValue.parse(dataText);
218        final JSONObject jsonDataObject = (JSONObject) jsonData.get(1);
219        Assert.assertTrue("TimeBlock Data Missing.", checkJSONValues(new JSONObject() {{ put("outer", jsonDataObject); }},
220                new ArrayList<Map<String, Object>>() {{
221                    add(new HashMap<String, Object>() {{
222                        put("earnCode", "RGN");
223                        put("hours", "5.0");
224                        put("amount", null);
225                    }});
226                }},
227                new HashMap<String, Object>() {{
228                    put("earnCode", "RGN");
229                    put("startNoTz", start.toString("yyyy-MM-dd'T'HH:mm:ss"));
230                    put("endNoTz", end.toString("yyyy-MM-dd'T'HH:mm:ss"));
231                    put("title", "SDR1 Work Area");
232                    put("assignment", "IU-BL_30_30_30");
233                }}
234        ));
235    }
236
237    public void testInitiatedTimesheetNotEditable(String userId) throws Exception {
238        // admin, add one timeblock
239        String tdocId = fredsDocument.getDocumentId();
240        HtmlPage page = loginAndGetTimeDetailsHtmlPage(getWebClient(), userId, tdocId, true);
241        //HtmlUnitUtil.createTempFile(page, "loggedin");
242        Assert.assertTrue("Calendar not loaded.", page.asText().contains("March 2011"));
243
244        HtmlForm form = page.getFormByName("TimeDetailActionForm");
245        Assert.assertNotNull(form);
246        List<Assignment> assignments = HrServiceLocator.getAssignmentService().getAssignments("fred", JAN_AS_OF_DATE.toLocalDate());
247        Assignment assignment = assignments.get(0);
248
249        List<EarnCode> earnCodes = TkServiceLocator.getTimesheetService().getEarnCodesForTime(assignment, JAN_AS_OF_DATE.toLocalDate());
250        EarnCode earnCode = earnCodes.get(0);
251
252        Assert.assertEquals("There should be one existing time block.", 1, fredsDocument.getTimeBlocks().size());
253        HrContext.setTargetPrincipalId("fred");
254        DateTimeZone dateTimeZone = DateTimeZone.forID(HrServiceLocator.getTimezoneService().getUserTimezone("fred"));
255        DateTime start = new DateTime(2011, 3, 4, 8, 0, 0, 0, dateTimeZone);
256        DateTime end = new DateTime(2011, 3, 4, 13, 0, 0, 0, dateTimeZone);
257        TimeDetailActionFormBase tdaf = TimeDetailTestUtils.buildDetailActionForm(fredsDocument, assignment, earnCode, start, end, null, false, null, true, null, null, null, null, null, null);
258        List<String> errors = TimeDetailTestUtils.setTimeBlockFormDetails(form, tdaf);
259        if (CollectionUtils.isNotEmpty(errors)) {
260            for (String error : errors) {
261                LOG.error(error);
262            }
263        }
264        KPMERole[] roleNames = KPMERole.values();
265        Assert.assertEquals("There should be no errors in this time detail submission", 0, errors.size());
266        page = TimeDetailTestUtils.submitTimeDetails(getWebClient(), userId, getTimesheetDocumentUrl(tdocId), tdaf);
267        Assert.assertNotNull(page);
268        HtmlUnitUtil.createTempFile(page, "aftertdadd");
269        Assert.assertTrue("Should not have access", page.asText().contains("You are not authorized to access this portion of the application."));
270    }
271
272    @Test
273    public void testInitiatedTimesheetIsEditableByAdmin() throws Exception {
274        testInitiatedTimesheetEditable("admin");
275    }
276
277    @Test
278    public void testInitiatedTimesheetIsEditableByApprover() throws Exception {
279        testInitiatedTimesheetEditable("fran");
280    }
281
282    @Test
283    public void testInitiatedTimesheetIsEditableByReviewer() throws Exception {
284        testInitiatedTimesheetEditable("frank");
285    }
286
287    @Test
288    public void testInitiatedTimesheetIs_NOT_EditableByViewOnly() throws Exception {
289        testInitiatedTimesheetNotEditable("edna");
290    }
291
292    @Test
293    public void testInitiatedTimesheetIs_NOT_EditableByDeptAdmin() throws Exception {
294        testInitiatedTimesheetNotEditable("testuser6");
295    }
296
297
298    @Test
299    public void testInitiatedTimesheetSubmitUser() throws Exception {
300        // User,
301        // Check for submit button.
302        // Click Button
303    }
304
305    @Test
306    public void testInitiatedTimesheetSubmitAdmin() throws Exception {
307        // Admin
308        // Check for submit button.
309        // Click Button
310    }
311
312    @Test
313    public void testInitiatedTimesheetSubmitApprover() throws Exception {
314        // Approver
315        // Check for submit button.
316        // Click Button
317    }
318
319
320    @Test
321    public void testInitiatedTimesheetIs_NOT_SubmittableByUsers() throws Exception {
322        // DeptAdmin, View Only, Reviewer
323        // Check that submit button is not present.
324    }
325
326    /*
327     * Test for ENROUTE state.
328     */
329
330    @Test
331    public void testEnrouteTimesheetIsVisibleByAll() throws Exception {
332        // test valid users
333    }
334
335    @Test
336    public void testEnrouteTimesheetIsNotVisible() throws Exception {
337        // make sure invalid users do not have access
338    }
339
340    @Test
341    public void testEnrouteTimesheetIsEditableByAdmin() throws Exception {
342        // admin, add one timeblock
343    }
344
345    @Test
346    public void testEnrouteTimesheetIsEditableByApprover() throws Exception {
347        // approver, add one timeblock
348    }
349
350    @Test
351    public void testEnrouteTimesheetIsEditableByReviewer() throws Exception {
352        // reviewer add one timeblock.
353    }
354
355    @Test
356    public void testEnrouteTimesheetIs_NOT_EditableByViewOnly() throws Exception {
357    }
358
359    @Test
360    public void testEnrouteTimesheetIs_NOT_EditableByDeptAdmin() throws Exception {
361    }
362
363
364    @Test
365    public void testEnrouteTimesheet_NOT_Approvable() throws Exception {
366        // User, Reviewer, View Only, Dept Admin
367        // Check for approve button
368    }
369
370    @Test
371    public void testEnrouteTimesheetApproveAdmin() throws Exception {
372        // Admin
373        // Check for approve button.
374        // Click Button
375    }
376
377    @Test
378    public void testEnrouteTimesheetApproveApprover() throws Exception {
379        // Approver
380        // Check for approve button.
381        // Click Button
382    }
383
384    @Test
385    public void testEnrouteTimesheetIs_NOT_SubmittableByUsers() throws Exception {
386        // DeptAdmin, View Only, Reviewer
387        // Check that submit button is not present.
388    }
389
390
391    /*
392     * Final State
393     */
394
395    @Test
396    public void testFinalTimesheetIsVisibleByAll() throws Exception {
397        // test valid users
398    }
399
400    @Test
401    public void testFinalTimesheetIsNotVisible() throws Exception {
402        // make sure invalid users do not have access
403    }
404
405    @Test
406    public void testFinalTimesheetIsNotEditable() throws Exception {
407        // by everyone but admin
408    }
409
410    @Test
411    public void testFinalTimesheetIsAdminEditable() throws Exception {
412        // admin, add timeblock.
413    }
414
415    /**
416     * Verifies that each admin/approver/reviewer login is active for this test.
417     */
418    private void verifyLogins(TimesheetDocument tdoc) throws Exception {
419        for (String userId : VALID_NON_ENTRY_USERS) {
420            String tdocId = tdoc.getDocumentId();
421            HtmlPage page = loginAndGetTimeDetailsHtmlPage(getWebClient(), userId, tdocId, true);
422            Assert.assertTrue("Calendar not loaded.", page.asText().contains("March 2011"));
423        }
424    }
425
426}