]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - tests/modules/Schedulers/SchedulerTest.php
Release 6.5.16
[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-2013 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             // Job with incorrectly set time-range should fail to execute (crontab notation allows no reverse ranges)
187             array("1-59::*::*::*::*", "5/17/2011 2:15pm", null, true),
188             array("59-1::*::*::*::*", "5/17/2011 2:15pm", null, false),
189              );
190     }
191
192     /**
193      * @dataProvider getSchedules
194      * Test deriveDBDateTimes()
195      */
196     public function testDbTimes($sched, $time, $last, $run)
197     {
198         $time = $this->timedate->fromUser($time);
199         $time->setTime($time->hour, $time->min, rand(0, 59));
200         $this->timedate->setNow($time);
201         $this->scheduler->job_interval = $sched;
202         $this->scheduler->catch_up = false;
203         if($last) {
204             $this->scheduler->last_run = $this->timedate->fromUser($last)->asDb();
205         } else {
206             $this->scheduler->last_run = null;
207         }
208         if($run) {
209             $this->assertTrue($this->scheduler->fireQualified());
210         } else {
211             $this->assertFalse($this->scheduler->fireQualified());
212         }
213     }
214
215     public function testScheduleJob()
216     {
217         $this->scheduler->job_interval =  "*::*::*::*::*";
218         $this->scheduler->new_with_id = true;
219         $this->scheduler->status = "Active";
220         $this->scheduler->job = "test::test";
221         $this->scheduler->save();
222         $queue = new MockSchedulerQueue();
223         $this->scheduler->checkPendingJobs($queue);
224         $this->assertNotEmpty($queue->jobs, "Job was not submitted");
225         $ourjob = null;
226         foreach($queue->jobs as $job) {
227             if($job->scheduler_id == $this->scheduler->id) {
228                 $ourjob = $job;
229                 break;
230             }
231         }
232         $this->assertNotEmpty($ourjob, "Could not find our job in the queue");
233         $this->assertEquals(SchedulersJob::JOB_STATUS_QUEUED, $ourjob->status, "Wrong status");
234     }
235
236     public function testScheduleJobRepeat()
237     {
238         $this->scheduler->job_interval =  "*::*::*::*::*";
239         $this->scheduler->job = "test::test";
240         $this->scheduler->status = "Active";
241         $this->scheduler->new_with_id = true;
242         $this->scheduler->save();
243         $queue = new MockSchedulerQueue();
244         $this->scheduler->checkPendingJobs($queue);
245         $this->assertNotEmpty($queue->jobs, "Job was not submitted");
246         $ourjob = null;
247         foreach($queue->jobs as $job) {
248             if($job->scheduler_id == $this->scheduler->id) {
249                 $ourjob = $job;
250                 break;
251             }
252         }
253         $this->assertNotEmpty($ourjob, "Could not find our job in the queue");
254         // Do that again
255         $queue = new MockSchedulerQueue();
256         $this->scheduler->checkPendingJobs($queue);
257         $ourjob2 = null;
258         foreach($queue->jobs as $job) {
259             if($job->scheduler_id == $this->scheduler->id) {
260                 $ourjob2 = $job;
261                 break;
262             }
263         }
264         $this->assertEmpty($ourjob2, "Copy job submitted");
265         // set job to running
266         $ourjob->status = SchedulersJob::JOB_STATUS_RUNNING;
267         $ourjob->save();
268         $queue = new MockSchedulerQueue();
269         $this->scheduler->checkPendingJobs($queue);
270         $ourjob2 = null;
271         foreach($queue->jobs as $job) {
272             if($job->scheduler_id == $this->scheduler->id) {
273                 $ourjob2 = $job;
274                 break;
275             }
276         }
277         $this->assertEmpty($ourjob2, "Copy job submitted");
278         // set job to done
279         $ourjob->status = SchedulersJob::JOB_STATUS_DONE;
280         $ourjob->save();
281         $queue = new MockSchedulerQueue();
282         $this->scheduler->checkPendingJobs($queue);
283         $ourjob2 = null;
284         foreach($queue->jobs as $job) {
285             if($job->scheduler_id == $this->scheduler->id) {
286                 $ourjob2 = $job;
287                 break;
288             }
289         }
290         $this->assertNotEmpty($ourjob, "Could not find our job in the queue");
291     }
292
293     public function testJobsCleanupReschedule()
294     {
295         $this->scheduler->job_interval =  "*::*::*::*::*";
296         $this->scheduler->job = "test::test";
297         $this->scheduler->status = "Active";
298         $this->scheduler->new_with_id = true;
299         $this->scheduler->save();
300
301         $job = new SchedulersJob();
302         $job->update_date_modified = false;
303         $job->status = SchedulersJob::JOB_STATUS_RUNNING;
304         $job->scheduler_id = $this->scheduler->id;
305         $job->execute_time = $GLOBALS['timedate']->nowDb();
306         $job->date_entered = '2010-01-01 12:00:00';
307         $job->date_modified = '2010-01-01 12:00:00';
308         $job->name = "Unit test Job 1";
309         $job->target = "test::test";
310         $job->assigned_user_id = $GLOBALS['current_user']->id;
311         $job->save();
312         $jobid = $job->id;
313         // try queue run with old job stuck
314         $queue = new MockSchedulerQueue();
315         $this->scheduler->checkPendingJobs($queue);
316         $ourjob = null;
317         foreach($queue->jobs as $job) {
318             if($job->scheduler_id == $this->scheduler->id) {
319                 $ourjob = $job;
320                 break;
321             }
322         }
323         $this->assertEmpty($ourjob, "Duplicate job found");
324         // now cleanup the job
325         $queue->cleanup();
326         $job = new SchedulersJob();
327         $job->retrieve($jobid);
328         $this->assertEquals(SchedulersJob::JOB_STATUS_DONE, $job->status, "Wrong status");
329         $this->assertEquals(SchedulersJob::JOB_FAILURE, $job->resolution, "Wrong resolution");
330         // now try again - should schedule now
331         $queue = new MockSchedulerQueue();
332         $this->scheduler->checkPendingJobs($queue);
333         $ourjob = null;
334         foreach($queue->jobs as $job) {
335             if($job->scheduler_id == $this->scheduler->id) {
336                 $ourjob = $job;
337                 break;
338             }
339         }
340         $this->assertNotEmpty($ourjob, "Could not find our job in the queue");
341     }
342
343 }
344
345 class MockSchedulerQueue extends SugarJobQueue
346 {
347     public $jobs = array();
348
349     public function submitJob($job)
350     {
351         $this->jobs[] = $job;
352         parent::submitJob($job);
353     }
354 }
355
356 class TestScheduler extends Scheduler
357 {
358     public $fired = false;
359     public $id = "test";
360     public $name = "testJob";
361     public $date_time_start = '2005-01-01 19:00:00';
362
363     public function fire() {
364         $this->fired = true;
365     }
366 }