Recently I set up Bitbucket Pipelines as CI for the DEITY Magento API module (background: DEITY: Technical Overview)

This was an interesting challenge, since I usually only run unit tests and integration tests on platforms like Bitbucket Pipelines, Travis CI or Wercker, and these do not need a functional web server. But for a module that only exists to extend the REST API, API functional tests are essential and the API functional test framework of Magento needs to make real HTTP requests using cURL.

Choosing a Magento Docker Image

With Bitbucket Pipelines you can choose any docker image as base image where the builds are executed. Additional docker images can be added as services (e.g. a database). It’s the same concept as in Wercker, which I like to use for Magento extensions hosted on Github.

I found the markoshust/magento-php image (previously “mageinferno/magento2-php”) image a good base for integration tests, together with a MySQL service. But for some reason the Bitbucket Pipeline scripts were never executed in the image. No error message, just “Build setup” and “Build teardown” without anything in between. I could not figure out why and how to solve it (if you have any idea, please let me know), but going back to the old mageinferno image worked, so here’s the main image:

Unlike the new one, this is missing a few packages to be able to install Magento and run tests within the container, so this goes into the script block:

For MySQL, the official image sometimes caused trouble with “MySQL server has gone away” errors during the Magento installation. It can be fixed by MySQL configuration (described in https://github.com/magento/magento2/issues/2805), but we cannot deploy custom MySQL configuration to the service, so I use our own image with adjusted configuration, integernet/mysql_ci.

In Bitbucket Pipelines, exposed ports of the services and the main image are automatically forwarded, so they can access each other at 127.0.0.1:$PORT.

This is the setup that works for integration tests, but now we also need a web server. Naturally the first thing I tried is to add markoshust/magento-nginx as additional service. However, unlike with docker-compose, services in Bitbucket Pipelines or Wercker share a network, but cannot share volumes. All we can do to configure a service is setting environment variables, there’s no way to deploy code and configuration to the nginx container.

PHP Built-in Webserver

Luckily, there is a simple alternative: PHP contains a built-in webserver for development purposes, and Magento comes with configuration for it out of the box (see https://github.com/magento/magento2/tree/2.2-develop/phpserver).

It works well for the API tests. Start the web server after the Magento installation step, not immediately before running the API tests, otherwise they start before the web server is up and running. With the following command it starts in the background and listens on port 8082:

Use http://127.0.0.1:8082/index.php/ as base URL in the Magento installation and in the phpunit.xml configuration for the api-functional test suite.

Pipelines Configuration

For reference, here’s the full bitbucket-pipelines.yml configuration file:

I moved all commands for Magento installation and test execution into a separate script, bin/pipelines-test.sh

Script: Installation

Let’s walk through the script to install Magento with the module to test and to execute the tests.

First we set some environment variables:

The database credentials are the same as configured in bitbucket-pipelines.yml. We need two additional environment variables so that composer can access the Magento repository: MAGENTO_REPO_PUBLIC_KEY and MAGENTO_REPO_PRIVATE_KEY. As repository admin in Bitbucket you can define private environment variables for pipelines in the project setting, so we added them there instead of in the repository.

Next, we create a temporary branch in the module repository, which is already checked out in the version that should be tested:

We will refer to this branch later to install the module from the local repository with composer.

For the Magento installation we download the pre-built repositories from Nexcess (like the Mageinferno image in its install script), but you could also use composer create-project. Afterwards, the Magento installation is finished with the setup:install command:

Now it’s time to add our own module:

First we add the Magento keys (if you use composer create-project, you should have done this before). Then we tell composer where to find the local repository and install the module from the temporary branch. Finally the module is enabled and setup scripts are executed. This step is not necessary for integration tests which run on a separate database with all modules enabled by default, but for the functional tests it is.

Before we start the tests, we need to update the PHPUnit configuration for each test suite. The repository contains configuration files with some placeholders (like DB_HOST), we copy them over to the Magento installation and replace the placeholders:

Find details about the test configuration files in the section “Test Configuration” below.

Script: Test

The second part of the pipelines-test.sh script is actually running the tests:

Bitbucket Pipelines will pick up test logs from the test-reports directory to display the summary of successful and failed tests.

Test Configuration

For the API functional tests, two configuration files are needed: install-config-mysql.php and phpunit.xml. For the MySQL configuration copy the original file from dev/tests/api-functional/install-config-mysql.php.dist and change the following values (these are the placeholders that will be replaced by our script):

For the PHPUnit configuration, copy the original file from dev/tests/api-functional/phpunit.xml.dist and change the test suite definition (i.e. remove the core test suite and add your own):

Adjust the paths within vendor to match your own module and the location of its tests and source.

Also, change the TESTS_BASE_URL value:

For integration tests it’s almost the same.

What about Gitlab? Travis? [Insert your favorite build platform]?

The script can be used on any other platform, just the setup of the image and services might look differently. As mentioned before, Wercker works very similar, Gitlab Pipelines as well. For platforms that don’t allow building on a specific docker image and additional docker images as services, you will need a different setup to have a system where Magento can be installed: Basically that’s PHP 7 with the required PHP extensions and MySQL.

Fabian Schmengler

Author: Fabian Schmengler

Fabian Schmengler is Magento developer and trainer at integer_net. His focus lies in backend development, conceptual design and test automation.

Fabian was repeatedly selected as a Magento Master in 2017 and 2018 based on his engagements, active participation on StackExchange and contributions to the Magento 2 core.

More Information · Twitter · GitHub