From b9f12678e71c5ecfcb748b7ccf6bb0a0da677840 Mon Sep 17 00:00:00 2001 From: Markus Glaser Date: Thu, 14 Oct 2010 00:06:24 +0000 Subject: [PATCH] * start / stop selenium server on Linux * credits to Dan Nessett --- maintenance/tests/RunSeleniumTests.php | 78 +++++- maintenance/tests/selenium/Selenium.php | 4 + maintenance/tests/selenium/SeleniumConfig.php | 6 +- .../tests/selenium/SeleniumServerManager.php | 228 ++++++++++++++++++ .../selenium_settings.ini.php52.sample | 2 + .../selenium/selenium_settings.ini.sample | 2 + 6 files changed, 310 insertions(+), 10 deletions(-) create mode 100644 maintenance/tests/selenium/SeleniumServerManager.php diff --git a/maintenance/tests/RunSeleniumTests.php b/maintenance/tests/RunSeleniumTests.php index 2208ff8732..44727511d6 100644 --- a/maintenance/tests/RunSeleniumTests.php +++ b/maintenance/tests/RunSeleniumTests.php @@ -29,24 +29,28 @@ define( 'SELENIUMTEST', true ); require_once( dirname( dirname( __FILE__ ) )."/Maintenance.php" ); require_once( 'PHPUnit/Framework.php' ); require_once( 'PHPUnit/Extensions/SeleniumTestCase.php' ); +require_once( dirname( __FILE__ ) . "/selenium/SeleniumServerManager.php" ); class SeleniumTester extends Maintenance { protected $selenium; + protected $serverManager; + protected $seleniumServerExecPath; public function __construct() { parent::__construct(); $this->mDescription = "Selenium Test Runner. For documentation, visit http://www.mediawiki.org/wiki/SeleniumFramework"; - $this->addOption( 'port', 'Port used by selenium server. Default: 4444' ); - $this->addOption( 'host', 'Host selenium server. Default: $wgServer . $wgScriptPath' ); - $this->addOption( 'testBrowser', 'The browser he used during testing. Default: firefox' ); - $this->addOption( 'wikiUrl', 'The Mediawiki installation to point to. Default: http://localhost' ); - $this->addOption( 'username', 'The login username for sunning tests. Default: empty' ); - $this->addOption( 'userPassword', 'The login password for running tests. Default: empty' ); - $this->addOption( 'seleniumConfig', 'Location of the selenium config file. Default: empty' ); + $this->addOption( 'port', 'Port used by selenium server. Default: 4444', false, true ); + $this->addOption( 'host', 'Host selenium server. Default: $wgServer . $wgScriptPath', false, true ); + $this->addOption( 'testBrowser', 'The browser used during testing. Default: firefox', false, true ); + $this->addOption( 'wikiUrl', 'The Mediawiki installation to point to. Default: http://localhost', false, true ); + $this->addOption( 'username', 'The login username for sunning tests. Default: empty', false, true ); + $this->addOption( 'userPassword', 'The login password for running tests. Default: empty', false, true ); + $this->addOption( 'seleniumConfig', 'Location of the selenium config file. Default: empty', false, true ); $this->addOption( 'list-browsers', 'List the available browsers.' ); $this->addOption( 'verbose', 'Be noisier.' ); - + $this->addOption( 'startserver', 'Start Selenium Server (on localhost) before the run.' ); + $this->addOption( 'stopserver', 'Stop Selenium Server (on localhost) after the run.' ); $this->deleteOption( 'dbpass' ); $this->deleteOption( 'dbuser' ); $this->deleteOption( 'globals' ); @@ -63,6 +67,47 @@ class SeleniumTester extends Maintenance { echo $desc; } + protected function startServer() { + if ( $this->seleniumServerExecPath == '' ) { + die ( "The selenium server exec path is not set in " . + "selenium_settings.ini. Cannot start server \n" . + "as requested - terminating RunSeleniumTests\n" ); + } + $this->serverManager = new SeleniumServerManager( 'true', + $this->selenium->getPort(), + $this->seleniumServerExecPath ); + switch ( $this->serverManager->start() ) { + case 'started': + break; + case 'failed': + die ( "Unable to start the Selenium Server - " . + "terminating RunSeleniumTests\n" ); + case 'running': + echo ( "Warning: The Selenium Server is " . + "already running\n" ); + break; + } + + return; + } + + protected function stopServer() { + if ( !isset ( $this->serverManager ) ) { + echo ( "Warning: Request to stop Selenium Server, but it was " . + "not stared by RunSeleniumTests\n" . + "RunSeleniumTests cannot stop a Selenium Server it " . + "did not start\n" ); + } else { + switch ( $this->serverManager->stop() ) { + case 'stopped': + break; + case 'failed': + echo ( "unable to stop the Selenium Server\n" ); + } + } + return; + } + protected function runTests( $seleniumTestSuites = array() ) { $result = new PHPUnit_Framework_TestResult; $result->addListener( new SeleniumTestListener( $this->selenium->getLogger() ) ); @@ -108,6 +153,13 @@ class SeleniumTester extends Maintenance { $seleniumTestSuites ) ); } + // State for starting/stopping the Selenium server has nothing to do with the Selenium + // class. Keep this state local to SeleniumTester class. Using getOption() is clumsy, but + // the Maintenance class does not have a setOption() + if ( isset( $seleniumSettings['startserver'] ) ) $this->getOption( 'startserver', true ); + if ( isset( $seleniumSettings['stopserver'] ) ) $this->getOption( 'stopserver', true ); + if ( !isset( $seleniumSettings['seleniumserverexecpath'] ) ) $seleniumSettings['seleniumserverexecpath'] = ''; + $this->seleniumServerExecPath = $seleniumSettings['seleniumserverexecpath']; //set reasonable defaults if we did not find the settings if ( !isset( $seleniumBrowsers ) ) $seleniumBrowsers = array ('firefox' => '*firefox'); @@ -117,7 +169,8 @@ class SeleniumTester extends Maintenance { if ( !isset( $seleniumSettings['username'] ) ) $seleniumSettings['username'] = ''; if ( !isset( $seleniumSettings['userPassword'] ) ) $seleniumSettings['userPassword'] = ''; if ( !isset( $seleniumSettings['testBrowser'] ) ) $seleniumSettings['testBrowser'] = 'firefox'; - + + // Setup Selenium class $this->selenium = new Selenium( ); $this->selenium->setAvailableBrowsers( $seleniumBrowsers ); $this->selenium->setUrl( $this->getOption( 'wikiUrl', $seleniumSettings['wikiUrl'] ) ); @@ -132,11 +185,18 @@ class SeleniumTester extends Maintenance { $this->listBrowsers(); exit(0); } + if ( $this->hasOption( 'startserver' ) ) { + $this->startServer(); + } $logger = new SeleniumTestConsoleLogger; $this->selenium->setLogger( $logger ); $this->runTests( $seleniumTestSuites ); + + if ( $this->hasOption( 'stopserver' ) ) { + $this->stopServer(); + } } } diff --git a/maintenance/tests/selenium/Selenium.php b/maintenance/tests/selenium/Selenium.php index 925d335c09..e41e673975 100644 --- a/maintenance/tests/selenium/Selenium.php +++ b/maintenance/tests/selenium/Selenium.php @@ -112,6 +112,10 @@ class Selenium { $this->port = $port; } + public function getPort() { + return $this->port; + } + public function setUser( $user ) { $this->user = $user; } diff --git a/maintenance/tests/selenium/SeleniumConfig.php b/maintenance/tests/selenium/SeleniumConfig.php index 8847cdeeb8..757bc091ff 100644 --- a/maintenance/tests/selenium/SeleniumConfig.php +++ b/maintenance/tests/selenium/SeleniumConfig.php @@ -44,7 +44,11 @@ class SeleniumConfig { $seleniumSettings['wikiUrl'] = $configArray['SeleniumSettings']['wikiUrl']; $seleniumSettings['username'] = $configArray['SeleniumSettings']['username']; $seleniumSettings['userPassword'] = $configArray['SeleniumSettings']['userPassword']; - $seleniumSettings['testBrowser'] = $configArray['SeleniumSettings']['testBrowser']; + $seleniumSettings['testBrowser'] = $configArray['SeleniumSettings']['testBrowser']; + $seleniumSettings['startserver'] = $configArray['SeleniumSettings']['startserver']; + $seleniumSettings['stopserver'] = $configArray['SeleniumSettings']['stopserver']; + $seleniumSettings['seleniumserverexecpath'] = $configArray['SeleniumSettings']['seleniumserverexecpath']; + wfRestoreWarnings(); } if ( array_key_exists( 'SeleniumTests', $configArray) ) { diff --git a/maintenance/tests/selenium/SeleniumServerManager.php b/maintenance/tests/selenium/SeleniumServerManager.php new file mode 100644 index 0000000000..e3daaff2c8 --- /dev/null +++ b/maintenance/tests/selenium/SeleniumServerManager.php @@ -0,0 +1,228 @@ + + * http://citizendium.org/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @addtogroup Maintenance + */ + +class SeleniumServerManager { + private $SeleniumStartServer = false; + private $OS = ''; + private $SeleniumServerPid = 'NaN'; + private $SeleniumServerPort = 4444; + private $SeleniumServerStartTimeout = 10; // 10 secs. + private $SeleniumServerExecPath; + + public function __construct( $startServer, + $serverPort, + $serverExecPath ) { + $this->OS = (string) PHP_OS; + if ( isset( $startServer ) ) + $this->SeleniumStartServer = $startServer; + if ( isset( $serverPort ) ) + $this->SeleniumServerPort = $serverPort; + if ( isset( $serverExecPath ) ) + $this->SeleniumServerExecPath = $serverExecPath; + return; + } + + // Getters for certain private attributes. No setters, since they + // should not change after the manager object is created. + + public function getSeleniumStartServer() { + return $this->SeleniumStartServer; + } + + public function getSeleniumServerPort() { + return $this->SeleniumServerPort; + } + + public function getSeleniumServerPid() { + return $this->SeleniumServerPid; + } + + // Changing value of SeleniumStartServer allows starting server after + // creation of the class instance. Only allow setting SeleniumStartServer + // to true, since after server is started, it is shut down by stop(). + + public function setSeleniumStartServer( $startServer ) { + if ( $startServer == true ) $this->SeleniumStartServer = true; + } + + // return values are: 1) started - server started, 2) failed - + // server not started, 3) running - instructed to start server, but + // server already running + + public function start() { + + if ( !$this->SeleniumStartServer ) return 'failed'; + + // commented out cases are untested + + switch ( $this->OS ) { + case "Linux": +# case' CYGWIN_NT-5.1': +# case 'Darwin': +# case 'FreeBSD': +# case 'HP-UX': +# case 'IRIX64': +# case 'NetBSD': +# case 'OpenBSD': +# case 'SunOS': +# case 'Unix': + // *nix based OS + return $this->startServerOnUnix(); + break; + case "Windows": + case "WIN32": + case "WINNT": + // Windows + return $this->startServerOnWindows(); + break; + default: + // An untested OS + return 'failed'; + break; + } + } + + public function stop() { + + // commented out cases are untested + + switch ( $this->OS ) { + case "Linux": +# case' CYGWIN_NT-5.1': +# case 'Darwin': +# case 'FreeBSD': +# case 'HP-UX': +# case 'IRIX64': +# case 'NetBSD': +# case 'OpenBSD': +# case 'SunOS': +# case 'Unix': + // *nix based OS + return $this->stopServerOnUnix(); + break; + case "Windows": + case "WIN32": + case "WINNT": + // Windows + return $this->stopServerOnWindows(); + break; + default: + // An untested OS + return 'failed'; + break; + } + } + + private function startServerOnUnix() { + + $output = array(); + $user = $_ENV['USER']; + exec("ps -U " . $user . " w | grep -i selenium-server", $output); + + // Start server. If there is already a server running, + // return running. + + if ( isset( $this->SeleniumServerExecPath ) ) { + $found = 0; + foreach ( $output as $string ) { + $found += preg_match( + '~^(.*)java(.+)-jar(.+)selenium-server~', + $string ); + } + if ( $found == 0 ) { + + // Didn't find the selenium server. Start it up. + // First set up comamand line suffix. + // NB: $! is pid of last job run in background + // The echo guarentees it is put into $op when + // the exec command is run. + + $commandSuffix = ' > /dev/null 2>&1'. ' & echo $!'; + $portText = ' -port ' . $this->SeleniumServerPort; + $command = "java -jar " . + $this->SeleniumServerExecPath . + $portText . $commandSuffix; + exec($command ,$op); + $pid = (int)$op[0]; + if ( $pid != "" ) + $this->SeleniumServerPid = $pid; + else { + $this->SeleniumServerPid = 'NaN'; + // Server start failed. + return 'failed'; + } + // Wait for the server to startup and listen + // on its port. Note: this solution kinda + // stinks, since it uses a wait loop - dnessett + + for ( $cnt = 1; + $cnt <= $this->SeleniumServerStartTimeout; + $cnt++ ) { + $fp = @fsockopen ( 'localhost', + $this->SeleniumServerPort, + &$errno, &$errstr, 0 ); + if ( !$fp ) { + sleep( 1 ); + continue; + // Server start succeeded. + } else { + fclose ( $fp ); + return 'started'; + } + } + echo ( "Starting Selenium server timed out.\n" ); + return 'failed'; + } + // server already running. + else return 'running'; + + } + // No Server execution path defined. + return 'failed'; + } + + private function startServerOnWindows() { + // Unimplemented. + return 'failed'; + } + + private function stopServerOnUnix() { + + if ( !empty( $this->SeleniumServerPid ) && + $this->SeleniumServerPid != 'NaN' ) { + exec( "kill -9 " . $this->SeleniumServerPid ); + return 'stopped'; + } + else return 'failed'; + } + + private function stopServerOnWindows() { + // Unimplemented. + return 'failed'; + + } +} diff --git a/maintenance/tests/selenium/selenium_settings.ini.php52.sample b/maintenance/tests/selenium/selenium_settings.ini.php52.sample index aa09240a15..7b617ea642 100644 --- a/maintenance/tests/selenium/selenium_settings.ini.php52.sample +++ b/maintenance/tests/selenium/selenium_settings.ini.php52.sample @@ -12,6 +12,8 @@ wikiUrl = "http://localhost/mediawiki/latest_trunk/trunk/phase3" username = "Wikiadmin" userPassword = "Wikiadminpw" testBrowser = "firefox" +startserver = +stopserver = [testSuite] diff --git a/maintenance/tests/selenium/selenium_settings.ini.sample b/maintenance/tests/selenium/selenium_settings.ini.sample index c27f53c2f5..3d743d8f69 100644 --- a/maintenance/tests/selenium/selenium_settings.ini.sample +++ b/maintenance/tests/selenium/selenium_settings.ini.sample @@ -9,6 +9,8 @@ wikiUrl = "http://localhost/deployment" username = "wikiuser" userPassword = "wikipass" testBrowser = "firefox" +startserver = +stopserver = [SeleniumTests] -- 2.20.1