Merge branch 'wip-mdl-46514' of https://github.com/rajeshtaneja/moodle
authorDan Poltawski <dan@moodle.com>
Tue, 23 Aug 2016 07:59:24 +0000 (08:59 +0100)
committerDan Poltawski <dan@moodle.com>
Tue, 23 Aug 2016 07:59:24 +0000 (08:59 +0100)
14 files changed:
lib/behat/behat_base.php
lib/behat/lib.php
lib/setup.php
lib/testing/classes/util.php
lib/tests/behat/behat_hooks.php
lib/yui/build/moodle-core-notification-ajaxexception/moodle-core-notification-ajaxexception-debug.js
lib/yui/build/moodle-core-notification-ajaxexception/moodle-core-notification-ajaxexception-min.js
lib/yui/build/moodle-core-notification-ajaxexception/moodle-core-notification-ajaxexception.js
lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception-debug.js
lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception-min.js
lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception.js
lib/yui/src/notification/js/ajaxexception.js
lib/yui/src/notification/js/exception.js
mod/quiz/edit_rest.php

index 5276703..3fd7d2b 100644 (file)
@@ -764,6 +764,17 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
             // Joined xpath expression. Most of the time there will be no exceptions, so this pre-check
             // is faster than to send the 4 xpath queries for each step.
             if (!$this->getSession()->getDriver()->find($joinedxpath)) {
+                // Check if we have recorded any errors in driver process.
+                $phperrors = behat_get_shutdown_process_errors();
+                if (!empty($phperrors)) {
+                    foreach ($phperrors as $error) {
+                        $errnostring = behat_get_error_string($error['type']);
+                        $msgs[] = $errnostring . ": " .$error['message'] . " at " . $error['file'] . ": " . $error['line'];
+                    }
+                    $msg = "PHP errors found:\n" . implode("\n", $msgs);
+                    throw new \Exception(htmlentities($msg));
+                }
+
                 return;
             }
 
