MDL-69232 behat: Make selenium start more fault tolerant
authorAndrew Nicols <andrew@nicols.co.uk>
Wed, 8 Jul 2020 07:35:34 +0000 (15:35 +0800)
committerAndrew Nicols <andrew@nicols.co.uk>
Fri, 10 Jul 2020 00:40:29 +0000 (08:40 +0800)
The session was previously only started once, but has now been moved to
restart between each test. Because of this the `$session->start()` is
now called more frequently which exposes a pre-existing issue whereby
Selenium will periodically fail to start.

When the session was only started at the beginning of the test, and at
occasional other times, it made sense to always stop the test runner
because it signified an issue with obtaining the session at all.

Since the session is restarted more frequently, and now between every
test, it no longer makes sense to do this. The test should only be
_stopped_ if the first attempt to obtain the Session fails. Once a
Session has been retrieved at least once it no longer makes sense to
assume that the failure was a configuration failure, but a connection
failure. Therefore subsequent tests should be attempted.

lib/tests/behat/behat_hooks.php

index d9ee40a..b5b12a1 100644 (file)
@@ -293,6 +293,21 @@ class behat_hooks extends behat_base {
         }
     }
 
         }
     }
 
+    /**
+     * Helper function to restart the Mink session.
+     */
+    protected function restart_session(): void {
+        $session = $this->getSession();
+        if ($session->isStarted()) {
+            $session->restart();
+        } else {
+            $session->start();
+        }
+        if ($this->running_javascript() && $this->getSession()->getDriver()->getWebDriverSessionId() === 'session') {
+            throw new DriverException('Unable to create valid session');
+        }
+    }
+
     /**
      * Resets the test environment.
      *
     /**
      * Resets the test environment.
      *
@@ -302,33 +317,35 @@ class behat_hooks extends behat_base {
     public function before_scenario(BeforeScenarioScope $scope) {
         global $DB, $CFG;
 
     public function before_scenario(BeforeScenarioScope $scope) {
         global $DB, $CFG;
 
-        $moreinfo = 'More info in ' . behat_command::DOCS_URL;
-        $driverexceptionmsg = 'Selenium server is not running, you need to start it to run tests that involve Javascript. ' . $moreinfo;
-        try {
-            $session = $this->getSession();
-            if (!$session->isStarted()) {
-                $session->start();
+        if (self::$initprocessesfinished) {
+            $this->restart_session();
+        } else {
+            $moreinfo = 'More info in ' . behat_command::DOCS_URL;
+            $driverexceptionmsg = 'Selenium server is not running, you need to start it to run tests that involve Javascript. ' . $moreinfo;
+
+            try {
+                $this->restart_session();
+            } catch (CurlExec $e) {
+                // Exception thrown by WebDriver, so only @javascript tests will be caugth; in
+                // behat_util::check_server_status() we already checked that the server is running.
+                throw new behat_stop_exception(
+                    $driverexceptionmsg . '. ' .
+                    $e->getMessage() . "\n\n" .
+                    format_backtrace($e->getTrace(), true)
+                );
+            } catch (DriverException $e) {
+                throw new behat_stop_exception(
+                    $driverexceptionmsg . '. ' .
+                    $e->getMessage() . "\n\n" .
+                    format_backtrace($e->getTrace(), true)
+                );
+            } catch (UnknownError $e) {
+                // Generic 'I have no idea' Selenium error. Custom exception to provide more feedback about possible solutions.
+                throw new behat_stop_exception(
+                    $e->getMessage() . "\n\n" .
+                    format_backtrace($e->getTrace(), true)
+                );
             }
             }
-        } catch (CurlExec $e) {
-            // Exception thrown by WebDriver, so only @javascript tests will be caugth; in
-            // behat_util::check_server_status() we already checked that the server is running.
-            throw new behat_stop_exception(
-                $driverexceptionmsg . '. ' .
-                $e->getMessage() . "\n\n" .
-                format_backtrace($e->getTrace(), true)
-            );
-        } catch (DriverException $e) {
-            throw new behat_stop_exception(
-                $driverexceptionmsg . '. ' .
-                $e->getMessage() . "\n\n" .
-                format_backtrace($e->getTrace(), true)
-            );
-        } catch (UnknownError $e) {
-            // Generic 'I have no idea' Selenium error. Custom exception to provide more feedback about possible solutions.
-            throw new behat_stop_exception(
-                $e->getMessage() . "\n\n" .
-                format_backtrace($e->getTrace(), true)
-            );
         }
 
         $suitename = $scope->getSuite()->getName();
         }
 
         $suitename = $scope->getSuite()->getName();
@@ -364,9 +381,6 @@ class behat_hooks extends behat_base {
 
         }
 
 
         }
 
-        // Reset mink session between the scenarios.
-        $session->reset();
-
         // Reset $SESSION.
         \core\session\manager::init_empty_session();
 
         // Reset $SESSION.
         \core\session\manager::init_empty_session();