The target audience of this post is primarily developers charged with maintaining a site on Pantheon, and who would like to offload regression testing to a machine, in this case Jenkins. The test framework used is Behat but the approach should be translatable to your framework of choice.
The ultimate goal is to have Jenkins execute Behat tests, against the appropriate Pantheon environment, whenever application code for that environment is updated.
Primary components
- The php script that Pantheon's webhook service (Quicksilver) will execute.
- A
secrets.json
file to store credentials (not in source control). - The Jenkins job.
- An entry in
pantheon.yml
that tells quicksilver what script to execute and when.
PHP webhook
First, create the webhook and confirm it can successfully trigger a job on the Jenkins server. Start by downloading a copy of Pantheon's example. The following modifications in jenkins_integration.php
might be necessary
<?php
curl_setopt($curl, CURLOPT_POSTFIELDS, array(
'token' => $secrets->token,
));
to
<?php
curl_setopt($curl, CURLOPT_POSTFIELDS, array(
'token' => $secrets['token'],
));
because $secrets
has already been json_decode()
'ed. Good opportunity for a PR :)
Also, this is not required, but useful if triggering different Jenkins jobs per environment.
$secrets = _get_secrets('secrets.json');
$secrets = $secrets['test-build'];
Its purpose is explained in the next section.
Locally put this in docroot/private/scripts/jenkins_integration.php
secrets.json
{
"slack_url": "",
"test-build": {
"jenkins_url": "",
"token": "",
"username": "",
"api_token": ""
}
}
If Quicksilver is already being used there might be other config in secrets.json
besides jenkins integration, like "slack_url": "",
for Slack notifications. Be careful not to overwrite!
"test-build": {
is an entry for a multi-dev environment. All the config specific for that multi-dev goes in here. The idea being that it's possible different environments need to use different jobs, or different Jenkins servers.
Point "jenkins_url":
at the specific job you want triggered, e.g. https://myjenkins.com/job/behat_tests_job_name/build
"token":
Grants access to trigger behat_tests_job_name
. This is defined in the Jenkins job configuration. A random 32 char alphanumeric string should suffice.
"username":
the Jenkins user recorded as triggering the build.
"api_token":
grants general access to Jenkins for "username":
. If you have admin privileges in Jenkins the api token for a user can be viewed at https://your_jenkins.com/securityRealm/user/some_user_name/configure
. Ensure the user has sufficient permission to read the job you want to build.
Put the file in docroot/files/private/secrets.json
for now.
Test by
$ cd docroot
$ php private/scripts/jenkins_integration.php
It will likely complain No secrets file found. Aborting!
, because $_SERVER['HOME']
in _get_secrets()
is not accurate. Change this to secrets.json
absolute path to confirm credentials are accurate, and then after change it back.
Once a Build queued
response is displayed, login to Jenkins dashboard, and confirm a new build was actually created.
When ready to test live upload secrets.json
to the environment via sftp (credentials are in Pantheon dashboard > Site > Environment tab > Connection Info) and
sftp> cd files sftp> mkdir private // Skip this if files/private already exists sftp> cd private sftp> put secrets.json
The Jenkins job
Create a Freestyle project. The Git plugin is useful for connecting jobs with repos. Connect to the one containing the Behat tests. This is setup under the 'Source Code Management' section of the job configuration.
An example setup with tests and Drupal application in the same repo might have the tests located at docroot/private/tests/behat
. On the Jenkins server install composer
and npm
globally to manage test dependencies.
Under the 'Build Triggers' section select the 'Trigger builds remotely' checkbox and define an Authentication Token. Make it long!
Next is a series of shell steps. Keeping most of Behat's dependencies contained to the Behat directory minimizes the amount of cruft installed globally on the Jenkins server which might be running a diverse number of jobs. Because of this the shell steps typically start with
$ cd private/tests/behat
Update dependencies
- Execute shell 1:
$ composer install
- Execute shell 2:
$ npm install
Start phantomjs (or browser of choice)
- Execute shell 3:
$ nohup node_modules/phantomjs/bin/phantomjs --webdriver=8643 &
Run Behat
- Execute shell 4:
$ bin/behat --strict &> behat_tests.txt
The Behat output is redirected to behat_tests.txt
and sent to Slack for logging. Alternatively leave it to stdout
and consult the console output of the job in the Jenkins dashboard. Note the browser, browser driver, and domain configuration for Behat are defined in behat.yml
and out of scope for this discussion.
pantheon.yml
Now that the script is able to trigger the job, and the job is able to execute the Behat tests, all that's left is the final glue instructing the Quicksilver service what to do. In docroot/pantheon.yml
include
workflows:
sync_code:
after:
- type: webphp
description: Integrate With Jenkins
script: private/scripts/jenkins_integration.php
Now after the code has been sync'ed to the Pantheon repo (a commit is pushed), Quicksilver will execute the webhook script, which will trigger the Jenkins job to kickoff testing.
Can test, and debug, this by pushing empty commits to the multi-dev branch
$ git commit --allow-empty
and watching Quicksilver output with
terminus workflow:watch
That's pretty much it. All that's left is to outline the mission critical features of your site, translate those into Behat tests, and have Jenkins run them. Now your QA team can focus on novel ways to break the application while Jenkins helps with the tedious search for regressions. Happy automating!