Merge "Script calling cleanups"
[lhc/web/wiklou.git] / tests / RunSeleniumTests.php
1 #!/usr/bin/env php
2 <?php
3 /**
4 * @file
5 * @ingroup Maintenance
6 * @copyright Copyright © Wikimedia Deuschland, 2009
7 * @author Hallo Welt! Medienwerkstatt GmbH
8 * @author Markus Glaser, Dan Nessett, Priyanka Dhanda
9 * initial idea by Daniel Kinzler
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 * http://www.gnu.org/copyleft/gpl.html
25 */
26
27 if ( PHP_SAPI != 'cli' ) {
28 die( "Run me from the command line please.\n" );
29 }
30
31 define( 'SELENIUMTEST', true );
32
33 require( __DIR__ . '/../maintenance/Maintenance.php' );
34
35 require_once( 'PHPUnit/Runner/Version.php' );
36 if ( version_compare( PHPUnit_Runner_Version::id(), '3.5.0', '>=' ) ) {
37 # PHPUnit 3.5.0 introduced a nice autoloader based on class name
38 require_once( 'PHPUnit/Autoload.php' );
39 } else {
40 # Keep the old pre PHPUnit 3.5.0 behaviour for compatibility
41 require_once( 'PHPUnit/TextUI/Command.php' );
42 }
43
44 require_once( 'PHPUnit/Extensions/SeleniumTestCase.php' );
45 include_once( 'PHPUnit/Util/Log/JUnit.php' );
46
47 require_once( __DIR__ . "/selenium/SeleniumServerManager.php" );
48
49 class SeleniumTester extends Maintenance {
50 protected $selenium;
51 protected $serverManager;
52 protected $seleniumServerExecPath;
53
54 public function __construct() {
55 parent::__construct();
56 $this->mDescription = "Selenium Test Runner. For documentation, visit http://www.mediawiki.org/wiki/SeleniumFramework";
57 $this->addOption( 'port', 'Port used by selenium server. Default: 4444', false, true );
58 $this->addOption( 'host', 'Host selenium server. Default: $wgServer . $wgScriptPath', false, true );
59 $this->addOption( 'testBrowser', 'The browser used during testing. Default: firefox', false, true );
60 $this->addOption( 'wikiUrl', 'The Mediawiki installation to point to. Default: http://localhost', false, true );
61 $this->addOption( 'username', 'The login username for sunning tests. Default: empty', false, true );
62 $this->addOption( 'userPassword', 'The login password for running tests. Default: empty', false, true );
63 $this->addOption( 'seleniumConfig', 'Location of the selenium config file. Default: empty', false, true );
64 $this->addOption( 'list-browsers', 'List the available browsers.' );
65 $this->addOption( 'verbose', 'Be noisier.' );
66 $this->addOption( 'startserver', 'Start Selenium Server (on localhost) before the run.' );
67 $this->addOption( 'stopserver', 'Stop Selenium Server (on localhost) after the run.' );
68 $this->addOption( 'jUnitLogFile', 'Log results in a specified JUnit log file. Default: empty', false, true );
69 $this->addOption( 'runAgainstGrid', 'The test will be run against a Selenium Grid. Default: false.', false, true );
70 $this->deleteOption( 'dbpass' );
71 $this->deleteOption( 'dbuser' );
72 $this->deleteOption( 'globals' );
73 $this->deleteOption( 'wiki' );
74 }
75
76 public function listBrowsers() {
77 $desc = "Available browsers:\n";
78
79 foreach ( $this->selenium->getAvailableBrowsers() as $k => $v ) {
80 $desc .= " $k => $v\n";
81 }
82
83 echo $desc;
84 }
85
86 protected function startServer() {
87 if ( $this->seleniumServerExecPath == '' ) {
88 die ( "The selenium server exec path is not set in " .
89 "selenium_settings.ini. Cannot start server \n" .
90 "as requested - terminating RunSeleniumTests\n" );
91 }
92 $this->serverManager = new SeleniumServerManager( 'true',
93 $this->selenium->getPort(),
94 $this->seleniumServerExecPath );
95 switch ( $this->serverManager->start() ) {
96 case 'started':
97 break;
98 case 'failed':
99 die ( "Unable to start the Selenium Server - " .
100 "terminating RunSeleniumTests\n" );
101 case 'running':
102 echo ( "Warning: The Selenium Server is " .
103 "already running\n" );
104 break;
105 }
106
107 return;
108 }
109
110 protected function stopServer() {
111 if ( !isset ( $this->serverManager ) ) {
112 echo ( "Warning: Request to stop Selenium Server, but it was " .
113 "not stared by RunSeleniumTests\n" .
114 "RunSeleniumTests cannot stop a Selenium Server it " .
115 "did not start\n" );
116 } else {
117 switch ( $this->serverManager->stop() ) {
118 case 'stopped':
119 break;
120 case 'failed':
121 echo ( "unable to stop the Selenium Server\n" );
122 }
123 }
124 return;
125 }
126
127 protected function runTests( $seleniumTestSuites = array() ) {
128 $result = new PHPUnit_Framework_TestResult;
129 $result->addListener( new SeleniumTestListener( $this->selenium->getLogger() ) );
130 if ( $this->selenium->getJUnitLogFile() ) {
131 $jUnitListener = new PHPUnit_Util_Log_JUnit( $this->selenium->getJUnitLogFile(), true );
132 $result->addListener( $jUnitListener );
133 }
134
135 foreach ( $seleniumTestSuites as $testSuiteName => $testSuiteFile ) {
136 require( $testSuiteFile );
137 $suite = new $testSuiteName();
138 $suite->setName( $testSuiteName );
139 $suite->addTests();
140
141 try {
142 $suite->run( $result );
143 } catch ( Testing_Selenium_Exception $e ) {
144 $suite->tearDown();
145 throw new MWException( $e->getMessage() );
146 }
147 }
148
149 if ( $this->selenium->getJUnitLogFile() ) {
150 $jUnitListener->flush();
151 }
152 }
153
154 public function execute() {
155 global $wgServer, $wgScriptPath, $wgHooks;
156
157 $seleniumSettings = array();
158 $seleniumBrowsers = array();
159 $seleniumTestSuites = array();
160
161 $configFile = $this->getOption( 'seleniumConfig', '' );
162 if ( strlen( $configFile ) > 0 ) {
163 $this->output( "Using Selenium Configuration file: " . $configFile . "\n" );
164 SeleniumConfig::getSeleniumSettings( $seleniumSettings,
165 $seleniumBrowsers,
166 $seleniumTestSuites,
167 $configFile );
168 } elseif ( !isset( $wgHooks['SeleniumSettings'] ) ) {
169 $this->output( "No command line, configuration file or configuration hook found.\n" );
170 SeleniumConfig::getSeleniumSettings( $seleniumSettings,
171 $seleniumBrowsers,
172 $seleniumTestSuites
173 );
174 } else {
175 $this->output( "Using 'SeleniumSettings' hook for configuration.\n" );
176 wfRunHooks( 'SeleniumSettings', array( $seleniumSettings,
177 $seleniumBrowsers,
178 $seleniumTestSuites ) );
179 }
180
181 // State for starting/stopping the Selenium server has nothing to do with the Selenium
182 // class. Keep this state local to SeleniumTester class. Using getOption() is clumsy, but
183 // the Maintenance class does not have a setOption()
184 if ( !isset( $seleniumSettings['startserver'] ) ) {
185 $this->getOption( 'startserver', true );
186 }
187 if ( !isset( $seleniumSettings['stopserver'] ) ) {
188 $this->getOption( 'stopserver', true );
189 }
190 if ( !isset( $seleniumSettings['seleniumserverexecpath'] ) ) {
191 $seleniumSettings['seleniumserverexecpath'] = '';
192 }
193 $this->seleniumServerExecPath = $seleniumSettings['seleniumserverexecpath'];
194
195 //set reasonable defaults if we did not find the settings
196 if ( !isset( $seleniumBrowsers ) ) {
197 $seleniumBrowsers = array( 'firefox' => '*firefox' );
198 }
199 if ( !isset( $seleniumSettings['host'] ) ) {
200 $seleniumSettings['host'] = $wgServer . $wgScriptPath;
201 }
202 if ( !isset( $seleniumSettings['port'] ) ) {
203 $seleniumSettings['port'] = '4444';
204 }
205 if ( !isset( $seleniumSettings['wikiUrl'] ) ) {
206 $seleniumSettings['wikiUrl'] = 'http://localhost';
207 }
208 if ( !isset( $seleniumSettings['username'] ) ) {
209 $seleniumSettings['username'] = '';
210 }
211 if ( !isset( $seleniumSettings['userPassword'] ) ) {
212 $seleniumSettings['userPassword'] = '';
213 }
214 if ( !isset( $seleniumSettings['testBrowser'] ) ) {
215 $seleniumSettings['testBrowser'] = 'firefox';
216 }
217 if ( !isset( $seleniumSettings['jUnitLogFile'] ) ) {
218 $seleniumSettings['jUnitLogFile'] = false;
219 }
220 if ( !isset( $seleniumSettings['runAgainstGrid'] ) ) {
221 $seleniumSettings['runAgainstGrid'] = false;
222 }
223
224 // Setup Selenium class
225 $this->selenium = new Selenium();
226 $this->selenium->setAvailableBrowsers( $seleniumBrowsers );
227 $this->selenium->setRunAgainstGrid( $this->getOption( 'runAgainstGrid', $seleniumSettings['runAgainstGrid'] ) );
228 $this->selenium->setUrl( $this->getOption( 'wikiUrl', $seleniumSettings['wikiUrl'] ) );
229 $this->selenium->setBrowser( $this->getOption( 'testBrowser', $seleniumSettings['testBrowser'] ) );
230 $this->selenium->setPort( $this->getOption( 'port', $seleniumSettings['port'] ) );
231 $this->selenium->setHost( $this->getOption( 'host', $seleniumSettings['host'] ) );
232 $this->selenium->setUser( $this->getOption( 'username', $seleniumSettings['username'] ) );
233 $this->selenium->setPass( $this->getOption( 'userPassword', $seleniumSettings['userPassword'] ) );
234 $this->selenium->setVerbose( $this->hasOption( 'verbose' ) );
235 $this->selenium->setJUnitLogFile( $this->getOption( 'jUnitLogFile', $seleniumSettings['jUnitLogFile'] ) );
236
237 if ( $this->hasOption( 'list-browsers' ) ) {
238 $this->listBrowsers();
239 exit( 0 );
240 }
241 if ( $this->hasOption( 'startserver' ) ) {
242 $this->startServer();
243 }
244
245 $logger = new SeleniumTestConsoleLogger;
246 $this->selenium->setLogger( $logger );
247
248 $this->runTests( $seleniumTestSuites );
249
250 if ( $this->hasOption( 'stopserver' ) ) {
251 $this->stopServer();
252 }
253 }
254 }
255
256 $maintClass = "SeleniumTester";
257
258 require_once( RUN_MAINTENANCE_IF_MAIN );