]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - tests/SugarTestHelper.php
Release 6.5.6
[Github/sugarcrm.git] / tests / SugarTestHelper.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
38 if(!defined('sugarEntry')) define('sugarEntry', true);
39
40 set_include_path(
41     dirname(__FILE__) . PATH_SEPARATOR .
42     dirname(__FILE__) . '/..' . PATH_SEPARATOR .
43     get_include_path()
44 );
45
46 // constant to indicate that we are running tests
47 if (!defined('SUGAR_PHPUNIT_RUNNER'))
48     define('SUGAR_PHPUNIT_RUNNER', true);
49
50 // initialize the various globals we use
51 global $sugar_config, $db, $fileName, $current_user, $locale, $current_language;
52
53 if ( !isset($_SERVER['HTTP_USER_AGENT']) )
54     // we are probably running tests from the command line
55     $_SERVER['HTTP_USER_AGENT'] = 'cli';
56
57 // move current working directory
58 chdir(dirname(__FILE__) . '/..');
59
60 require_once('include/entryPoint.php');
61
62 require_once('include/utils/layout_utils.php');
63
64 $GLOBALS['db'] = DBManagerFactory::getInstance();
65
66 $current_language = $sugar_config['default_language'];
67 // disable the SugarLogger
68 $sugar_config['logger']['level'] = 'fatal';
69
70 $GLOBALS['sugar_config']['default_permissions'] = array (
71                 'dir_mode' => 02770,
72                 'file_mode' => 0777,
73                 'chown' => '',
74                 'chgrp' => '',
75         );
76
77 $GLOBALS['js_version_key'] = 'testrunner';
78
79 if ( !isset($_SERVER['SERVER_SOFTWARE']) )
80     $_SERVER["SERVER_SOFTWARE"] = 'PHPUnit';
81
82 // helps silence the license checking when running unit tests.
83 $_SESSION['VALIDATION_EXPIRES_IN'] = 'valid';
84
85 $GLOBALS['startTime'] = microtime(true);
86
87 // clean out the cache directory
88 require_once('modules/Administration/QuickRepairAndRebuild.php');
89 $repair = new RepairAndClear();
90 $repair->module_list = array();
91 $repair->show_output = false;
92 $repair->clearJsLangFiles();
93 $repair->clearJsFiles();
94
95 // mark that we got by the admin wizard already
96 $focus = new Administration();
97 $focus->retrieveSettings();
98 $focus->saveSetting('system','adminwizard',1);
99
100 // include the other test tools
101 require_once 'SugarTestObjectUtilities.php';
102 require_once 'SugarTestProjectUtilities.php';
103 require_once 'SugarTestProjectTaskUtilities.php';
104 require_once 'SugarTestUserUtilities.php';
105 require_once 'SugarTestLangPackCreator.php';
106 require_once 'SugarTestThemeUtilities.php';
107 require_once 'SugarTestContactUtilities.php';
108 require_once 'SugarTestEmailUtilities.php';
109 require_once 'SugarTestCampaignUtilities.php';
110 require_once 'SugarTestLeadUtilities.php';
111 require_once 'SugarTestStudioUtilities.php';
112 require_once 'SugarTestMeetingUtilities.php';
113 require_once 'SugarTestCallUtilities.php';
114 require_once 'SugarTestAccountUtilities.php';
115 require_once 'SugarTestTrackerUtility.php';
116 require_once 'SugarTestImportUtilities.php';
117 require_once 'SugarTestMergeUtilities.php';
118 require_once 'SugarTestTaskUtilities.php';
119 require_once 'SugarTestOpportunityUtilities.php';
120 require_once 'SugarTestRelationshipUtilities.php';
121
122 $GLOBALS['db']->commit();
123
124 // define our testcase subclass
125 class Sugar_PHPUnit_Framework_TestCase extends PHPUnit_Framework_TestCase
126 {
127     protected $backupGlobals = FALSE;
128
129     protected $useOutputBuffering = true;
130
131     protected function assertPreConditions()
132     {
133         if(isset($GLOBALS['log'])) {
134             $GLOBALS['log']->info("START TEST: {$this->getName(false)}");
135         }
136         SugarCache::instance()->flush();
137     }
138
139     protected function assertPostConditions() {
140         if(!empty($_REQUEST)) {
141             foreach(array_keys($_REQUEST) as $k) {
142                         unset($_REQUEST[$k]);
143                     }
144         }
145
146         if(!empty($_POST)) {
147             foreach(array_keys($_POST) as $k) {
148                         unset($_POST[$k]);
149                     }
150         }
151
152         if(!empty($_GET)) {
153             foreach(array_keys($_GET) as $k) {
154                         unset($_GET[$k]);
155                     }
156         }
157         if(isset($GLOBALS['log'])) {
158             $GLOBALS['log']->info("DONE TEST: {$this->getName(false)}");
159         }
160         // reset error handler in case somebody set it
161         restore_error_handler();
162     }
163
164     public static function tearDownAfterClass()
165     {
166         unset($GLOBALS['disable_date_format']);
167         unset($GLOBALS['saving_relationships']);
168         unset($GLOBALS['updating_relationships']);
169         $GLOBALS['timedate']->clearCache();
170     }
171 }
172
173 // define output testcase subclass
174 class Sugar_PHPUnit_Framework_OutputTestCase extends PHPUnit_Extensions_OutputTestCase
175 {
176     protected $backupGlobals = FALSE;
177
178     protected $_notRegex;
179     protected $_outputCheck;
180
181     protected function assertPreConditions()
182     {
183         if(isset($GLOBALS['log'])) {
184             $GLOBALS['log']->info("START TEST: {$this->getName(false)}");
185         }
186         SugarCache::instance()->flush();
187     }
188
189     protected function assertPostConditions() {
190         if(!empty($_REQUEST)) {
191             foreach(array_keys($_REQUEST) as $k) {
192                         unset($_REQUEST[$k]);
193                     }
194         }
195
196         if(!empty($_POST)) {
197             foreach(array_keys($_POST) as $k) {
198                         unset($_POST[$k]);
199                     }
200         }
201
202         if(!empty($_GET)) {
203             foreach(array_keys($_GET) as $k) {
204                         unset($_GET[$k]);
205                     }
206         }
207         if(isset($GLOBALS['log'])) {
208             $GLOBALS['log']->info("DONE TEST: {$this->getName(false)}");
209         }
210     }
211
212     protected function NotRegexCallback($output)
213     {
214         if(empty($this->_notRegex)) {
215             return true;
216         }
217         $this->assertNotRegExp($this->_notRegex, $output);
218         return true;
219     }
220
221     public function setOutputCheck($callback)
222     {
223         if (!is_callable($callback)) {
224             throw new PHPUnit_Framework_Exception;
225         }
226
227         $this->_outputCheck = $callback;
228     }
229
230     protected function runTest()
231     {
232                 $testResult = parent::runTest();
233         if($this->_outputCheck) {
234             $this->assertTrue(call_user_func($this->_outputCheck, $this->output));
235         }
236         return $testResult;
237     }
238
239     public function expectOutputNotRegex($expectedRegex)
240     {
241         if (is_string($expectedRegex) || is_null($expectedRegex)) {
242             $this->_notRegex = $expectedRegex;
243         }
244
245         $this->setOutputCheck(array($this, "NotRegexCallback"));
246     }
247
248 }
249
250 // define a mock logger interface; used for capturing logging messages emited
251 // the test suite
252 class SugarMockLogger
253 {
254         private $_messages = array();
255
256         public function __call($method, $message)
257         {
258                 $this->messages[] = strtoupper($method) . ': ' . $message[0];
259         }
260
261         public function getLastMessage()
262         {
263                 return end($this->messages);
264         }
265
266         public function getMessageCount()
267         {
268                 return count($this->messages);
269         }
270 }
271
272 require_once('ModuleInstall/ModuleInstaller.php');
273
274 /**
275  * Own exception for SugarTestHelper class
276  *
277  * @author mgusev@sugarcrm.com
278  */
279 class SugarTestHelperException extends PHPUnit_Framework_Exception
280 {
281
282 }
283
284 /**
285  * Helper for initialization of global variables of SugarCRM
286  *
287  * @author mgusev@sugarcrm.com
288  */
289 class SugarTestHelper
290 {
291     /**
292      * @var array array of registered vars. It allows helper to unregister them on tearDown
293      */
294     protected static $registeredVars = array();
295
296     /**
297      * @var array array of global vars. They are storing on init one time and restoring in global scope each tearDown
298      */
299     protected static $initVars = array(
300         'GLOBALS' => array()
301     );
302
303     /**
304      * @var array of system preference of SugarCRM as theme etc. They are storing on init one time and restoring each tearDown
305      */
306     protected static $systemVars = array();
307
308     /**
309      * @var array of modules which we should refresh on tearDown.
310      */
311     protected static $cleanModules = array();
312
313     /**
314      * @var bool is SugarTestHelper inited or not. Just to skip initialization on the second and others call of init method
315      */
316     protected static $isInited = false;
317
318     /**
319      * All methods are static because of it we disable constructor
320      */
321     private function __construct()
322     {
323     }
324
325     /**
326      * All methods are static because of it we disable clone
327      */
328     private function __clone()
329     {
330     }
331
332     /**
333      * Initialization of main variables of SugarCRM in global scope
334      *
335      * @static
336      */
337     public static function init()
338     {
339         if (self::$isInited == true)
340         {
341             return true;
342         }
343
344         // initialization & backup of sugar_config
345         self::$initVars['GLOBALS']['sugar_config'] = null;
346         if ($GLOBALS['sugar_config'])
347         {
348             self::$initVars['GLOBALS']['sugar_config'] = $GLOBALS['sugar_config'];
349         }
350         if (self::$initVars['GLOBALS']['sugar_config'] == false)
351         {
352             global $sugar_config;
353             if (is_file('config.php'))
354             {
355                 require_once('config.php');
356             }
357             if (is_file('config_override.php'))
358             {
359                 require_once('config_override.php');
360             }
361             self::$initVars['GLOBALS']['sugar_config'] = $GLOBALS['sugar_config'];
362         }
363
364         // backup of current_language
365         self::$initVars['GLOBALS']['current_language'] = 'en_us';
366         if (isset($sugar_config['current_language']))
367         {
368             self::$initVars['GLOBALS']['current_language'] = $sugar_config['current_language'];
369         }
370         if (isset($GLOBALS['current_language']))
371         {
372             self::$initVars['GLOBALS']['current_language'] = $GLOBALS['current_language'];
373         }
374         $GLOBALS['current_language'] = self::$initVars['GLOBALS']['current_language'];
375
376         // backup of reload_vardefs
377         self::$initVars['GLOBALS']['reload_vardefs'] = null;
378         if (isset($GLOBALS['reload_vardefs']))
379         {
380             self::$initVars['GLOBALS']['reload_vardefs'] = $GLOBALS['reload_vardefs'];
381         }
382
383         // backup of locale
384         self::$initVars['GLOBALS']['locale'] = null;
385         if (isset($GLOBALS['locale']))
386         {
387             self::$initVars['GLOBALS']['locale'] = $GLOBALS['locale'];
388         }
389         if (self::$initVars['GLOBALS']['locale'] == false)
390         {
391             self::$initVars['GLOBALS']['locale'] = new Localization();
392         }
393
394         // backup of service_object
395         self::$initVars['GLOBALS']['service_object'] = null;
396         if (isset($GLOBALS['service_object']))
397         {
398             self::$initVars['GLOBALS']['service_object'] = $GLOBALS['service_object'];
399         }
400
401         // backup of SugarThemeRegistry
402         self::$systemVars['SugarThemeRegistry'] = SugarThemeRegistry::current();
403
404         self::$isInited = true;
405     }
406
407     /**
408      * Checking is there helper for variable or not
409      *
410      * @static
411      * @param string $varName name of global variable of SugarCRM
412      * @return bool is there helper for a variable or not
413      * @throws SugarTestHelperException fired when there is no implementation of helper for a variable
414      */
415     protected static function checkHelper($varName)
416     {
417         if (method_exists(__CLASS__, 'setUp_' . $varName) == false)
418         {
419             throw new SugarTestHelperException('setUp for $' . $varName . ' is not implemented. ' . __CLASS__ . '::setUp_' . $varName);
420         }
421     }
422
423     /**
424      * Entry point for setup of global variable
425      *
426      * @static
427      * @param string $varName name of global variable of SugarCRM
428      * @param array $params some parameters for helper. For example for $mod_strings or $current_user
429      * @return bool is variable setuped or not
430      */
431     public static function setUp($varName, $params = array())
432     {
433         self::init();
434         self::checkHelper($varName);
435         return call_user_func(__CLASS__ . '::setUp_' . $varName, $params);
436     }
437
438     /**
439      * Clean up all registered variables and restore $initVars and $systemVars
440      * @static
441      * @return bool status of tearDown
442      */
443     public static function tearDown()
444     {
445         self::init();
446         foreach(self::$registeredVars as $varName => $isCalled)
447         {
448             if ($isCalled)
449             {
450                 unset(self::$registeredVars[$varName]);
451                 if (method_exists(__CLASS__, 'tearDown_' . $varName))
452                 {
453                     call_user_func(__CLASS__ . '::tearDown_' . $varName, array());
454                 }
455                 elseif (isset($GLOBALS[$varName]))
456                 {
457                     unset($GLOBALS[$varName]);
458                 }
459             }
460         }
461
462         // Restoring of system variables
463         foreach(self::$initVars as $scope => $vars)
464         {
465             foreach ($vars as $name => $value)
466             {
467                 $GLOBALS[$scope][$name] = $value;
468             }
469         }
470
471         // Restoring of theme
472         SugarThemeRegistry::set(self::$systemVars['SugarThemeRegistry']->dirName);
473         SugarCache::$isCacheReset = false;
474         return true;
475     }
476
477     /**
478      * Registration of $current_user in global scope
479      *
480      * @static
481      * @param array $params parameters for SugarTestUserUtilities::createAnonymousUser method
482      * @return bool is variable setuped or not
483      */
484     protected static function setUp_current_user(array $params)
485     {
486         self::$registeredVars['current_user'] = true;
487         $GLOBALS['current_user'] = call_user_func_array('SugarTestUserUtilities::createAnonymousUser', $params);
488         return true;
489     }
490
491     /**
492      * Removal of $current_user from global scope
493      *
494      * @static
495      * @return bool is variable removed or not
496      */
497     protected static function tearDown_current_user()
498     {
499         SugarTestUserUtilities::removeAllCreatedAnonymousUsers();
500         unset($GLOBALS['current_user']);
501         return true;
502     }
503
504     /**
505      * Registration of $beanList in global scope
506      *
507      * @static
508      * @return bool is variable setuped or not
509      */
510     protected static function setUp_beanList()
511     {
512         self::$registeredVars['beanList'] = true;
513         global $beanList;
514         require('include/modules.php');
515         return true;
516     }
517
518     /**
519      * Registration of $beanFiles in global scope
520      *
521      * @static
522      * @return bool is variable setuped or not
523      */
524     protected static function setUp_beanFiles()
525     {
526         self::$registeredVars['beanFiles'] = true;
527         global $beanFiles;
528         require('include/modules.php');
529         return true;
530     }
531
532     /**
533      * Registration of $moduleList in global scope
534      *
535      * @static
536      * @return bool is variable setuped or not
537      */
538     protected static function setUp_moduleList()
539     {
540         self::$registeredVars['moduleList'] = true;
541         global $moduleList;
542         require('include/modules.php');
543         return true;
544     }
545
546     /**
547      * Reinitialization of $moduleList in global scope because we can't unset that variable
548      *
549      * @static
550      * @return bool is variable setuped or not
551      */
552     protected static function tearDown_moduleList()
553     {
554         return self::setUp_moduleList();
555     }
556
557     /**
558      * Registration of $modListHeader in global scope
559      *
560      * @static
561      * @return bool is variable setuped or not
562      */
563     protected static function setUp_modListHeader()
564     {
565         self::$registeredVars['modListHeader'] = true;
566         if (isset($GLOBALS['current_user']) == false)
567         {
568             self::setUp_current_user(array(
569                 true,
570                 1
571             ));
572         }
573         $GLOBALS['modListHeader'] = query_module_access_list($GLOBALS['current_user']);
574         return true;
575     }
576
577     /**
578      * Registration of $app_strings in global scope
579      *
580      * @static
581      * @return bool is variable setuped or not
582      */
583     protected static function setUp_app_strings()
584     {
585         self::$registeredVars['app_strings'] = true;
586         $GLOBALS['app_strings'] = return_application_language($GLOBALS['current_language']);
587         return true;
588     }
589
590     /**
591      * Registration of $app_list_strings in global scope
592      *
593      * @static
594      * @return bool is variable setuped or not
595      */
596     protected static function setUp_app_list_strings()
597     {
598         self::$registeredVars['app_list_strings'] = true;
599         $GLOBALS['app_list_strings'] = return_app_list_strings_language($GLOBALS['current_language']);
600         return true;
601     }
602
603     /**
604      * Registration of $timedate in global scope
605      *
606      * @static
607      * @return bool is variable setuped or not
608      */
609     protected static function setUp_timedate()
610     {
611         self::$registeredVars['timedate'] = true;
612         $GLOBALS['timedate'] = TimeDate::getInstance();
613         return true;
614     }
615
616     /**
617      * Removal of $timedate from global scope
618      *
619      * @static
620      * @return bool is variable removed or not
621      */
622     protected static function tearDown_timedate()
623     {
624         $GLOBALS['timedate']->clearCache();
625         return true;
626     }
627
628     /**
629      * Registration of $mod_strings in global scope
630      *
631      * @static
632      * @param array $params parameters for return_module_language function
633      * @return bool is variable setuped or not
634      */
635     protected static function setUp_mod_strings(array $params)
636     {
637         self::$registeredVars['mod_strings'] = true;
638         $GLOBALS['mod_strings'] = return_module_language($GLOBALS['current_language'], $params[0]);
639         return true;
640     }
641
642     /**
643      * Registration of $dictionary in global scope
644      *
645      * @static
646      * @return bool is variable setuped or not
647      */
648     protected static function setUp_dictionary()
649     {
650         self::setUp('beanFiles');
651         self::setUp('beanList');
652         self::$registeredVars['dictionary'] = true;
653
654         global $dictionary;
655         $dictionary = array();
656         $moduleInstaller = new ModuleInstaller();
657         $moduleInstaller->silent = true;
658         $moduleInstaller->rebuild_tabledictionary();
659         require 'modules/TableDictionary.php';
660
661         foreach($GLOBALS['beanList'] as $k => $v)
662         {
663             VardefManager::loadVardef($k, $v);
664         }
665         return true;
666     }
667
668     /**
669      * Reinitialization of $dictionary in global scope because we can't unset that variable
670      *
671      * @static
672      * @return bool is variable setuped or not
673      */
674     protected static function tearDown_dictionary()
675     {
676         return self::setUp_dictionary();
677     }
678
679     /**
680      * Cleaning caches and refreshing vardefs
681      *
682      * @static
683      * @param string $lhs_module left module from relation
684      * @param string $rhs_module right module from relation
685      * @return bool are caches refreshed or not
686      */
687     protected static function setUp_relation(array $params)
688     {
689         if (empty($params[0]) || empty($params[1]))
690         {
691             throw new SugarTestHelperException('setUp("relation") requires two parameters');
692         }
693         list($lhs_module, $rhs_module) = $params;
694         self::$registeredVars['relation'] = true;
695         self::$cleanModules[] = $lhs_module;
696
697         LanguageManager::clearLanguageCache($lhs_module);
698         if ($lhs_module != $rhs_module)
699         {
700             self::$cleanModules[] = $rhs_module;
701             LanguageManager::clearLanguageCache($rhs_module);
702         }
703
704         self::setUp('dictionary');
705
706         VardefManager::$linkFields = array();
707         VardefManager::clearVardef();
708         VardefManager::refreshVardefs($lhs_module, BeanFactory::getObjectName($lhs_module));
709         if ($lhs_module != $rhs_module)
710         {
711             VardefManager::refreshVardefs($rhs_module, BeanFactory::getObjectName($rhs_module));
712         }
713         SugarRelationshipFactory::rebuildCache();
714
715         return true;
716     }
717
718     /**
719      * Doing the same things like setUp but for initialized list of modules
720      *
721      * @static
722      * @return bool are caches refreshed or not
723      */
724     protected static function tearDown_relation()
725     {
726         SugarRelationshipFactory::deleteCache();
727
728         $modules = array_unique(self::$cleanModules);
729         foreach ($modules as $module)
730         {
731             LanguageManager::clearLanguageCache($module);
732         }
733
734         self::tearDown('dictionary');
735
736         VardefManager::$linkFields = array();
737         VardefManager::clearVardef();
738         foreach($modules as $module)
739         {
740             VardefManager::refreshVardefs($module, BeanFactory::getBeanName($module));
741         }
742         SugarRelationshipFactory::rebuildCache();
743
744         self::$cleanModules = array();
745         return true;
746     }
747 }