]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - tests/modules/Schedulers/SchedulerTest.php
Release 6.5.6
[Github/sugarcrm.git] / tests / modules / Schedulers / SchedulerTest.php
1 <?php
2 /*********************************************************************************
3  * SugarCRM Community Edition is a customer relationship management program developed by
4  * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
5  * 
6  * This program is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU Affero General Public License version 3 as published by the
8  * Free Software Foundation with the addition of the following permission added
9  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
10  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
11  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
12  * 
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
16  * details.
17  * 
18  * You should have received a copy of the GNU Affero General Public License along with
19  * this program; if not, see http://www.gnu.org/licenses or write to the Free
20  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21  * 02110-1301 USA.
22  * 
23  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
24  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
25  * 
26  * The interactive user interfaces in modified source and object code versions
27  * of this program must display Appropriate Legal Notices, as required under
28  * Section 5 of the GNU Affero General Public License version 3.
29  * 
30  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
31  * these Appropriate Legal Notices must retain the display of the "Powered by
32  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
33  * technical reasons, the Appropriate Legal Notices must display the words
34  * "Powered by SugarCRM".
35  ********************************************************************************/
36
37 require_once 'include/SugarQueue/SugarJobQueue.php';
38 require_once 'modules/Schedulers/Scheduler.php';
39
40 class SchedulerTest extends Sugar_PHPUnit_Framework_TestCase
41 {
42         static protected $old_timedate;
43
44         public static function setUpBeforeClass()
45         {
46                 self::$old_timedate = $GLOBALS['timedate'];
47             unset($GLOBALS['disable_date_format']);
48         $GLOBALS['current_user'] = SugarTestUserUtilities::createAnonymousUser();
49             $GLOBALS['current_user']->setPreference('datef', "m/d/Y");
50                 $GLOBALS['current_user']->setPreference('timef', "h:ia");
51                 $GLOBALS['current_user']->setPreference('timezone', "America/Los_Angeles");
52         }
53
54         public static function tearDownAfterClass()
55         {
56             SugarTestUserUtilities::removeAllCreatedAnonymousUsers();
57         unset($GLOBALS['current_user']);
58                 $GLOBALS['timedate'] = self::$old_timedate;
59         }
60
61         public function setUp()
62     {
63         $this->scheduler = new TestScheduler(false);
64         $GLOBALS['timedate'] = $this->timedate = TimeDate::getInstance();
65         $this->timedate->allow_cache = true;
66         $this->now = $this->timedate->getNow();
67     }
68
69     public function tearDown()
70     {
71         $this->timedate->setNow($this->now);
72         $GLOBALS['db']->query("DELETE FROM schedulers WHERE id='{$this->scheduler->id}'");
73         $GLOBALS['db']->query("DELETE FROM job_queue WHERE scheduler_id='{$this->scheduler->id}'");
74     }
75
76     /**
77      * Test catch-up functionality
78      */
79     public function testCatchUp()
80     {
81         $this->scheduler->job_interval = "*::*::*::*::*";
82         $this->scheduler->catch_up = true;
83         $this->assertTrue($this->scheduler->fireQualified());
84         // we were late to the job
85         $this->timedate->setNow($this->timedate->fromDb("2011-02-01 14:45:00"));
86         $this->scheduler->job_interval = "30::3::*::*::*"; // 10:30 or 11:30 in UTC
87         $this->scheduler->last_run = null;
88         $this->scheduler->catch_up = 0;
89         $this->assertFalse($this->scheduler->fireQualified());
90         // but we can still catch up
91         $this->scheduler->catch_up = 1;
92         $this->assertTrue($this->scheduler->fireQualified());
93         // if already did it, don't catch up
94         $this->scheduler->last_run = $this->timedate->getNow(true)->setDate(2011, 2, 1)->setTime(3, 30)->asDb();
95         $this->assertFalse($this->scheduler->fireQualified());
96         // but if did it yesterday, do
97         $this->scheduler->last_run = $this->timedate->getNow(true)->setDate(2011, 1, 31)->setTime(3, 30)->asDb();
98         $this->assertTrue($this->scheduler->fireQualified());
99     }
100
101     /**
102      * Test date start/finish
103      */
104     public function testDateFromTo()
105     {
106         $this->scheduler->job_interval = "*::*::*::*::*";
107         $this->scheduler->catch_up = 0;
108         $this->timedate->setNow($this->timedate->fromDb("2011-04-17 20:00:00"));
109
110         // no limits
111         $this->assertTrue($this->scheduler->fireQualified());
112         // limit start, inclusive
113         $this->scheduler->date_time_start = "2011-01-01 20:00:00";
114         $this->assertTrue($this->scheduler->fireQualified(), "Inclusive start test failed");
115         // exact time ok
116         $this->scheduler->date_time_start = "2011-04-17 20:00:00";
117         $this->assertTrue($this->scheduler->fireQualified(), "Start now test failed");
118         // limit start, exclusive
119         $this->scheduler->date_time_start = "2011-05-01 20:00:00";
120         $this->assertFalse($this->scheduler->fireQualified(), "Exclusive start test failed");
121
122         // limit end, inclusive
123         $this->scheduler->date_time_start = "2011-01-01 20:00:00";
124         $this->scheduler->date_time_end = "2011-05-01 20:00:00";
125         $this->assertTrue($this->scheduler->fireQualified(), "Inclusive start test failed");
126         // exact time ok
127         $this->scheduler->date_time_end = "2011-04-17 20:00:00";
128         $this->assertTrue($this->scheduler->fireQualified(), "Start now test failed");
129         // limit start, exclusive
130         $this->scheduler->date_time_end = "2011-02-01 20:00:00";
131         $this->assertFalse($this->scheduler->fireQualified(), "Exclusive start test failed");
132     }
133
134     /**
135      * Test date start/finish
136      */
137     public function testActiveFromTo()
138     {
139         $this->scheduler->job_interval = "*::*::*::*::*";
140         $this->scheduler->catch_up = 0;
141         $this->scheduler->time_from = "02:00:00";
142         $this->scheduler->time_to = "21:00:00";
143
144         $this->timedate->setNow($this->timedate->fromUser("1/17/2011 01:20am"));
145         $this->assertFalse($this->scheduler->fireQualified(), "Before start test failed");
146         $this->timedate->setNow($this->timedate->fromUser("2/17/2011 02:00am"));
147         $this->assertTrue($this->scheduler->fireQualified(), "Start test failed");
148         $this->timedate->setNow($this->timedate->fromUser("5/17/2011 10:00am"));
149         $this->assertTrue($this->scheduler->fireQualified(), "After start test failed");
150         $this->timedate->setNow($this->timedate->fromUser("7/17/2011 9:00pm"));
151         $this->assertTrue($this->scheduler->fireQualified(), "End test failed");
152         $this->timedate->setNow($this->timedate->fromUser("11/17/2011 11:30pm"));
153         $this->assertFalse($this->scheduler->fireQualified(), "After end test failed");
154     }
155
156     public function getSchedules()
157     {
158         return array(
159             // schedule - now point - last run - should be run?
160             array("*::*::*::*::*", "5/17/2011 1:00am", null, true),
161             array("*::*::*::*::*", "5/17/2011 11:20pm", null, true),
162             array("*::*::*::*::*", "5/17/2011 5:40pm", null, true),
163             array("*::*::*::*::*", "5/17/2011 7:43pm", null, true),
164             // at X:25
165             array("25::*::*::*::*", "5/17/2011 5:25pm", null, true),
166             array("25::*::*::*::*", "5/17/2011 7:27pm", null, false),
167             array("25::*::*::*::*", "5/17/2011 7:25pm", "5/17/2011 7:25pm", false),
168             array("25::*::*::*::*", "5/17/2011 8:25pm", "5/17/2011 7:25pm", true),
169             // at 6:00
170              array("0::6::*::*::*", "5/17/2011 6:00pm", null, false),
171              array("0::6::*::*::*", "5/17/2011 6:00am", null, true),
172              array("0::6::*::*::*", "5/17/2011 1:00pm", null, false),
173              array("0::6::*::*::*", "5/17/2011 2:00pm", null, false),
174              // 2am on 1st
175              array("0::2::1::*::*", "2/1/2011 2:00pm", null, false),
176              array("0::2::1::*::*", "2/1/2011 2:00am", null, true),
177              array("0::2::1::*::*", "2/17/2011 2:00am", null, false),
178              array("0::2::1::*::*", "1/31/2011 2:00am", null, false),
179              array("0::2::1::*::*", "2/2/2011 2:00am", null, false),
180              // Every 15 mins on Mon, Tue
181              array("*/15::*::*::*::1,2", "5/16/2011 2:00pm", null, true),
182              array("*/15::*::*::*::1,2", "5/17/2011 2:00pm", null, true),
183              array("*/15::*::*::*::1,2", "5/18/2011 2:00pm", null, false),
184              array("*/15::*::*::*::1,2", "5/17/2011 2:10pm", "5/17/2011 2:00pm", false),
185              array("*/15::*::*::*::1,2", "5/17/2011 2:15pm", "5/17/2011 2:00pm", true),
186              );
187     }
188
189     /**
190      * @dataProvider getSchedules
191      * Test deriveDBDateTimes()
192      */
193     public function testDbTimes($sched, $time, $last, $run)
194     {
195         $time = $this->timedate->fromUser($time);
196         $time->setTime($time->hour, $time->min, rand(0, 59));
197         $this->timedate->setNow($time);
198         $this->scheduler->job_interval = $sched;
199         $this->scheduler->catch_up = false;
200         if($last) {
201             $this->scheduler->last_run = $this->timedate->fromUser($last)->asDb();
202         } else {
203             $this->scheduler->last_run = null;
204         }
205         if($run) {
206             $this->assertTrue($this->scheduler->fireQualified());
207         } else {
208             $this->assertFalse($this->scheduler->fireQualified());
209         }
210     }
211
212     public function testScheduleJob()
213     {
214         $this->scheduler->job_interval =  "*::*::*::*::*";
215         $this->scheduler->new_with_id = true;
216         $this->scheduler->status = "Active";
217         $this->scheduler->job = "test::test";
218         $this->scheduler->save();
219         $queue = new MockSchedulerQueue();
220         $this->scheduler->checkPendingJobs($queue);
221         $this->assertNotEmpty($queue->jobs, "Job was not submitted");
222         $ourjob = null;
223         foreach($queue->jobs as $job) {
224             if($job->scheduler_id == $this->scheduler->id) {
225                 $ourjob = $job;
226                 break;
227             }
228         }
229         $this->assertNotEmpty($ourjob, "Could not find our job in the queue");
230         $this->assertEquals(SchedulersJob::JOB_STATUS_QUEUED, $ourjob->status, "Wrong status");
231     }
232
233     public function testScheduleJobRepeat()
234     {
235         $this->scheduler->job_interval =  "*::*::*::*::*";
236         $this->scheduler->job = "test::test";
237         $this->scheduler->status = "Active";
238         $this->scheduler->new_with_id = true;
239         $this->scheduler->save();
240         $queue = new MockSchedulerQueue();
241         $this->scheduler->checkPendingJobs($queue);
242         $this->assertNotEmpty($queue->jobs, "Job was not submitted");
243         $ourjob = null;
244         foreach($queue->jobs as $job) {
245             if($job->scheduler_id == $this->scheduler->id) {
246                 $ourjob = $job;
247                 break;
248             }
249         }
250         $this->assertNotEmpty($ourjob, "Could not find our job in the queue");
251         // Do that again
252         $queue = new MockSchedulerQueue();
253         $this->scheduler->checkPendingJobs($queue);
254         $ourjob2 = null;
255         foreach($queue->jobs as $job) {
256             if($job->scheduler_id == $this->scheduler->id) {
257                 $ourjob2 = $job;
258                 break;
259             }
260         }
261         $this->assertEmpty($ourjob2, "Copy job submitted");
262         // set job to running
263         $ourjob->status = SchedulersJob::JOB_STATUS_RUNNING;
264         $ourjob->save();
265         $queue = new MockSchedulerQueue();
266         $this->scheduler->checkPendingJobs($queue);
267         $ourjob2 = null;
268         foreach($queue->jobs as $job) {
269             if($job->scheduler_id == $this->scheduler->id) {
270                 $ourjob2 = $job;
271                 break;
272             }
273         }
274         $this->assertEmpty($ourjob2, "Copy job submitted");
275         // set job to done
276         $ourjob->status = SchedulersJob::JOB_STATUS_DONE;
277         $ourjob->save();
278         $queue = new MockSchedulerQueue();
279         $this->scheduler->checkPendingJobs($queue);
280         $ourjob2 = null;
281         foreach($queue->jobs as $job) {
282             if($job->scheduler_id == $this->scheduler->id) {
283                 $ourjob2 = $job;
284                 break;
285             }
286         }
287         $this->assertNotEmpty($ourjob, "Could not find our job in the queue");
288     }
289
290     public function testJobsCleanupReschedule()
291     {
292         $this->scheduler->job_interval =  "*::*::*::*::*";
293         $this->scheduler->job = "test::test";
294         $this->scheduler->status = "Active";
295         $this->scheduler->new_with_id = true;
296         $this->scheduler->save();
297
298         $job = new SchedulersJob();
299         $job->update_date_modified = false;
300         $job->status = SchedulersJob::JOB_STATUS_RUNNING;
301         $job->scheduler_id = $this->scheduler->id;
302         $job->execute_time = $GLOBALS['timedate']->nowDb();
303         $job->date_entered = '2010-01-01 12:00:00';
304         $job->date_modified = '2010-01-01 12:00:00';
305         $job->name = "Unit test Job 1";
306         $job->target = "test::test";
307         $job->assigned_user_id = $GLOBALS['current_user']->id;
308         $job->save();
309         $jobid = $job->id;
310         // try queue run with old job stuck
311         $queue = new MockSchedulerQueue();
312         $this->scheduler->checkPendingJobs($queue);
313         $ourjob = null;
314         foreach($queue->jobs as $job) {
315             if($job->scheduler_id == $this->scheduler->id) {
316                 $ourjob = $job;
317                 break;
318             }
319         }
320         $this->assertEmpty($ourjob, "Duplicate job found");
321         // now cleanup the job
322         $queue->cleanup();
323         $job = new SchedulersJob();
324         $job->retrieve($jobid);
325         $this->assertEquals(SchedulersJob::JOB_STATUS_DONE, $job->status, "Wrong status");
326         $this->assertEquals(SchedulersJob::JOB_FAILURE, $job->resolution, "Wrong resolution");
327         // now try again - should schedule now
328         $queue = new MockSchedulerQueue();
329         $this->scheduler->checkPendingJobs($queue);
330         $ourjob = null;
331         foreach($queue->jobs as $job) {
332             if($job->scheduler_id == $this->scheduler->id) {
333                 $ourjob = $job;
334                 break;
335             }
336         }
337         $this->assertNotEmpty($ourjob, "Could not find our job in the queue");
338     }
339
340 }
341
342 class MockSchedulerQueue extends SugarJobQueue
343 {
344     public $jobs = array();
345
346     public function submitJob($job)
347     {
348         $this->jobs[] = $job;
349         parent::submitJob($job);
350     }
351 }
352
353 class TestScheduler extends Scheduler
354 {
355     public $fired = false;
356     public $id = "test";
357     public $name = "testJob";
358     public $date_time_start = '2005-01-01 19:00:00';
359
360     public function fire() {
361         $this->fired = true;
362     }
363 }