Effective behat command
authorFrederic Massart <fred@moodle.com>
Tue, 19 Feb 2013 01:39:13 +0000 (09:39 +0800)
committerFrederic Massart <fred@moodle.com>
Tue, 19 Feb 2013 01:39:13 +0000 (09:39 +0800)
README.md
config-dist.json
extra/bash_completion
lib/moodle.py
lib/tools.py
moodle-behat.py

index 4869f50..2dbe778 100644 (file)
--- a/README.md
+++ b/README.md
@@ -122,6 +122,13 @@ Restore the second backup of the instance stable_master
 
     mdk backup --restore stable_master_02
 
+
+behat
+-----
+
+Get the instance ready for acceptance testing (Behat).
+
+
 check
 -----
 
index 037f97b..2b47096 100644 (file)
     "git": "/usr/bin/git",
     // Path to PHP
     "php": "/usr/bin/php",
+    // Path to Java
+    "java": "/usr/bin/java",
 
     // Experimental setting to use a local cache as your upstream remotes.
     // Can be useful to prevent fetch from a slow remote.
index 27fd890..fac4ce4 100644 (file)
@@ -44,7 +44,7 @@ function _moodle() {
     if [[ "${COMP_CWORD}" == 1 ]]; then
         # List the commands and aliases.
         # Ignoring these commands on purpose: init
-        OPTS="alias backport backup check config create fix info install phpunit purge pull push rebase remove run update upgrade"
+        OPTS="alias backport backup behat check config create fix info install phpunit purge pull push rebase remove run update upgrade"
         OPTS="$OPTS $($BIN alias list | cut -d ':' -f 1)"
     else
         # List of options according to the command.
@@ -73,6 +73,10 @@ function _moodle() {
                     OPTS="$OPTS $($BIN info -ln)"
                 fi
                 ;;
+            behat)
+                OPTS="--run --switch-completely --no-javascript --selenium"
+                OPTS="$OPTS $($BIN info -ln)"
+                ;;
             check)
                 # Empty options.
                 ;;
index e1a827f..c315079 100644 (file)
@@ -254,9 +254,15 @@ class Moodle(object):
 
     def initBehat(self, switchcompletely=False):
         """Initialise the Behat environment"""
+
         if self.branch_compare(25, '<'):
             raise Exception('Behat is only available from Moodle 2.5')
 
+        # Force switch completely for PHP < 5.4
+        (none, phpVersion, none) = process('%s -r "echo version_compare(phpversion(), \'5.4\');"' % (C.get('php')))
+        if int(phpVersion) <= 0:
+            switchcompletely = True
+
         # Set Behat data root
         behat_dataroot = self.get('dataroot') + '_behat'
         if self.get('behat_dataroot') == None:
@@ -266,7 +272,7 @@ class Moodle(object):
         if not os.path.isdir(behat_dataroot):
             os.mkdir(behat_dataroot, 0777)
 
-        # Set PHPUnit prefix
+        # Set Behat DB prefix
         behat_prefix = 'behat_'
         if self.get('behat_prefix') == None:
             self.addConfig('behat_prefix', behat_prefix)
@@ -310,19 +316,22 @@ class Moodle(object):
                 pass
             return result
 
+        # Force a cache purge
+        self.purge()
+
         # Not really proud of this logic, but it works for now. Ideally there shouldn't be any duplicated call to enable().
         result = enable()
         if result[0] == 251:
             raise Exception('Error: Behat requires PHP 5.4 or the flag --switch-completely to be set')
-        elif result[0] == 253:
-            # Need to drop the tables
-            drop()
+        elif result[0] == 254:
+            # Installation required
             installResult = install()
             if installResult[0] != 0:
                 raise Exception('Unknown error while installing Behat. \nError code: %s\nStdout: %s\nStderr: %s' % (result))
             result = enable()
-        elif result[0] == 254:
-            # Installation required
+        elif result[0] > 0:
+            # Need to drop the tables
+            drop()
             installResult = install()
             if installResult[0] != 0:
                 raise Exception('Unknown error while installing Behat. \nError code: %s\nStdout: %s\nStderr: %s' % (result))
index 0eab3c8..15d69ec 100644 (file)
@@ -27,6 +27,7 @@ import os
 import subprocess
 import shlex
 import re
+import threading
 
 
 def yesOrNo(q):
@@ -111,3 +112,17 @@ def stableBranch(version):
     if version == 'master':
         return 'master'
     return 'MOODLE_%d_STABLE' % int(version)
