View Javadoc
1   /**
2    * Copyright 2004-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.hr.time.clock.web;
17  
18  import java.math.BigDecimal;
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.Collections;
22  import java.util.Iterator;
23  import java.util.LinkedHashMap;
24  import java.util.List;
25  import java.util.Map;
26  
27  import org.joda.time.DateTime;
28  import org.joda.time.DateTimeZone;
29  import org.joda.time.LocalDate;
30  import org.junit.Assert;
31  import org.junit.Ignore;
32  import org.junit.Test;
33  import org.kuali.hr.KPMEWebTestCase;
34  import org.kuali.hr.util.HtmlUnitUtil;
35  import org.kuali.kpme.core.FunctionalTest;
36  import org.kuali.kpme.core.service.HrServiceLocator;
37  import org.kuali.kpme.core.util.HrTestConstants;
38  import org.kuali.kpme.core.util.TKUtils;
39  import org.kuali.kpme.tklm.api.common.TkConstants;
40  import org.kuali.kpme.tklm.api.time.clocklog.ClockLog;
41  import org.kuali.kpme.tklm.api.time.timeblock.TimeBlock;
42  import org.kuali.kpme.tklm.time.clocklog.ClockLogBo;
43  import org.kuali.kpme.tklm.time.rules.graceperiod.GracePeriodRule;
44  import org.kuali.kpme.tklm.time.service.TkServiceLocator;
45  import org.kuali.kpme.tklm.time.timeblock.TimeBlockBo;
46  import org.kuali.kpme.tklm.time.timehourdetail.TimeHourDetailBo;
47  import org.kuali.kpme.tklm.time.timesheet.TimesheetDocument;
48  import org.kuali.kpme.tklm.time.workflow.TimesheetDocumentHeader;
49  import org.kuali.kpme.tklm.utils.TkTestConstants;
50  import org.kuali.rice.core.api.config.property.ConfigContext;
51  import org.kuali.rice.krad.service.KRADServiceLocator;
52  
53  import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
54  import com.gargoylesoftware.htmlunit.WebClient;
55  import com.gargoylesoftware.htmlunit.html.HtmlElement;
56  import com.gargoylesoftware.htmlunit.html.HtmlPage;
57  
58  
59  @FunctionalTest
60  public class ClockWebTest extends KPMEWebTestCase {
61  
62      private String tbId;
63  
64      public Long maxDocumentId() {
65          Collection aCol = KRADServiceLocator.getBusinessObjectService().findAll(TimesheetDocumentHeader.class);
66          Long maxId = new Long(-1);
67          Iterator<TimesheetDocumentHeader> itr = aCol.iterator();
68          while (itr.hasNext()) {
69              TimesheetDocumentHeader tdh = itr.next();
70              Long temp = new Long(tdh.getDocumentId());
71              if (temp > maxId) {
72                  maxId = temp;
73              }
74          }
75          return maxId;
76      }
77  
78      public Long maxTimeBlockId() {
79          Collection aCol = KRADServiceLocator.getBusinessObjectService().findAll(TimeBlockBo.class);
80          Long maxId = new Long(-1);
81          Iterator<TimeBlockBo> itr = aCol.iterator();
82          while (itr.hasNext()) {
83              TimeBlockBo tb = itr.next();
84              Long temp = new Long(tb.getTkTimeBlockId());
85              if (temp > maxId) {
86                  maxId = temp;
87              }
88          }
89          return maxId;
90      }
91  
92      public void createTB() {
93          TimeBlockBo timeBlock = new TimeBlockBo();
94          timeBlock.setUserPrincipalId("admin");
95          timeBlock.setJobNumber(2L);
96          timeBlock.setWorkArea(1234L);
97          timeBlock.setTask(1L);
98          timeBlock.setEarnCode("RGN");
99          timeBlock.setBeginTimestamp(TKUtils.getCurrentTimestamp());
100         timeBlock.setEndTimestamp(TKUtils.getCurrentTimestamp());
101         TimeHourDetailBo timeHourDetail = new TimeHourDetailBo();
102         timeHourDetail.setEarnCode("RGN");
103         timeHourDetail.setHours(new BigDecimal(2.0));
104         timeBlock.getTimeHourDetails().add(timeHourDetail);
105         timeBlock.setHours(new BigDecimal(2.0));
106         List<TimeBlock> tbList = new ArrayList<TimeBlock>();
107         String documentId = this.maxDocumentId().toString();
108         timeBlock.setDocumentId(documentId);
109         tbList.add(TimeBlockBo.to(timeBlock));
110         TkServiceLocator.getTimeBlockService().saveTimeBlocks(tbList);
111 
112         tbId = timeBlock.getTkTimeBlockId();
113         TimesheetDocument td = TkServiceLocator.getTimesheetService().getTimesheetDocument(documentId);
114         td.setTimeBlocks(tbList);
115 
116     }
117 
118     @Ignore
119     public void testDistributeTB() throws Exception {
120         String baseUrl = TkTestConstants.Urls.CLOCK_URL;
121         HtmlPage page = HtmlUnitUtil.gotoPageAndLogin(getWebClient(), baseUrl);
122         Assert.assertNotNull(page);
123         Assert.assertTrue("Clock Page contains Distribute Button", page.asText().contains("Distribute Time Blocks"));
124         this.createTB();
125         updateWebClient();
126         HtmlElement element = page.getElementByName("distributeTime");
127         Assert.assertNotNull(element);
128 //	  	HtmlPage testPage1 = element.click();
129 //	  	assertTrue("Distribute Page contains Close button", testPage1.asText().contains("Close"));
130 //        assertTrue("Distribute Page contains Close button", testPage1.asText().contains("Edit"));
131 
132         // timeDistribute.jsp
133         String distributeUrl = baseUrl + "?methodToCall=distributeTimeBlocks";
134         HtmlPage page1 = HtmlUnitUtil.gotoPageAndLogin(getWebClient(), distributeUrl);
135         Assert.assertTrue("Distribute Page contains Close button", page1.asText().contains("Close"));
136         Assert.assertTrue("Distribute Page contains Close button", page1.asText().contains("Edit"));
137 
138         element = page1.getElementByName("editTimeBlock");
139         Assert.assertNotNull(element);
140         Assert.assertTrue("Onclick attribute of Edit button contains", element.getAttribute("onclick").contains("Clock.do?methodToCall=editTimeBlock&editTimeBlockId="));
141 
142         if (tbId == null) {
143             tbId = this.maxTimeBlockId().toString();
144         }
145 
146         //editTimeBlock.jsp
147         String editUrl = baseUrl + "?methodToCall=editTimeBlock&editTimeBlockId=" + tbId;
148         HtmlPage page3 = HtmlUnitUtil.gotoPageAndLogin(getWebClient(), editUrl);
149 
150         // editTimeBlock.jsp
151         Assert.assertTrue("Edit Time Blocks Page contains Cancel button", page3.asText().contains("Add"));
152         Assert.assertTrue("Edit Time Blocks Page contains Save button", page3.asText().contains("Save"));
153         Assert.assertTrue("Edit Time Blocks Page contains Cancel button", page3.asText().contains("Cancel"));
154 
155         element = page3.getElementByName("addTimeBlock");
156         Assert.assertNotNull(element);
157         Assert.assertTrue("Onclick attribute of Add button contains", element.getAttribute("onclick").contains("javascript: addTimeBlockRow(this.form);"));
158 
159         updateWebClient();
160 
161 //	  	HtmlPage page4 = element.click();
162 //	  	assertTrue("Edit Time Blocks Page contains Cancel button", page4.asText().contains("Add"));
163 
164     }
165 
166     public void updateWebClient() {
167         WebClient webClient = getWebClient();
168         webClient.getOptions().setJavaScriptEnabled(true);
169         webClient.getOptions().setThrowExceptionOnScriptError(false);
170         webClient.setAjaxController(new NicelyResynchronizingAjaxController());
171         webClient.waitForBackgroundJavaScript(10000);
172     }
173 
174     /**
175      * This test is to :
176      * 1) make sure the seconds on clockTimestamp and timestamp are preserved when there is no grace period rule.
177      * 2) the clock in / out button is correctly rendered
178      *
179      * @throws Exception
180      */
181     @Test
182     public void testClockActionWithoutGracePeriodRule() throws Exception {
183         // Make sure there is no active grace period rule
184         GracePeriodRule gpr = TkServiceLocator.getGracePeriodService().getGracePeriodRule(LocalDate.now());
185         if (gpr != null && gpr.isActive()) {
186             gpr.setActive(false);
187             KRADServiceLocator.getBusinessObjectService().save(gpr);
188         }
189 
190         // Clock in
191         clockIn();
192         // Make sure clock out button is rendered
193         ClockLog lastClockLog = TkServiceLocator.getClockLogService().getLastClockLog("admin");
194         // Make sure both timestamps preserve seconds
195         Assert.assertTrue("The seconds on clock timestamp should be preserved", lastClockLog.getClockDateTime().getSecondOfMinute() != 0);
196         Assert.assertTrue("The seconds on timestamp should be preserved", lastClockLog.getCreateTime().getSecondOfMinute() != 0);
197 
198         // Clock out
199         clockOut();
200         // Make sure both timestamps preserve seconds
201         lastClockLog = TkServiceLocator.getClockLogService().getLastClockLog("admin");
202         Assert.assertTrue("The seconds on clock timestamp should be preserved", lastClockLog.getClockDateTime().getSecondOfMinute() != 0);
203         Assert.assertTrue("The seconds on timestamp should be preserved", lastClockLog.getCreateTime().getSecondOfMinute() != 0);
204     }
205 
206     @Test
207     public void testClockActionWithGracePeriodRule() throws Exception {
208     	String gpRuleConfig = ConfigContext.getCurrentContextConfig().getProperty(TkConstants.KPME_GRACE_PERIOD_RULE_CONFIG);
209     	if(gpRuleConfig != null && gpRuleConfig.equals("CLOCK")) {
210 	    	//clean clock logs
211 	        KRADServiceLocator.getBusinessObjectService().deleteMatching(ClockLogBo.class, Collections.singletonMap("principalId", "admin"));
212 	        GracePeriodRule gpr = new GracePeriodRule();
213 	        //gpr.setTkGracePeriodRuleId("1");
214 	        gpr.setEffectiveLocalDate(new LocalDate(2010, 1, 1));
215 	        gpr.setHourFactor(new BigDecimal(3));
216 	        gpr.setTimestamp(TKUtils.getCurrentTimestamp());
217 	        gpr.setUserPrincipalId("admin");
218 	        
219 	        gpr.setActive(true);
220 	        KRADServiceLocator.getBusinessObjectService().save(gpr);
221 	
222 	        // Clock in
223 	        clockIn();
224 	        // Make sure clock out button is rendered
225 	        ClockLog lastClockLog = TkServiceLocator.getClockLogService().getLastClockLog("admin");
226 	        // Make sure both timestamps preserve seconds
227 	        Assert.assertTrue("The seconds on clock timestamp should NOT be preserved", lastClockLog.getClockDateTime().getSecondOfMinute() == 0);
228 	        Assert.assertTrue("The seconds on timestamp should be preserved", lastClockLog.getCreateTime().getSecondOfMinute() != 0);
229 	
230 	        // Clock out
231 	        clockOut();
232 	        // Make sure both timestamps preserve seconds
233 	        lastClockLog = TkServiceLocator.getClockLogService().getLastClockLog("admin");
234 	        Assert.assertTrue("The seconds on clock timestamp should NOT be preserved", lastClockLog.getClockDateTime().getSecondOfMinute() == 0);
235 	        Assert.assertTrue("The seconds on timestamp should be preserved", lastClockLog.getCreateTime().getSecondOfMinute() != 0);
236 
237     	}
238     }
239     
240     
241 	@Test
242 	public void testClockInOutWithTimezone() throws Exception {
243 		HtmlPage page = HtmlUnitUtil.gotoPageAndLogin(getWebClient(), TkTestConstants.Urls.CLOCK_URL,true);
244 		Assert.assertNotNull(page);
245     	
246     	Map<String, Object> criteria = new LinkedHashMap<String, Object>();
247     	criteria.put("selectedAssignment", new String[]{HrTestConstants.FormElementTypes.DROPDOWN, "IU-IN_30_30_30"});
248     	// choose the first assignment from the drop down
249     	page = HtmlUnitUtil.fillOutForm(page, criteria);
250     	Assert.assertNotNull(page);
251     	// clock in
252     	page = HtmlUnitUtil.clickButton(page, "clockAction");
253     	// clock out 
254     	page = HtmlUnitUtil.clickButton(page, "clockAction");
255     	HtmlUnitUtil.createTempFile(page);
256     	
257     	DateTimeZone dateTimeZone = DateTimeZone.forID(HrServiceLocator.getTimezoneService().getUserTimezone());
258     	DateTime dateTime = new DateTime().withZone(dateTimeZone);
259     	String timeZone = dateTime.toString("zzzz");
260     	Assert.assertTrue("Time zone information is incorrect", page.asText().contains(timeZone));
261 	}
262 
263     private HtmlPage clockIn() throws Exception {
264 
265         // Clock in
266         HtmlPage page = clockAction(TkConstants.CLOCK_IN);
267 
268         // Make sure clock in button is rendered
269         HtmlUnitUtil.createTempFile(page);
270         Assert.assertTrue("The clock out button should have displayed", page.asText().contains("Clock Out"));
271         // KPME-3532 system lunch is always off now, so lunch button should never show up
272         // Assert.assertTrue("The clock out button should have displayed", page.asText().contains("Take Lunch"));
273 
274         return page;
275     }
276 
277     private HtmlPage clockOut() throws Exception {
278         DateTime dateTime = new DateTime();
279         if (dateTime.getSecondOfMinute() >= 58
280                 || dateTime.getSecondOfMinute() == 0) {
281             Thread.sleep(4000);
282         }
283         // Clock out
284         HtmlPage page = clockAction(TkConstants.CLOCK_OUT);
285 
286         // Make sure clock in button is rendered
287         HtmlUnitUtil.createTempFile(page);
288         Assert.assertTrue("The clock out button should have displayed", page.asText().contains("Clock In"));
289 
290         return page;
291     }
292 
293     /**
294      * This method is used for clocking in and out.
295      * For some reason, htmlunit couldn't click the clock action button correctly.
296      * It's probably because we bind a onClick event to the button instead of submitting the form.
297      *
298      * @param clockAction
299      * @return HtmlPage page
300      */
301     private HtmlPage clockAction(String clockAction) throws Exception {
302         DateTime dateTime = new DateTime();
303         if (dateTime.getSecondOfMinute() >= 58
304                 || dateTime.getSecondOfMinute() == 0) {
305             Thread.sleep(4000);
306         }
307         String baseUrl = TkTestConstants.Urls.CLOCK_URL;
308         String actionUrl = baseUrl + "?methodToCall=clockAction&selectedAssignment=IU-IN_30_30_30&currentClockAction=" + clockAction;
309         HtmlPage page = HtmlUnitUtil.gotoPageAndLogin(getWebClient(), actionUrl);
310         Assert.assertNotNull("The login page shouldn't be null", page);
311         Thread.sleep(3000);
312         return page;
313     }
314 
315 
316 }