Difference between revisions of "Selenium.class.php"

From Organic Design wiki
m
m
 
(6 intermediate revisions by the same user not shown)
Line 1: Line 1:
<?php
+
{{legacy}}
 +
<source lang="php"><?php
 
/**
 
/**
 
  * Selenium extension
 
  * Selenium extension
  * {{php}}
+
  *
 
  * See http://www.mediawiki.org/Extension:Selenium for installation and usage details
 
  * See http://www.mediawiki.org/Extension:Selenium for installation and usage details
 
  * See http://www.organicdesign.co.nz/Extension_talk:Selenium.php for development notes and disucssion
 
  * See http://www.organicdesign.co.nz/Extension_talk:Selenium.php for development notes and disucssion
Line 15: Line 16:
  
 
class Selenium {
 
class Selenium {
+
 
 +
var $testCount = array(); # keep track of number of tests in each suite processed
 +
 
 
function __construct() {
 
function __construct() {
 
global $wgParser, $egSeleniumTag;
 
global $wgParser, $egSeleniumTag;
Line 21: Line 24:
 
# Add the tag hook
 
# Add the tag hook
 
$wgParser->setHook($egSeleniumTag, array($this, 'tagSelenium'));
 
$wgParser->setHook($egSeleniumTag, array($this, 'tagSelenium'));
+
 
 
# Check the schedule and see if any test-runs should be spawned
 
# Check the schedule and see if any test-runs should be spawned
 
$this->checkSchedule();
 
$this->checkSchedule();
Line 31: Line 34:
 
*/
 
*/
 
public function tagSelenium($text, &$argv, &$parser) {
 
public function tagSelenium($text, &$argv, &$parser) {
global $egSeleniumCategory;
+
global $wgOut, $egSeleniumSuiteCat, $egSeleniumTestCat;
  
 +
# The suite being processed is the article title text, keep track of number of tests in it
 +
$suite = $parser->mTitle->getPrefixedText();
 +
$this->testCount[$suite] = array_key_exists($suite, $this->testCount) ? $this->testCount[$suite]+1 : 1;
 +
 
# Get name of test from title tag
 
# Get name of test from title tag
 
$name = preg_match("|<title>(.+?)</title>|i", $text, $match) ? $match[1] : 'untitled';
 
$name = preg_match("|<title>(.+?)</title>|i", $text, $match) ? $match[1] : 'untitled';
Line 40: Line 47:
 
$text = preg_replace("#\\s*</?t?(html|head|body)>\\s*#i", "", $text);
 
$text = preg_replace("#\\s*</?t?(html|head|body)>\\s*#i", "", $text);
  
# Categorise the article into Selenium tests category
+
# Categorise the article into Selenium tests category if more than one test in this suite
$text .= "[[Category:$egSeleniumCategory]]";
+
# - todo: and also remove from the cat for individual tests
 +
if ($this->testCount[$suite] > 1) $text .= "[[Category:$egSeleniumSuiteCat]]";
  
# Parse the content normally and return wrapped in a div of class selenium
+
# Parse the content normally and return wrapped in a div of class selenium and id of test name
$text = $parser->parse($text, $parser->mTitle, $parser->mOptions, false, false)->getText();
+
$out = $parser->parse($text, $parser->mTitle, $parser->mOptions, false, false);
return "<div class=\"selenium\" id=\"$name\">$text</div><!-- selenium end -->";
+
$text = $out->getText();
 +
return "<div class=\"selenium\" id=\"$name\">$text</div><!-- selenium-end -->";
 
}
 
}
  
 
/**
 
/**
* Check whether any tests should run and spawn them if so
+
* Extract the individual tests from the suite indexed by name in selenese HTML format
 +
* - also add the selenese HTML for the whole suite under index of suite name
 
*/
 
*/
public function checkSchedule() {
+
public static function selenese($suite, $path = false) {
 +
global $wgParser;
 +
 
 +
# Get the content of the suite article and parse it
 +
# NOTE: parsing the content results in the head, body, thead, tbody etc being removed,
 +
#      but it seems that the TestRunner doesn't care and can work with the basic table structure
 +
$suiteTitle = Title::newFromText($suite);
 +
$suiteArticle = new Article($suiteTitle);
 +
$text = $wgParser->parse($suiteArticle->getContent(), $suiteTitle, new ParserOptions(), true, true)->getText();
 +
 
 +
# extract the name and content of the individual tests in the suite
 +
$numTests = preg_match_all(
 +
"|<div class=\"selenium\" id=\"(.+?)\">\\s*(.+?)\\s*</div><!-- selenium-end -->|is",
 +
$text,
 +
$matches,
 +
PREG_PATTERN_ORDER
 +
);
 +
 
 +
# Re-organise the matched test content into a hash indexed by test name
 +
$tests = array();
 +
for ($i = 0; $i < $numTests; $i++) $tests[$matches[1][$i]] = $matches[2][$i];
 +
 +
# Create the HTML for the entire suite under index of suite name
 +
$html = "<html><head><meta content=\"text/html; charset=ISO-8859-1\" http-equiv=\"content-type\">
 +
<title>Selenium</title></head><body><table cellpadding=\"1\" cellspacing=\"1\" border=\"1\">
 +
<tbody><tr><td><b>$suite</b></td></tr>\n";
 +
$title = Title::makeTitle(NS_SPECIAL, 'Selenium');
 +
foreach (array_keys($tests) as $test) {
 +
$url = $path ? "$path/wiki-".urlencode($test).".html" : $title->getLocalURL("suite=$suite&test=$test");
 +
$html .= "<tr><td><a href=\"$url\">$test</a></td></tr>\n";
 +
}
 +
$tests[$suite] = "$html</tbody></table></body></html>";
 +
 +
return $tests;
 
}
 
}
  
 
/**
 
/**
* Spawn a thread to run a test suite and report if failure
+
* Check whether any tests should run
 
*/
 