+
+
+class ProcessInThread(threading.Thread):
+    """Executes a process in a separate thread"""
+
+    cli = None
+    loop = True
+
+    def __init__(self, cli):
+        threading.Thread.__init__(self)
+        self.cli = cli
+
+    def run(self):
+        process(self.cli)
index a85991e..c6de9c1 100755 (executable)
@@ -23,8 +23,12 @@ http://github.com/FMCorz/mdk
 """
 import sys
 import argparse
+import os
+import urllib
+import re
+from time import sleep
 from lib import workplace
-from lib.tools import debug, process
+from lib.tools import debug, process, ProcessInThread
 from lib.config import Conf
 
 C = Conf()
@@ -33,7 +37,8 @@ C = Conf()
 parser = argparse.ArgumentParser(description='Initialise Behat')
 parser.add_argument('-r', '--run', action='store_true', help='run the tests')
 parser.add_argument('-j', '--no-javascript', action='store_true', help='skip the tests involving Javascript', dest='nojavascript')
-parser.add_argument('-s', '--switch-completely', action='store_true', help='enable for compatibility with PHP < 5.4', dest='switchcompletely')
+parser.add_argument('-s', '--switch-completely', action='store_true', help='force the switch completely setting. This will be automatically enabled for PHP < 5.4', dest='switchcompletely')
+parser.add_argument('--selenium', metavar='jarfile', nargs='?', default=None, help='path to the selenium standalone server to use', dest='selenium')
 parser.add_argument('name', metavar='name', default=None, nargs='?', help='name of the instance')
 args = parser.parse_args()
 
@@ -50,19 +55,73 @@ if not M.get('installed'):
     debug('This instance needs to be installed first')
     sys.exit(1)
 
+# If not composer.phar, install Composer
+if not os.path.isfile(os.path.join(M.get('path'), 'composer.phar')):
+    debug('Installing Composer')
+    cliFile = 'behat_install_composer.php'
+    cliPath = os.path.join(M.get('path'), 'behat_install_composer.php')
+    urllib.urlretrieve('http://getcomposer.org/installer', cliPath)
+    M.cli('/' + cliFile, stdout=None)
+    os.remove(cliPath)
+    M.cli('composer.phar', args='install --dev')
+
+# Download selenium
+seleniumPath = os.path.expanduser(os.path.join(C.get('dirs.mdk'), 'selenium.jar'))
+if args.selenium:
+    seleniumPath = args.selenium
+elif not os.path.isfile(seleniumPath):
+    debug('Attempting to find a download for Selenium')
+    url = urllib.urlopen('http://docs.seleniumhq.org/download/')
+    content = url.read()
+    selenium = re.search(r'http:[a-z0-9/._-]+selenium-server-standalone-[0-9.]+\.jar', content, re.I)
+    if selenium:
+        debug('Downloading Selenium from %s' % (selenium.group(0)))
+        urllib.urlretrieve(selenium.group(0), seleniumPath)
+    else:
+        debug('Could not locate Selenium server to download')
+
+if not os.path.isfile(seleniumPath):
+    debug('Selenium file %s does not exist')
+    sys.exit(1)
+
 # Run cli
 try:
     M.initBehat(switchcompletely=args.switchcompletely)
     debug('Behat ready!')
+
+    # Preparing Behat command
+    cmd = ['vendor/bin/behat']
+    if args.nojavascript:
+        cmd.append('--tags ~@javascript')
+    cmd.append('--config=%s/behat/behat.yml' % (M.get('behat_dataroot')))
+    cmd = ' '.join(cmd)
+
     if args.run:
+        debug('Preparing Behat testing')
+
+        # Preparing PHP Server
+        phpServer = None
+        if not M.get('behat_switchcompletely'):
+            debug('Starting standalone PHP server')
+            phpServer = ProcessInThread('%s -S http://localhost:8000' % (C.get('php')))
+            phpServer.start()
+
+        # Launching Selenium
+        seleniumServer = None
+        if seleniumPath and not args.nojavascript:
+            debug('Starting Selenium server')
+            seleniumServer = ProcessInThread('%s -jar %s' % (C.get('java'), seleniumPath))
+            seleniumServer.start()
+
         debug('Running Behat tests')
-        cmd = ['vendor/bin/behat']
-        if args.nojavascript:
-            cmd.append('--tags ~@javascript')
-        cmd.append('--config=%s/behat/behat.yml' % (M.get('behat_dataroot')))
-        cmd = ' '.join(cmd)
-        debug(' %s' % cmd)
+        # Sleep for a few seconds before starting Behat
+        if phpServer or seleniumServer:
+            sleep(3)
+
         process(cmd, M.path, None, None)
+    else:
+        debug('Behat command: %s' % (cmd))
+
 except Exception as e:
     debug(e)
     sys.exit(1)