Index: drupal_web_test_case.php
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/simpletest/Attic/drupal_web_test_case.php,v
retrieving revision 1.3.2.6
diff -u -r1.3.2.6 drupal_web_test_case.php
--- drupal_web_test_case.php 16 Dec 2009 02:39:11 -0000 1.3.2.6
+++ drupal_web_test_case.php 16 Dec 2009 04:19:16 -0000
@@ -189,12 +189,12 @@
/**
* Delete an assertion record by message ID.
- *
+ *
* @param $message_id
* Message ID of the assertion to delete.
* @return
* TRUE if the assertion was deleted, FALSE otherwise.
- *
+ *
* @see DrupalTestCase::insertAssert()
*/
public static function deleteAssert($message_id) {
@@ -423,7 +423,8 @@
$username = variable_get('simpletest_username', NULL);
$password = variable_get('simpletest_password', NULL);
if ($username && $password) {
- $this->httpauth_credentials = $username . ':' . $password;
+ $this->httpauth_username = $username;
+ $this->httpauth_password = $password;
}
set_error_handler(array($this, 'errorHandler'));
@@ -609,6 +610,14 @@
* Test case for typical Drupal tests.
*/
class DrupalWebTestCase extends DrupalTestCase {
+
+ /**
+ * Browser instance.
+ *
+ * @var object
+ */
+ protected $browser;
+
/**
* The URL currently loaded in the internal browser.
*
@@ -700,6 +709,7 @@
*/
function __construct($test_id = NULL) {
parent::__construct($test_id);
+
$this->skipClasses[__CLASS__] = TRUE;
}
@@ -1249,136 +1259,63 @@
if ($this->originalLanguageDefault) {
$GLOBALS['conf']['language_default'] = $this->originalLanguageDefault;
}
-
- // Close the CURL handler.
- $this->curlClose();
}
}
/**
- * Initializes the cURL connection.
- *
- * If the simpletest_httpauth_credentials variable is set, this function will
- * add HTTP authentication headers. This is necessary for testing sites that
- * are protected by login credentials from public access.
- * See the description of $curl_options for other options.
+ * Initialize browser.
*/
- protected function curlInitialize() {
- global $base_url, $db_prefix;
+ protected function browserInitialize() {
+ global $db_prefix;
- if (!isset($this->curlHandle)) {
- $this->curlHandle = curl_init();
- $curl_options = $this->additionalCurlOptions + array(
- CURLOPT_COOKIEJAR => $this->cookieFile,
- CURLOPT_URL => $base_url,
- CURLOPT_FOLLOWLOCATION => TRUE,
- CURLOPT_MAXREDIRS => 5,
- CURLOPT_RETURNTRANSFER => TRUE,
- CURLOPT_SSL_VERIFYPEER => FALSE, // Required to make the tests run on https.
- CURLOPT_SSL_VERIFYHOST => FALSE, // Required to make the tests run on https.
- CURLOPT_HEADERFUNCTION => array(&$this, 'curlHeaderCallback'),
- );
- if (isset($this->httpauth_credentials)) {
- $curl_options[CURLOPT_USERPWD] = $this->httpauth_credentials;
+ if (!isset($this->browser)) {
+ module_load_include('inc', 'browser');
+ $this->browser = new Browser();
+ $this->browser->setPageListener(array($this, 'browserPageListener'));
+
+ if (isset($this->httpauth_username)) {
+ $this->browser->setHttpAuthentication($this->httpauth_username, $this->httpauth_password);
}
- curl_setopt_array($this->curlHandle, $this->additionalCurlOptions + $curl_options);
// By default, the child session name should be the same as the parent.
- $this->session_name = session_name();
+ $this->session_name = session_name(); // TODO
}
- // We set the user agent header on each request so as to use the current
- // time and a new uniqid.
+
+ // Generate a user agent based on the db prefix.
if (preg_match('/simpletest\d+/', $db_prefix, $matches)) {
- curl_setopt($this->curlHandle, CURLOPT_USERAGENT, drupal_generate_test_ua($matches[0]));
+ $this->browser->setUserAgent(drupal_generate_test_ua($matches[0]));
}
+
+ $this->browser->setRequestHeaders(array());
+ return $this->browser;
}
/**
- * Performs a cURL exec with the specified options after calling curlConnect().
- *
- * @param $curl_options
- * Custom cURL options.
- * @return
- * Content returned from the exec.
+ * Browser page callback.
*/
- protected function curlExec($curl_options) {
- $this->curlInitialize();
- $url = empty($curl_options[CURLOPT_URL]) ? curl_getinfo($this->curlHandle, CURLINFO_EFFECTIVE_URL) : $curl_options[CURLOPT_URL];
- if (!empty($curl_options[CURLOPT_POST])) {
- // This is a fix for the Curl library to prevent Expect: 100-continue
- // headers in POST requests, that may cause unexpected HTTP response
- // codes from some webservers (like lighttpd that returns a 417 error
- // code). It is done by setting an empty "Expect" header field that is
- // not overwritten by Curl.
- $curl_options[CURLOPT_HTTPHEADER][] = 'Expect:';
- }
- curl_setopt_array($this->curlHandle, $this->additionalCurlOptions + $curl_options);
-
- // Reset headers and the session ID.
- $this->session_id = NULL;
- $this->headers = array();
-
- $this->drupalSetContent(curl_exec($this->curlHandle), curl_getinfo($this->curlHandle, CURLINFO_EFFECTIVE_URL));
+ public function browserPageListener(array $state, Browser $browser) {
$message_vars = array(
- '!method' => !empty($curl_options[CURLOPT_NOBODY]) ? 'HEAD' : (empty($curl_options[CURLOPT_POSTFIELDS]) ? 'GET' : 'POST'),
- '@url' => $url,
- '@status' => curl_getinfo($this->curlHandle, CURLINFO_HTTP_CODE),
- '!length' => format_size(strlen($this->content))
+ '!method' => $browser->getMethod(),
+ '@url' => $state['url'],
+ '@status' => $state['code'],
+ '!length' => format_size(strlen($state['content'])),
);
$message = t('!method @url returned @status (!length).', $message_vars);
- $this->assertTrue($this->content !== FALSE, $message, t('Browser'));
- return $this->drupalGetContent();
- }
-
- /**
- * Reads headers and registers errors received from the tested site.
- *
- * @see _drupal_log_error().
- *
- * @param $curlHandler
- * The cURL handler.
- * @param $header
- * An header.
- */
- protected function curlHeaderCallback($curlHandler, $header) {
- $this->headers[] = $header;
+ $this->assertTrue($this->browser->getContent() !== FALSE, $message, t('Browser'));
- // Errors are being sent via X-Drupal-Assertion-* headers,
- // generated by _drupal_log_error() in the exact form required
- // by DrupalWebTestCase::error().
- if (preg_match('/^X-Drupal-Assertion-[0-9]+: (.*)$/', $header, $matches)) {
- // Call DrupalWebTestCase::error() with the parameters from the header.
- call_user_func_array(array(&$this, 'error'), unserialize(urldecode($matches[1])));
+ if ($browser->getMethod() == 'GET') {
+ $this->verbose('GET request to: ' . $this->path .
+ '
Ending URL: ' . $state['url'] .
+ '' . $state['content']);
}
-
- // Save cookies.
- if (preg_match('/^Set-Cookie: ([^=]+)=(.+)/', $header, $matches)) {
- $name = $matches[1];
- $parts = array_map('trim', explode(';', $matches[2]));
- $value = array_shift($parts);
- $this->cookies[$name] = array('value' => $value, 'secure' => in_array('secure', $parts));
- if ($name == $this->session_name) {
- if ($value != 'deleted') {
- $this->session_id = $value;
- }
- else {
- $this->session_id = NULL;
- }
- }
+ else {
+ $this->verbose('POST request to: ' . $this->path .
+ 'Ending URL: ' . $state['url'] .
+ 'Fields: ' . highlight_string('browser->getPost(), TRUE), TRUE) .
+ '' . $state['content']);
}
- // This is required by cURL.
- return strlen($header);
- }
-
- /**
- * Close the cURL handler and unset the handler.
- */
- protected function curlClose() {
- if (isset($this->curlHandle)) {
- curl_close($this->curlHandle);
- unset($this->curlHandle);
- }
+ $this->path = '[previous]';
}
/**
@@ -1420,22 +1357,18 @@
* The retrieved HTML string, also available as $this->drupalGetContent()
*/
protected function drupalGet($path, array $options = array(), array $headers = array()) {
+ $this->path = $path;
+
+ // The browser requires the URL to be absolute.
$options['absolute'] = TRUE;
- // We re-using a CURL connection here. If that connection still has certain
- // options set, it might change the GET into a POST. Make sure we clear out
- // previous options.
- $out = $this->curlExec(array(CURLOPT_HTTPGET => TRUE, CURLOPT_URL => url($path, $options), CURLOPT_NOBODY => FALSE, CURLOPT_HTTPHEADER => $headers));
- $this->refreshVariables(); // Ensure that any changes to variables in the other thread are picked up.
-
- // Replace original page output with new output from redirected page(s).
- if (($new = $this->checkForMetaRefresh())) {
- $out = $new;
- }
- $this->verbose('GET request to: ' . $path .
- 'Ending URL: ' . $this->getUrl() .
- '' . $out);
- return $out;
+ // Make the GET request.
+ $state = $this->browserInitialize()->get(url($path, $options));
+
+ // Ensure that any changes to variables in the other thread are picked up.
+ $this->refreshVariables();
+
+ return $state['content'];
}
/**
@@ -1501,81 +1434,28 @@
* "name: value".
*/
protected function drupalPost($path, $edit, $submit, array $options = array(), array $headers = array()) {
- $submit_matches = FALSE;
- $ajax = is_array($submit);
- if (isset($path)) {
- $html = $this->drupalGet($path, $options);
- }
- if ($this->parse()) {
- $edit_save = $edit;
- // Let's iterate over all the forms.
- $forms = $this->xpath('//form');
- foreach ($forms as $form) {
- // We try to set the fields of this form as specified in $edit.
- $edit = $edit_save;
- $post = array();
- $upload = array();
- $submit_matches = $this->handleForm($post, $edit, $upload, $ajax ? NULL : $submit, $form);
- $action = isset($form['action']) ? $this->getAbsoluteUrl($form['action']) : $this->getUrl();
- if ($ajax) {
- $action = $this->getAbsoluteUrl(!empty($submit['path']) ? $submit['path'] : 'system/ajax');
- // AJAX callbacks verify the triggering element if necessary, so while
- // we may eventually want extra code that verifies it in the
- // handleForm() function, it's not currently a requirement.
- $submit_matches = TRUE;
- }
+ $this->path = $path;
- // We post only if we managed to handle every field in edit and the
- // submit button matches.
- if (!$edit && $submit_matches) {
- $post_array = $post;
- if ($upload) {
- // TODO: cURL handles file uploads for us, but the implementation
- // is broken. This is a less than elegant workaround. Alternatives
- // are being explored at #253506.
- foreach ($upload as $key => $file) {
- $file = drupal_realpath($file);
- if ($file && is_file($file)) {
- $post[$key] = '@' . $file;
- }
- }
- }
- else {
- foreach ($post as $key => $value) {
- // Encode according to application/x-www-form-urlencoded
- // Both names and values needs to be urlencoded, according to
- // http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1
- $post[$key] = urlencode($key) . '=' . urlencode($value);
- }
- if ($ajax && isset($submit['triggering_element'])) {
- $post['ajax_triggering_element'] = 'ajax_triggering_element=' . urlencode($submit['triggering_element']);
- }
- $post = implode('&', $post);
- }
- $out = $this->curlExec(array(CURLOPT_URL => $action, CURLOPT_POST => TRUE, CURLOPT_POSTFIELDS => $post, CURLOPT_HTTPHEADER => $headers));
- // Ensure that any changes to variables in the other thread are picked up.
- $this->refreshVariables();
-
- // Replace original page output with new output from redirected page(s).
- if (($new = $this->checkForMetaRefresh())) {
- $out = $new;
- }
- $this->verbose('POST request to: ' . $path .
- 'Ending URL: ' . $this->getUrl() .
- 'Fields: ' . highlight_string('' . $out);
- return $out;
- }
- }
- // We have not found a form which contained all fields of $edit.
- foreach ($edit as $name => $value) {
- $this->fail(t('Failed to set field @name to @value', array('@name' => $name, '@value' => $value)));
- }
- if (!$ajax) {
- $this->assertTrue($submit_matches, t('Found the @submit button', array('@submit' => $submit)));
- }
- $this->fail(t('Found the requested form fields at @path', array('@path' => $path)));
+ // The browser requires the URL to be absolute.
+ $options['absolute'] = TRUE;
+
+ $this->browserInitialize();
+
+ foreach ($headers as $header) {
+ $parts = explode(':', $header);
+ $this->browser->setRequestHeader(trim($parts[0]), trim($parts[1]));
+ }
+ $state = $this->browser->post(url($path, $options), $edit, $submit);
+
+ if ($state) {
+ // Ensure that any changes to variables in the other thread are picked up.
+ $this->refreshVariables();
+
+ return $state['content'];
}
+
+ $this->fail(t('Found the requested form fields at [@path]', array('@path' => $path)));
+ return FALSE;
}
/**
@@ -1593,28 +1473,6 @@
}
/**
- * Check for meta refresh tag and if found call drupalGet() recursively. This
- * function looks for the http-equiv attribute to be set to "Refresh"
- * and is case-sensitive.
- *
- * @return
- * Either the new page content or FALSE.
- */
- protected function checkForMetaRefresh() {
- if (strpos($this->drupalGetContent(), 'parse()) {
- $refresh = $this->xpath('//meta[@http-equiv="Refresh"]');
- if (!empty($refresh)) {
- // Parse the content attribute of the meta tag for the format:
- // "[delay]: URL=[page_to_redirect_to]".
- if (preg_match('/\d+;\s*URL=(?P.*)/i', $refresh[0]['content'], $match)) {
- return $this->drupalGet($this->getAbsoluteUrl(decode_entities($match['url'])));
- }
- }
- }
- return FALSE;
- }
-
- /**
* Retrieves only the headers for a Drupal path or an absolute path.
*
* @param $path
@@ -1628,156 +1486,18 @@
* The retrieved headers, also available as $this->drupalGetContent()
*/
protected function drupalHead($path, array $options = array(), array $headers = array()) {
+ $this->path = $path;
+
+ // The browser requires the URL to be absolute.
$options['absolute'] = TRUE;
- $out = $this->curlExec(array(CURLOPT_NOBODY => TRUE, CURLOPT_URL => url($path, $options), CURLOPT_HTTPHEADER => $headers));
- $this->refreshVariables(); // Ensure that any changes to variables in the other thread are picked up.
- return $out;
- }
- /**
- * Handle form input related to drupalPost(). Ensure that the specified fields
- * exist and attempt to create POST data in the correct manner for the particular
- * field type.
- *
- * @param $post
- * Reference to array of post values.
- * @param $edit
- * Reference to array of edit values to be checked against the form.
- * @param $submit
- * Form submit button value.
- * @param $form
- * Array of form elements.
- * @return
- * Submit value matches a valid submit input in the form.
- */
- protected function handleForm(&$post, &$edit, &$upload, $submit, $form) {
- // Retrieve the form elements.
- $elements = $form->xpath('.//input|.//textarea|.//select');
- $submit_matches = FALSE;
- foreach ($elements as $element) {
- // SimpleXML objects need string casting all the time.
- $name = (string) $element['name'];
- // This can either be the type of or the name of the tag itself
- // for