Jenkins Integration Testing for Plugin Development

Jump to: navigation, search

This article describes how to use a Jenkins continuous integration server for automating PHPUnit and Behat tests for Moodle and Moodle plugins. The configuration uses Moodle's way of running PHPUnit and Behat tests using the command line.

Integration scenario: We are developing a Moodle plugin. We want to run automated tests, ensuring that it runs correctly on multiple Moodle platform versions, e.g., Moodle 2.7 and Moodle 2.8. This is motivated by the fact that we announce compatibility with these versions in the Moodle plugin directory, and we want to - at least - know, when a plugin becomes incompatible with an older version or needs to be changed. Since we are only running one recent Moodle version for development, automated tests with other versions are useful for us.

Prerequisites for this manual: Ubuntu-based integration server, headless (i.e. without a graphical environment), here: Ubuntu 14.04.

Installation of required software

  • Install Jenkins as a Ubuntu native package, as described on their website (instructions currently at http://pkg.jenkins-ci.org/debian/).
  • Install a Moodle runtime environment. A web server is not needed, since PHP 5's standalone server will be used. The following commands were used for our system:

sudo apt-get install postgresql<br />
sudo apt-get install php5-cli php-pear php5-curl php5-pgsql php5-gd php5-intl

  • Install git, which will be used to obtain the sources of Moodle and of your plugin.
sudo apt-get install git

  • For acceptance tests, you need to use a browser. Therefore you need to be able to run graphical applications. On headless servers (i.e. those without a display), you can install Xvfb, emulating a display which will be used by your browser.
sudo apt-get install xvfb firefox

  • Furthermore, acceptance tests require the Selenium standalone server to be installed. Download from http://www.seleniumhq.org/download/ (here: Version 2.45.0) and unpack it at a jenkins-accessible location, e.g. $JENKINS_HOME/selenium (here: /var/lib/jenkins/selenium).

Basic configuration of Jenkins using the shell

  • Configuration of the init script can be found at
    /etc/default/jenkins
    . It is not strictly necessary to change anything here, but we set
    HTTP_PORT=-1
    and added
    HTTPS_PORT=8998
    to make the server only via HTTPS. In that case, you also need to add
    --httpsPort=$HTTPS_PORT
    to the
    JENKINS_ARGS
    variable and restart Jenkins.
  • Furthermore, Moodle requires a
    config.php
    which is not contained in a repository. Therefore, configuration files need to be stored at a separate location, from where they can be pulled in. For our scenario, we stored the configuration file at
    $JENKINS_HOME/moodle-config/config_$target.php
    , where $target indicates a Moodle branch to build against (e.g., /var/lib/jenkins/moodle-config/config_MOODLE_28_STABLE.php).

Jenkins server configuration

For all following steps you need to open Jenkins in your browser.

Install or update the following plugins:

  • Xvfb plugin
  • Multiple SCMs plugin
  • Matrix project plugin
  • JUnit plugin
  • GitHub plugin
  • Job Configuration History Plugin (optional, but very useful)

Configure Jenkins in the following way (Manage Jenkins → Configure System):

  • Git
    • Add a git installation. Choose an arbitrary name and set the path to
      git
  • Git plugin
    • Set the fields
      Global Config user.name Value
      and
      Global Config user.email Value
      . In our case, we set those values to account and e-mail of a technical GitHub account that is only used by the Jenkins server

Create a job for your integration scenario:

  • On the dashboard, select New Item.
  • Choose Multi-configuration project and define an Item name without any spaces.
  • On the next page, define the following settings (Change to your requirements. Remember our integration scenario described above!):
    • GitHub project: URL to the web page of your repository
    • Source Code management:
      • Choose
        Multiple SCMs
        .
      • Use
        Add SCM
        to add two git repositories.
      • For the first repository,
        • set the URL to
          git://git.moodle.org/moodle.git
          .
        • Since this is a public repository, credentials are not required.
        • Under Additional Behaviours, add
          Advanced clone behaviours
          and check the option
          Shallow clone
          .
      • For the second repository,
        • set the URL to the URL of your git repository.
        • If this is a private repository, add credentials for accessing it (consider SSH authentication!)
        • Under Additional Behaviours, add
          Check out to a sub-directory
          and, for
          Local subdirectory for repo
          , enter the path where you would deploy your module in a usual Moodle installation (e.g.,
          mod/yourmodule
          ), without surrounding slashes.
        • Under Additional Behaviours, add
          Advanced clone behaviours
          and check the option
          Shallow clone
          .
    • Build Triggers:
      • Check Build when a change is pushed to GitHub.
      • Check Poll SCM. As a schedule, define e.g.
        H/5 * * * *
        for polling every five minutes.
    • Configuration Matrix:
      • Add two user-defined axes.
        • For the first axis, set name to
          target
          and values to
          MOODLE_28_STABLE MOODLE_27_STABLE
          . These values correspond to the branch names used in the Moodle repository.
        • For the second axis, set name to
          testtype
          and values to
          UnitTest BehatTest
          . These are used later on to perform different test types - be patient :).
      • Check Run each configuration sequentially.
    • Build Environment:
      • Check Start Xvfb before the build, and shut it down after.
    • Build:
      • Add Execute shell
        • Enter the following commands (Note that we use
          $target
          here, which always holds the current value of
          target
          in a particular configuration. Furthermore, this copies an appropriate config.php file into the current workspace):

git checkout $target;<br />
curl -s https://getcomposer.org/installer | php;<br />
php composer.phar install --prefer-source;<br />
cp $JENKINS_HOME/moodle-config/config_$target.php config.php;

  • Add Conditional step (single)
    • Run?:
      Strings match
      , String 1:
      ${testtype}
      , String 2:
      UnitTest
      (the motivation is that this command is only run for unit tests. In contrast, the other step will be for behat acceptance tests).
    • Builder:
      Execute shell
    • Enter the following commands:

mkdir -p ../moodledata/phpunit;<br />
php admin/tool/phpunit/cli/init.php;<br />
vendor/bin/phpunit --log-junit results/phpunit/phpunit.xml --group mod_ratingallocate || true;

  • Add Conditional step (single)
    • Run?:
      Strings match
      , String 1:
      ${testtype}
      , String 2:
      BehatTest
      .
    • Builder:
      Execute shell
    • Enter the following commands (replace
      [SeleniumVersion]
      ,
      [ModuleTag]
      , and
      [JobName]
      accordingly):

mkdir -p ../moodledata/behat;<br />
php admin/tool/behat/cli/init.php;<br />
java -jar /var/lib/jenkins/selenium/selenium-server-standalone-[SeleniumVersion].jar &gt; /dev/null 2&gt;&amp;1 &amp;<br />
SELENIUM_PID=$!<br />
php -S localhost:8000 &gt; /dev/null 2&gt;&amp;1 &amp;<br />
PHP_PID=$!<br />
vendor/bin/behat --config /var/lib/jenkins/jobs/[JobName]/workspace/target/moodledata/behat/behat/behat.yml --tags '@[ModuleTag]' --format moodle_progress,junit --out ,behatlog || true;<br />
kill $SELENIUM_PID<br />
kill $PHP_PID

  • Post-build Actions:
    • Add Publish JUnit test result report
      • Change the pattern for
        Test report XMLs
        to the value
        **/phpunit/phpunit.xml,**/behatlog/*.xml
  • Save the configuration and start the first build to test it.