*/
public function spawnTestRunner() {
+
public function checkSchedule() {
 +
global $egSeleniumSchdeule;
 +
if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'runtests') $this->runTests();
 +
$ts = date('H:i');
 +
if (in_array($ts, $egSeleniumSchdeule)) {
 +
$ts = date('d M Y').", $ts";
 +
 
 +
# Get the last log entry
 +
 
 +
# If tests for this time and day haven't run yet, run them now
 +
if ("Last log entry time stamp not equal to current") $this->runTests();
 +
}
 
}
 
}
  
 
/**
 
/**
* Notify a user about a test failure
+
* Run all the tests in the schedule in Selenium Remote Control (SRC)
 
*/
 
*/
public function failureNotification() {
+
public function runTests() {
 +
global $IP, $egSeleniumSchedule, $egSeleniumPath, $egSeleniumDir;
 +
 +
# Update the log with tests start message
 +
 +
# Define paths for the java server, the HTML test files and the results file
 +
$jar  = "$egSeleniumDir/selenium-server/selenium-server.jar";
 +
$tests = "$egSeleniumDir/selenium-core/tests";
 +
$out  = "$egSeleniumDir/selenium-core/tests/results.txt";
 +
 
 +
# We need to flip the operation to work by domain on the outer loop
 +
# - because it needs to build a set of selenese suite/test files for each site
 +
#  since the parser-functions used in the tests must be resolved my the wiki being tested
 +
 
 +
foreach ($egSeleniumSchedule as $suite => $domains) if (!is_numeric($suite)) {
 +
$es = urlencode($suite);
 +
 
 +
# Copy the suite and its tests as selenese HTML into the place SRC expects to find them
 +
foreach (Selenium::selenese($suite, "/selenium-server/tests") as $k => $v) {
 +
$ek = urlencode($k);
 +
file_put_contents("$tests/wiki-$ek.html", $v);
 +
}
 +
 
 +
# Run the suite for each domain
 +
foreach ($domains as $domain) {
 +
shell_exec("java -jar $jar -htmlSuite \"*custom /usr/bin/firefox\" \"$domain\" \"$tests/wiki-$es.html\" \"$out\"");
 +
$results = file_get_contents($out);
 +
}
 +
}
 +
 +
# Update the log with test results
 
}
 
}
  
Line 73: Line 157:
 
}
 
}
 
}
 
}
 +
</source>

Latest revision as of 14:56, 27 February 2020

Legacy.svg Legacy: This article describes a concept that has been superseded in the course of ongoing development on the Organic Design wiki. Please do not develop this any further or base work on this concept, this is only useful for a historic record of work done. You may find a link to the currently used concept or function in this article, if not you can contact the author to find out what has taken the place of this legacy item.
<?php
/**
 * Selenium extension
 *
 * See http://www.mediawiki.org/Extension:Selenium for installation and usage details
 * See http://www.organicdesign.co.nz/Extension_talk:Selenium.php for development notes and disucssion
 * 
 * @package MediaWiki
 * @subpackage Extensions
 * @author Marcus Davy [http://www.organicdesign.co.nz/User:Sven User:Sven]
 * @copyright © 2007 Marcus Davy
 * @licence GNU General Public Licence 2.0 or later
 */
if (!defined('MEDIAWIKI')) die('Not an entry point.');

class Selenium {

	var $testCount = array(); # keep track of number of tests in each suite processed

	function __construct() {
		global $wgParser, $egSeleniumTag;

		# Add the tag hook
		$wgParser->setHook($egSeleniumTag, array($this, 'tagSelenium'));

		# Check the schedule and see if any test-runs should be spawned
		$this->checkSchedule();
	}

