001    /**
002     * Copyright 2004-2012 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.hr.time.clock.web;
017    
018    import java.math.BigDecimal;
019    import java.sql.Timestamp;
020    import java.util.ArrayList;
021    import java.util.Collection;
022    import java.util.Collections;
023    import java.util.Iterator;
024    import java.util.List;
025    
026    import org.joda.time.DateTime;
027    import org.junit.Assert;
028    import org.junit.Ignore;
029    import org.junit.Test;
030    import org.kuali.hr.test.KPMETestCase;
031    import org.kuali.hr.time.clocklog.ClockLog;
032    import org.kuali.hr.time.graceperiod.rule.GracePeriodRule;
033    import org.kuali.hr.time.service.base.TkServiceLocator;
034    import org.kuali.hr.time.test.HtmlUnitUtil;
035    import org.kuali.hr.time.test.TkTestConstants;
036    import org.kuali.hr.time.timeblock.TimeBlock;
037    import org.kuali.hr.time.timeblock.TimeHourDetail;
038    import org.kuali.hr.time.timesheet.TimesheetDocument;
039    import org.kuali.hr.time.util.TKUtils;
040    import org.kuali.hr.time.util.TkConstants;
041    import org.kuali.hr.time.workflow.TimesheetDocumentHeader;
042    import org.kuali.rice.krad.service.KRADServiceLocator;
043    
044    import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
045    import com.gargoylesoftware.htmlunit.WebClient;
046    import com.gargoylesoftware.htmlunit.html.HtmlElement;
047    import com.gargoylesoftware.htmlunit.html.HtmlPage;
048    
049    
050    public class ClockWebTest extends KPMETestCase {
051    
052        private String tbId;
053    
054        public Long maxDocumentId() {
055            Collection aCol = KRADServiceLocator.getBusinessObjectService().findAll(TimesheetDocumentHeader.class);
056            Long maxId = new Long(-1);
057            Iterator<TimesheetDocumentHeader> itr = aCol.iterator();
058            while (itr.hasNext()) {
059                TimesheetDocumentHeader tdh = itr.next();
060                Long temp = new Long(tdh.getDocumentId());
061                if (temp > maxId) {
062                    maxId = temp;
063                }
064            }
065            return maxId;
066        }
067    
068        public Long maxTimeBlockId() {
069            Collection aCol = KRADServiceLocator.getBusinessObjectService().findAll(TimeBlock.class);
070            Long maxId = new Long(-1);
071            Iterator<TimeBlock> itr = aCol.iterator();
072            while (itr.hasNext()) {
073                TimeBlock tb = itr.next();
074                Long temp = new Long(tb.getTkTimeBlockId());
075                if (temp > maxId) {
076                    maxId = temp;
077                }
078            }
079            return maxId;
080        }
081    
082        public void createTB() {
083            TimeBlock timeBlock = new TimeBlock();
084            timeBlock.setUserPrincipalId("admin");
085            timeBlock.setJobNumber(2L);
086            timeBlock.setWorkArea(1234L);
087            timeBlock.setTask(1L);
088            timeBlock.setEarnCode("RGN");
089            Timestamp beginTimestamp = new Timestamp(System.currentTimeMillis());
090            timeBlock.setBeginTimestamp(beginTimestamp);
091            Timestamp endTimestamp = new Timestamp(System.currentTimeMillis());
092            timeBlock.setEndTimestamp(endTimestamp);
093            TimeHourDetail timeHourDetail = new TimeHourDetail();
094            timeHourDetail.setEarnCode("RGN");
095            timeHourDetail.setHours(new BigDecimal(2.0));
096            timeBlock.getTimeHourDetails().add(timeHourDetail);
097            timeBlock.setHours(new BigDecimal(2.0));
098            List<TimeBlock> tbList = new ArrayList<TimeBlock>();
099            String documentId = this.maxDocumentId().toString();
100            timeBlock.setDocumentId(documentId);
101            tbList.add(timeBlock);
102            TkServiceLocator.getTimeBlockService().saveTimeBlocks(tbList);
103    
104            tbId = timeBlock.getTkTimeBlockId();
105            TimesheetDocument td = TkServiceLocator.getTimesheetService().getTimesheetDocument(documentId);
106            td.setTimeBlocks(tbList);
107    
108        }
109    
110        @Ignore
111        public void testDistributeTB() throws Exception {
112            String baseUrl = TkTestConstants.Urls.CLOCK_URL;
113            HtmlPage page = HtmlUnitUtil.gotoPageAndLogin(baseUrl);
114            Assert.assertNotNull(page);
115            Assert.assertTrue("Clock Page contains Distribute Button", page.asText().contains("Distribute Time Blocks"));
116            this.createTB();
117            this.setWebClient(page.getWebClient());
118            HtmlElement element = page.getElementByName("distributeTime");
119            Assert.assertNotNull(element);
120    //              HtmlPage testPage1 = element.click();
121    //              assertTrue("Distribute Page contains Close button", testPage1.asText().contains("Close"));
122    //        assertTrue("Distribute Page contains Close button", testPage1.asText().contains("Edit"));
123    
124            // timeDistribute.jsp
125            String distributeUrl = baseUrl + "?methodToCall=distributeTimeBlocks";
126            HtmlPage page1 = HtmlUnitUtil.gotoPageAndLogin(distributeUrl);
127            Assert.assertTrue("Distribute Page contains Close button", page1.asText().contains("Close"));
128            Assert.assertTrue("Distribute Page contains Close button", page1.asText().contains("Edit"));
129    
130            element = page1.getElementByName("editTimeBlock");
131            Assert.assertNotNull(element);
132            Assert.assertTrue("Onclick attribute of Edit button contains", element.getAttribute("onclick").contains("Clock.do?methodToCall=editTimeBlock&editTimeBlockId="));
133    
134            if (tbId == null) {
135                tbId = this.maxTimeBlockId().toString();
136            }
137    
138            //editTimeBlock.jsp
139            String editUrl = baseUrl + "?methodToCall=editTimeBlock&editTimeBlockId=" + tbId;
140            HtmlPage page3 = HtmlUnitUtil.gotoPageAndLogin(editUrl);
141    
142            // editTimeBlock.jsp
143            Assert.assertTrue("Edit Time Blocks Page contains Cancel button", page3.asText().contains("Add"));
144            Assert.assertTrue("Edit Time Blocks Page contains Save button", page3.asText().contains("Save"));
145            Assert.assertTrue("Edit Time Blocks Page contains Cancel button", page3.asText().contains("Cancel"));
146    
147            element = page3.getElementByName("addTimeBlock");
148            Assert.assertNotNull(element);
149            Assert.assertTrue("Onclick attribute of Add button contains", element.getAttribute("onclick").contains("javascript: addTimeBlockRow(this.form);"));
150    
151            this.setWebClient(page3.getWebClient());
152    
153    //              HtmlPage page4 = element.click();
154    //              assertTrue("Edit Time Blocks Page contains Cancel button", page4.asText().contains("Add"));
155    
156        }
157    
158        public void setWebClient(WebClient webClient) {
159            webClient.setJavaScriptEnabled(true);
160            webClient.setThrowExceptionOnScriptError(false);
161            webClient.setAjaxController(new NicelyResynchronizingAjaxController());
162            webClient.waitForBackgroundJavaScript(10000);
163        }
164    
165        /**
166         * This test is to :
167         * 1) make sure the seconds on clockTimestamp and timestamp are preserved when there is no grace period rule.
168         * 2) the clock in / out button is correctly rendered
169         *
170         * @throws Exception
171         */
172        @Test
173        public void testClockActionWithoutGracePeriodRule() throws Exception {
174            // Make sure there is no active grace period rule
175            GracePeriodRule gpr = TkServiceLocator.getGracePeriodService().getGracePeriodRule(TKUtils.getCurrentDate());
176            if (gpr != null && gpr.isActive()) {
177                gpr.setActive(false);
178                KRADServiceLocator.getBusinessObjectService().save(gpr);
179            }
180    
181            // Clock in
182            clockIn();
183            // Make sure clock out button is rendered
184            ClockLog lastClockLog = TkServiceLocator.getClockLogService().getLastClockLog("admin");
185            // Make sure both timestamps preserve seconds
186            Assert.assertTrue("The seconds on clock timestamp should be preserved", new DateTime(lastClockLog.getClockTimestamp().getTime()).getSecondOfMinute() != 0);
187            Assert.assertTrue("The seconds on timestamp should be preserved", new DateTime(lastClockLog.getTimestamp().getTime()).getSecondOfMinute() != 0);
188    
189            // Clock out
190            clockOut();
191            // Make sure both timestamps preserve seconds
192            lastClockLog = TkServiceLocator.getClockLogService().getLastClockLog("admin");
193            Assert.assertTrue("The seconds on clock timestamp should be preserved", new DateTime(lastClockLog.getClockTimestamp().getTime()).getSecondOfMinute() != 0);
194            Assert.assertTrue("The seconds on timestamp should be preserved", new DateTime(lastClockLog.getTimestamp().getTime()).getSecondOfMinute() != 0);
195        }
196    
197        @Test
198        public void testClockActionWithGracePeriodRule() throws Exception {
199            //clean clock logs
200            KRADServiceLocator.getBusinessObjectService().deleteMatching(ClockLog.class, Collections.singletonMap("principalId", "admin"));
201            GracePeriodRule gpr = new GracePeriodRule();
202            //gpr.setTkGracePeriodRuleId("1");
203            gpr.setEffectiveDate(TKUtils.createDate(1, 1, 2010, 0, 0, 0));
204            gpr.setHourFactor(new BigDecimal(3));
205            gpr.setTimestamp(new Timestamp(System.currentTimeMillis()));
206            
207            gpr.setActive(true);
208            KRADServiceLocator.getBusinessObjectService().save(gpr);
209    
210            // Clock in
211            clockIn();
212            // Make sure clock out button is rendered
213            ClockLog lastClockLog = TkServiceLocator.getClockLogService().getLastClockLog("admin");
214            // Make sure both timestamps preserve seconds
215            Assert.assertTrue("The seconds on clock timestamp should NOT be preserved", new DateTime(lastClockLog.getClockTimestamp().getTime()).getSecondOfMinute() == 0);
216            Assert.assertTrue("The seconds on timestamp should be preserved", new DateTime(lastClockLog.getTimestamp().getTime()).getSecondOfMinute() != 0);
217    
218            // Clock out
219            clockOut();
220            // Make sure both timestamps preserve seconds
221            lastClockLog = TkServiceLocator.getClockLogService().getLastClockLog("admin");
222            Assert.assertTrue("The seconds on clock timestamp should NOT be preserved", new DateTime(lastClockLog.getClockTimestamp().getTime()).getSecondOfMinute() == 0);
223            Assert.assertTrue("The seconds on timestamp should be preserved", new DateTime(lastClockLog.getTimestamp().getTime()).getSecondOfMinute() != 0);
224    
225    
226        }
227    
228        private HtmlPage clockIn() throws Exception {
229    
230            // Clock in
231            HtmlPage page = clockAction(TkConstants.CLOCK_IN);
232    
233            // Make sure clock in button is rendered
234            HtmlUnitUtil.createTempFile(page);
235            Assert.assertTrue("The clock out button should have displayed", page.asText().contains("Clock Out"));
236            Assert.assertTrue("The clock out button should have displayed", page.asText().contains("Take Lunch"));
237    
238            return page;
239        }
240    
241        private HtmlPage clockOut() throws Exception {
242            DateTime dateTime = new DateTime();
243            if (dateTime.getSecondOfMinute() == 0) {
244                Thread.sleep(2000);
245            }
246            // Clock out
247            HtmlPage page = clockAction(TkConstants.CLOCK_OUT);
248    
249            // Make sure clock in button is rendered
250            HtmlUnitUtil.createTempFile(page);
251            Assert.assertTrue("The clock out button should have displayed", page.asText().contains("Clock In"));
252    
253            return page;
254        }
255    
256        /**
257         * This method is used for clocking in and out.
258         * For some reason, htmlunit couldn't click the clock action button correctly.
259         * It's probably because we bind a onClick event to the button instead of submitting the form.
260         *
261         * @param clockAction
262         * @return HtmlPage page
263         */
264        private HtmlPage clockAction(String clockAction) throws Exception {
265            DateTime dateTime = new DateTime();
266            if (dateTime.getSecondOfMinute() == 0) {
267                Thread.sleep(2000);
268            }
269            String baseUrl = TkTestConstants.Urls.CLOCK_URL;
270            String actionUrl = baseUrl + "?methodToCall=clockAction&selectedAssignment=30_30_30&currentClockAction=" + clockAction;
271            HtmlPage page = HtmlUnitUtil.gotoPageAndLogin(actionUrl);
272            Assert.assertNotNull("The login page shouldn't be null", page);
273            Thread.sleep(3000);
274            return page;
275        }
276    
277    
278    }