@@ -776,8 +787,20 @@ class behat_base extends Behat\MinkExtension\Context\RawMinkContext {
                 if (empty($errorinfoboxes)) {
                     $errorinfoboxes = $this->getSession()->getPage()->findAll('css', 'div.notifytiny');
                 }
-                $errorinfo = $this->get_debug_text($errorinfoboxes[0]->getHtml()) . "\n" .
-                    $this->get_debug_text($errorinfoboxes[1]->getHtml());
+
+                // If errorinfoboxes is empty, try find ajax/JS exception in dialogue.
+                if (empty($errorinfoboxes)) {
+                    $errorinfoboxes = $this->getSession()->getPage()->findAll('css', 'div.moodle-exception-message');
+
+                    // If ajax/JS exception.
+                    if ($errorinfoboxes) {
+                        $errorinfo = $this->get_debug_text($errorinfoboxes[0]->getHtml());
+                    }
+
+                } else {
+                    $errorinfo = $this->get_debug_text($errorinfoboxes[0]->getHtml()) . "\n" .
+                        $this->get_debug_text($errorinfoboxes[1]->getHtml());
+                }
 
                 $msg = "Moodle exception: " . $errormsg->getText() . "\n" . $errorinfo;
                 throw new \Exception(html_entity_decode($msg));
index 201831f..fa1a7ff 100644 (file)
@@ -84,6 +84,36 @@ function behat_error($errorcode, $text = '') {
     testing_error($errorcode, $text);
 }
 
+/**
+ * Return logical error string.
+ *
+ * @param int $errtype php error type.
+ * @return string string which will be returned.
+ */
+function behat_get_error_string($errtype) {
+    switch ($errtype) {
+        case E_USER_ERROR:
+            $errnostr = 'Fatal error';
+            break;
+        case E_WARNING:
+        case E_USER_WARNING:
+            $errnostr = 'Warning';
+            break;
+        case E_NOTICE:
+        case E_USER_NOTICE:
+        case E_STRICT:
+            $errnostr = 'Notice';
+            break;
+        case E_RECOVERABLE_ERROR:
+            $errnostr = 'Catchable';
+            break;
+        default:
+            $errnostr = 'Unknown error type';
+    }
+
+    return $errnostr;
+}
+
 /**
  * PHP errors handler to use when running behat tests.
  *
@@ -121,35 +151,57 @@ function behat_error_handler($errno, $errstr, $errfile, $errline, $errcontext) {
     // Using the default one in case there is a fatal catchable error.
     default_error_handler($errno, $errstr, $errfile, $errline, $errcontext);
 
-    switch ($errno) {
-        case E_USER_ERROR:
-            $errnostr = 'Fatal error';
-            break;
-        case E_WARNING:
-        case E_USER_WARNING:
-            $errnostr = 'Warning';
-            break;
-        case E_NOTICE:
-        case E_USER_NOTICE:
-        case E_STRICT:
-            $errnostr = 'Notice';
-            break;
-        case E_RECOVERABLE_ERROR:
-            $errnostr = 'Catchable';
-            break;
-        default:
-            $errnostr = 'Unknown error type';
-    }
+    $errnostr = behat_get_error_string($errno);
 
-    // Wrapping the output.
-    echo '<div class="phpdebugmessage" data-rel="phpdebugmessage">' . PHP_EOL;
-    echo "$errnostr: $errstr in $errfile on line $errline" . PHP_EOL;
-    echo '</div>';
+    // If ajax script then throw exception, so the calling api catch it and show it on web page.
+    if (defined('AJAX_SCRIPT')) {
+        throw new Exception("$errnostr: $errstr in $errfile on line $errline");
+    } else {
+        // Wrapping the output.
+        echo '<div class="phpdebugmessage" data-rel="phpdebugmessage">' . PHP_EOL;
+        echo "$errnostr: $errstr in $errfile on line $errline" . PHP_EOL;
+        echo '</div>';
+    }
 
     // Also use the internal error handler so we keep the usual behaviour.
     return false;
 }
 
+/**
+ * Before shutdown save last error entries, so we can fail the test.
+ */
+function behat_shutdown_function() {
+    global $DB;
+
+    // If any error found, then save it.
+    if ($error = error_get_last()) {
+        // Ignore E_WARNING, as they might come via ( @ )suppression and might lead to false failure.
+        if (isset($error['type']) && !($error['type'] & E_WARNING)) {
+            $errors = behat_get_shutdown_process_errors();
+
+            $errors[] = $error;
+            $errorstosave = json_encode($errors);
+
+            set_config('process_errors', $errorstosave, 'tool_behat');
+        }
+    }
+}
+
+/**
+ * Return php errors save which were save during shutdown.
+ *
+ * @return array
+ */
+function behat_get_shutdown_process_errors() {
+    $phperrors = get_config('tool_behat', 'process_errors');
+
+    if (!empty($phperrors)) {
+        return json_decode($phperrors, true);
+    } else {
+        return array();
+    }
+}
+
 /**
  * Restrict the config.php settings allowed.
  *
index 2972b6b..4026d1b 100644 (file)
@@ -1038,6 +1038,12 @@ if (isset($CFG->maintenance_later) and $CFG->maintenance_later <= time()) {
     }
 }
 
+// Add behat_shutdown_function to shutdown manager, so we can capture php errors,
+// but not necessary for behat CLI command as it's being captured by behat process.
+if (defined('BEHAT_SITE_RUNNING') && !defined('BEHAT_TEST')) {
+    core_shutdown_manager::register_function('behat_shutdown_function');
+}
+
 // note: we can not block non utf-8 installations here, because empty mysql database
 // might be converted to utf-8 in admin/index.php during installation
 
index a5b8b7c..1fa55b9 100644 (file)
@@ -939,12 +939,23 @@ abstract class testing_util {
         self::$tableupdated = array();
     }
 
+    /**
+     * Delete tablesupdatedbyscenario file. This should be called before suite,
+     * to ensure full db reset.
+     */
+    public static function clean_tables_updated_by_scenario_list() {
+        $tablesupdatedfile = self::get_tables_updated_by_scenario_list_path();
+        if (file_exists($tablesupdatedfile)) {
+            unlink($tablesupdatedfile);
+        }
+    }
+
     /**
      * Returns the path to the file which holds list of tables updated in scenario.
      * @return string
      */
     protected final static function get_tables_updated_by_scenario_list_path() {
-        return self::get_dataroot() . '/tablesupdatedbyscenario.txt';
+        return self::get_dataroot() . '/tablesupdatedbyscenario.json';
     }
 
     /**
index dfaf9f6..1f25c1a 100644 (file)
@@ -153,6 +153,7 @@ class behat_hooks extends behat_base {
 
         // Reset all data, before checking for check_server_status.
         // If not done, then it can return apache error, while running tests.
+        behat_util::clean_tables_updated_by_scenario_list();
         behat_util::reset_all_data();
 
         // Check if server is running and using same version for cli and apache.
index efbf363..be34b85 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-ajaxexception/moodle-core-notification-ajaxexception-debug.js and b/lib/yui/build/moodle-core-notification-ajaxexception/moodle-core-notification-ajaxexception-debug.js differ
index 22a7bcc..11bcd12 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-ajaxexception/moodle-core-notification-ajaxexception-min.js and b/lib/yui/build/moodle-core-notification-ajaxexception/moodle-core-notification-ajaxexception-min.js differ
index efbf363..be34b85 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-ajaxexception/moodle-core-notification-ajaxexception.js and b/lib/yui/build/moodle-core-notification-ajaxexception/moodle-core-notification-ajaxexception.js differ
index 91546f3..25f79ae 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception-debug.js and b/lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception-debug.js differ
index 4fb70e3..bb94ef7 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception-min.js and b/lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception-min.js differ
index 91546f3..25f79ae 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception.js and b/lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception.js differ
index 39fa89e..230f228 100644 (file)
@@ -34,7 +34,7 @@ Y.extend(AJAXEXCEPTION, M.core.notification.info, {
         this.setStdModContent(Y.WidgetStdMod.HEADER,
                 '<h1 id="moodle-dialogue-' + this.get('COUNT') + '-header-text">' + Y.Escape.html(config.name) + '</h1>',
                 Y.WidgetStdMod.REPLACE);
-        content = Y.Node.create('<div class="moodle-ajaxexception"></div>')
+        content = Y.Node.create('<div class="moodle-ajaxexception" data-rel="fatalerror"></div>')
                 .append(Y.Node.create('<div class="moodle-exception-message">' + Y.Escape.html(this.get('error')) + '</div>'))
                 .append(Y.Node.create('<div class="moodle-exception-param hidden param-debuginfo"><label>URL:</label> ' +
                         this.get('reproductionlink') + '</div>'))
index 7c5fdc4..a1b5842 100644 (file)
@@ -50,7 +50,7 @@ Y.extend(EXCEPTION, M.core.notification.info, {
         this.setStdModContent(Y.WidgetStdMod.HEADER,
                 '<h1 id="moodle-dialogue-' + config.COUNT + '-header-text">' + Y.Escape.html(config.name) + '</h1>',
                 Y.WidgetStdMod.REPLACE);
-        content = Y.Node.create('<div class="moodle-exception"></div>')
+        content = Y.Node.create('<div class="moodle-exception" data-rel="fatalerror"></div>')
                 .append(Y.Node.create('<div class="moodle-exception-message">' + Y.Escape.html(this.get('message')) + '</div>'))
                 .append(Y.Node.create('<div class="moodle-exception-param hidden param-filename"><label>File:</label> ' +
                         Y.Escape.html(this.get('fileName')) + '</div>'))
index a1a1585..6ad7fc2 100644 (file)
@@ -76,10 +76,10 @@ switch($requestmethod) {
         switch ($class) {
             case 'section':
                 $table = 'quiz_sections';
+                $section = $structure->get_section_by_id($id);
                 switch ($field) {
                     case 'getsectiontitle':
                         require_capability('mod/quiz:manage', $modcontext);
-                        $section = $structure->get_section_by_id($id);
                         echo json_encode(array('instancesection' => $section->heading));
                         break;
                     case 'updatesectiontitle':