	/**
	 * Process a selenium tag with test syntax in it
	 * - this tag also handles the categorisation of the article into Category:Selenium
	 */
	public function tagSelenium($text, &$argv, &$parser) {
		global $wgOut, $egSeleniumSuiteCat, $egSeleniumTestCat;

		# The suite being processed is the article title text, keep track of number of tests in it
		$suite = $parser->mTitle->getPrefixedText();
		$this->testCount[$suite] = array_key_exists($suite, $this->testCount) ? $this->testCount[$suite]+1 : 1;
		
		# Get name of test from title tag
		$name = preg_match("|<title>(.+?)</title>|i", $text, $match) ? $match[1] : 'untitled';

		# Get rid of unwanted tags
		$text = preg_replace("#\\s*<head>.+</head>\\s*#is", "", $text);
		$text = preg_replace("#\\s*</?t?(html|head|body)>\\s*#i", "", $text);

		# Categorise the article into Selenium tests category if more than one test in this suite
		# - todo: and also remove from the cat for individual tests
		if ($this->testCount[$suite] > 1) $text .= "[[Category:$egSeleniumSuiteCat]]";

		# Parse the content normally and return wrapped in a div of class selenium and id of test name
		$out = $parser->parse($text, $parser->mTitle, $parser->mOptions, false, false);
		$text = $out->getText();
		return "<div class=\"selenium\" id=\"$name\">$text</div><!-- selenium-end -->";
	}

	/**
	 * Extract the individual tests from the suite indexed by name in selenese HTML format
	 * - also add the selenese HTML for the whole suite under index of suite name
	 */
	public static function selenese($suite, $path = false) {
		global $wgParser;

		# Get the content of the suite article and parse it
		# NOTE: parsing the content results in the head, body, thead, tbody etc being removed,
		#       but it seems that the TestRunner doesn't care and can work with the basic table structure
		$suiteTitle = Title::newFromText($suite);
		$suiteArticle = new Article($suiteTitle);
		$text = $wgParser->parse($suiteArticle->getContent(), $suiteTitle, new ParserOptions(), true, true)->getText();

		# extract the name and content of the individual tests in the suite
		$numTests = preg_match_all(
			"|<div class=\"selenium\" id=\"(.+?)\">\\s*(.+?)\\s*</div><!-- selenium-end -->|is",
			$text,
			$matches,
			PREG_PATTERN_ORDER
		);

		# Re-organise the matched test content into a hash indexed by test name
		$tests = array();
		for ($i = 0; $i < $numTests; $i++) $tests[$matches[1][$i]] = $matches[2][$i];
		
		# Create the HTML for the entire suite under index of suite name
		$html = "<html><head><meta content=\"text/html; charset=ISO-8859-1\" http-equiv=\"content-type\">
			<title>Selenium</title></head><body><table cellpadding=\"1\" cellspacing=\"1\" border=\"1\">
			<tbody><tr><td><b>$suite</b></td></tr>\n";
		$title = Title::makeTitle(NS_SPECIAL, 'Selenium');
		foreach (array_keys($tests) as $test) {
			$url = $path ? "$path/wiki-".urlencode($test).".html" : $title->getLocalURL("suite=$suite&test=$test");
			$html .= "<tr><td><a href=\"$url\">$test</a></td></tr>\n";
		}
		$tests[$suite] = "$html</tbody></table></body></html>";
		
		return $tests;
	}

	/**
	 * Check whether any tests should run
	 */
	public function checkSchedule() {
		global $egSeleniumSchdeule;
		if (isset($_REQUEST['action']) && $_REQUEST['action'] == 'runtests') $this->runTests();
		$ts = date('H:i');
		if (in_array($ts, $egSeleniumSchdeule)) {
			$ts = date('d M Y').", $ts";

			# Get the last log entry

			# If tests for this time and day haven't run yet, run them now
			if ("Last log entry time stamp not equal to current") $this->runTests();
		}
	}

	/**
	 * Run all the tests in the schedule in Selenium Remote Control (SRC)
	 */
	public function runTests() {
		global $IP, $egSeleniumSchedule, $egSeleniumPath, $egSeleniumDir;
		
		# Update the log with tests start message
		
		# Define paths for the java server, the HTML test files and the results file
		$jar   = "$egSeleniumDir/selenium-server/selenium-server.jar";
		$tests = "$egSeleniumDir/selenium-core/tests";
		$out   = "$egSeleniumDir/selenium-core/tests/results.txt";

		# We need to flip the operation to work by domain on the outer loop
		# - because it needs to build a set of selenese suite/test files for each site
		#   since the parser-functions used in the tests must be resolved my the wiki being tested

		foreach ($egSeleniumSchedule as $suite => $domains) if (!is_numeric($suite)) {
			$es = urlencode($suite);

			# Copy the suite and its tests as selenese HTML into the place SRC expects to find them
			foreach (Selenium::selenese($suite, "/selenium-server/tests") as $k => $v) {
				$ek = urlencode($k);
				file_put_contents("$tests/wiki-$ek.html", $v);
			}

			# Run the suite for each domain
			foreach ($domains as $domain) {
				shell_exec("java -jar $jar -htmlSuite \"*custom /usr/bin/firefox\" \"$domain\" \"$tests/wiki-$es.html\" \"$out\"");
				$results = file_get_contents($out);
			}
		}
		
		# Update the log with test results
	}

	/**
	 * Needed in some versions to prevent Special:Version from breaking
	 */
	private function __toString() {
		return __CLASS__;
	}
}