This is the setup for a Vagrant instance that can be used for testing and development of the extension.

Initial setup

The usual setup is as described on mw:MediaWiki-Vagrant, and yes you need Git

mkdir ~/picklespace
cd ~/picklespace
git clone --recursive .
vagrant roles enable pickle
vagrant up # first “up” will do a provision

The first vagrant up will provision and start the instance.

Additional tweaks for the guest


If you get complaints about missing locales, usually from perl, then the problem is most likely missing locales in the vagrant box. Tunnel into the box with vagrant ssh and first check if /etc/ssh/sshd_config has a line AcceptEnv LANG LC_*, if it is commented then uncomment the line. Then do

sudo locale-gen nb_NO
sudo locale-gen nb_NO.UTF-8

Replace nb_NO with whatever locale that works for you. Then do

sudo dpkg-reconfigure locales
sudo update-locale LANG=nb_NO.UTF-8

Update & Upgrade

Make sure everything is updated

vagrant ssh
sudo apt-get update && sudo apt-get upgrade

Now reload the vagrant instance

vagrant reload

Git update

At this point you should do a vagrant git-update in the host directory, otherwise you will probably run into problems later. Then do a vagrant reload to make sure everything works.

At this point you should clean up the client for outdated apt packages. Do a

vagrant ssh
sudo apt-get autoremove

Note that this still leaves the box running old software, and you should do a sudo apt-get update && sudo apt-get upgrade from time to time.

Resource allocations

Vagrant resources

It could be interesting to adjust the amount of memory and number of CPU cores used during testing. Such resource allocations are described on mw:MediaWiki-Vagrant#Adjust the resources allocated to the VM? Especially note the code snippet for ~/picklespace/Vagrantfile-extra.rb.

Vagrant.configure('2') do |config|
  config.vm.provider :virtualbox do |vb|
    # See for additional options.
    vb.customize ['modifyvm', :id, '--memory', '1536']
    vb.customize ['modifyvm', :id, '--cpus', '2']

To restart the instance do vagrant reload.

If the memory is too low, then the test run in guest will end in a fork failed. When that happen, increase the memory until the test runs ok. With fastest it should be sufficient to set this around “1024”, and “1536” is enough. If it is set to high, then it seems like the test runs take more time. This could be due to garbage collection.

If the number of CPUs are increased beyond the actual number of cores, an increase in run time might be observed. When that happen, decrease the number of CPUs available to the vagrant instance.

Composer resources

There can be timeouts in the Vagrant guest instance during composer runs. To adjust for the increased time do something like

vagrant ssh
composer config --global process-timeout 900


Guest linting

Install additional Lua stuff

vagrant ssh
sudo apt-get install lua5.1
sudo apt-get install luarocks
sudo apt-get install unzip
sudo luarocks install luacheck

TODO: Probably be fixed in a few days. (T224791)

Seems like these two must be global to work properly

sudo apt install pdepend phpmd

The previous gives old versions, but they sort of work.

Most of the linting can be installed by the following (or vagrant git-update)

cd /vagrant/mediawiki/extensions/Pickle
composer install

Append a line PATH="$PATH:/vagrant/mediawiki" to the file ~/.profile, do an exit and vagrant ssh to get back into the box.

Given that a standard Mediawiki-Vagrant is used then sudo must be used while calling npm. First update npm itself

cd /vagrant/mediawiki/extensions/Pickle
sudo npm update -g npm

then install all dependencies

sudo npm install

Make sure we have a few additions

sudo npm install -g grunt-cli --save-dev
npm install grunt --save-dev

(Those are only used for linting in the guest!)

Update nano ./node_modules/grunt-contrib-lualint/tasks/lualint.js, change ./libs/lualint to luacheck. The check done by lualint is rather rudimentary compared to luacheck, but the later has no grunt-module.

If you run grunt --force at this point you should get failures involving lualint, and luac.

Linting with PHP_CodeSniffer require (skip?)

sudo apt-get install php-pear
sudo pear channel-update
sudo pear install PHP_CodeSniffer

TODO: Got a lot of undefined here. Outdated repo? (Bug #21218)

Host linting

Some needs to be set up in the host. Usually the editing software needs additional tweaking, such as if you are using w:Visual Studio Code. The following assumes you are on a host running Ubuntu 16.10

Part of this is from PHPraxis – PHP and more: Install PHP 5.6 (or 5.5) in Ubuntu 16.04 LTS (Xenial Xerus) (Apache-packages might be skipped, possibly also databases.)

LC_ALL=C.UTF-8 sudo add-apt-repository ppa:ondrej/php
sudo apt-get remove php-pear
sudo apt-get -y install composer npm curl git
sudo apt-get -y install php5.6 php5.6-xml php5.6-curl php5.6-json php5.6-mbstring php5.6-mysql php5.6-cli php5.6-sqlite3 php5.6-mcrypt
sudo apt-get -y install php7.0 php7.0-xml
sudo apt-get -y install libapache2-mod-php5.6 libapache2-mod-php7.0 mysql-server-5.7 apache2
sudo apt-get install php-codesniffer php-gettext php-pear php-php-gettext php-xdebug php-pear
npm install
composer install
sudo apt-get update && sudo apt-get upgrade

To shift from php 5.6 to php 7.0

sudo a2dismod php5.6 ; sudo a2enmod php7.0 ; sudo service apache2 restart

To shift from php 7.0 to php 5.6

sudo a2dismod php7.0 ; sudo a2enmod php5.6 ; sudo service apache2 restart

Assuming you are on a Ubuntu machine, set up luarocks

sudo apt-get install luarocks

then set up luacheck

sudo luarocks install luacheck

Mess detection

A lot of problems. Seems like the host works as advertised for pdepend and phpmd, while the guest has problems with newer versions. For now the only versions that works are the pretty old

composer global require pdepend/pdepend:1.* phpmd/phpmd:1.*

Manual testing

There are a number of code pages in a file pages.xml. This file can be imported by composer import, and if necessary a new file built by composer export. The core pages should be available from Main Page, but note especially the page VagrantRole/Pickle/testcases.

Verification of the setup

To do some very simple manual testing, add the following on a page Module:Test in the Vagrant-instance. It should be available at (HHVM) or at (PHP5)

local h = {} = function() return 'bar' end
return h

At this point the module should have a category “Modules with unknown tests”, which is clearly wrong as there are no tests! This is a bug that needs fixing, it is a default handler that doesn't check if the page exists.

Then add the following on a page Module:Test/pickle

local h = {}
function h.tap()
  return "1..1\nok 1"
return h

The h.tap() fakes a test report, as the code for reporting test states isn't finalized yet.

Page indicators and tracking categories should now be set, and logging events generated on state changes. The page Module:Test/pickle should have a page indicator saying “Good” in some language, and after reloading Module:Test that page should be “Good” too.

Verification of development

The development starts to come together, and it is possible to verify the code through the development console. In the present version the library is bootstrapped through a side effect of accessing describe(), which also double as the outer test case (or example) in a spec. The “loading” is requiring a number of libs, registering some functions to access those libraries, and then doing the usual function associated with describe. The resulting model can be observed in the lua console.

= mw.dumpObject( p )         -- this is a table

Note that the console does not handle comments, and those must be left out when you do copy-pasting.

The initial result, the value set to p, is the unevaluated model. To get to the (TODO)

A very small “shim” is available as part of the loading of non-pure lua libs. This is located at mw.pickle, and contains configuration data used during bootstrapping. Before bootstrap only configuration data and the function to do bootstrapping is available.

= mw.dumpObject( mw.pickle ) -- this is a table
= mw.dumpObject( describe )  -- this is a function

Actual content of the structure may change.

After bootstrapping the global environment will contain numerous other functions, and possibly some private tables. One private table is _reports and will expand and contract as tests are run. To some degree this can be safely manipulated through use of spies. The bootstrapping happens in the normal running code, and not in the console. What you inspect in the console is the observable model without the additional functions that will be installed through the bootstrap process. That means you will see the describe function, but you will not see the context or it functions unless you run describe inside the console.

= mw.dumpObject( _reports )  -- should return 'nil'
describe():eval()            -- this fill '_reports' with a few lines
= mw.dumpObject( _reports )  -- should now return a table

Automated testing

Testing of PHP files are mainly done from composer, which also include access points to test entries for Lua files. Testing of Javascript files and other files are done from grunt. Check out composer.json and Gruntfile.js.

Unit tests

To run the unit tests on the code base start the vagrant instance

vagrant up
vagrant ssh

and then run the test for phpunit

cd /vagrant/mediawiki
sudo -u www-data php5 tests/phpunit/phpunit.php --wiki wiki --group Pickle

or run the style tests and unit tests for composer

cd /vagrant/mediawiki/extensions/Pickle
composer test
composer unit

Running the unit tests through composer makes the tests run at twice the speed.

Bugs & problems

Role “scribunto”

Until the scribunto role is fixed, there are random critical errors during testing, the role must be manually set to use standalone instead of sandbox

# Class: role::scribunto
# Configures Scribunto, an extension for embedding scripting languages
# in MediaWiki.

class role::scribunto {
    include ::role::codeeditor
    include ::role::syntaxhighlight
    mediawiki::extension { 'Scribunto':
      settings => [
            '$wgScribuntoEngineConf["luastandalone"]["luaPath"] =
            '$wgScribuntoDefaultEngine = "luastandalone"',
            '$wgScribuntoUseGeSHi      = true',
            '$wgScribuntoUseCodeEditor = true',
        notify   => Service['apache2'],
        require  => [

Failed dependencies

During first vagrant up I often gets missing or failed dependencies. Usually a vagrant reload --provision solve the problem.

Missing /var/log

Sometimes I'm stuck on missing /var/log on guest. Usually I just do a vagrant destroy and start over, but sometime I'm stuck. Only thing that worked for me in those cases was a vagrant box remove trusty-cloud. This is a very hard reset because something has gone really wrong in the guest.

RPC failed

Sometime I get error: RPC failed; curl 56 GnuTLS recv error (-9): A TLS packet with unexpected length was received. In those cases start from scratch and hope the best. It seems like the error is triggered by packet collisions, then gnuTLS fails, and then curl can't restart. See also Phabricator T152801 and Launchpad: bug#1111882.

Timeout after updating the key

Usually something like “Timed out while waiting for the machine to boot.” Try a new vagrant reload, usually it will work after the restart, or slap the box with vagrant reload --provision.

Sometimes it helps to do a ACPI shutdown, or restart, and then an ACPI shutdown on the instance. Also, consider a restart on the host to release stuck bound sockets.

Timeout on waiting for NFS

Usually this is a failed restart of NFS on host. Do a vagrant halt, and restart NFS (hard), or reboot the host (easy). If NFS fails, it could be an indication that other things is stuck too.

NFS is tricky to restart, read the manual. And yes, it is not unlikely NFS has failed on the guest too.

Not sure about this: It seems like updates of VirtualBox often leaves an old version of the Guest Additions. That makes the next vagrant up fail. It seems like a vagrant destroy is necessary to make the guest work again, so all local additions must be reapplied. Because other guests might work as usual this can be very confusing.

Ports in use

Sometimes I'm stuck with ports in use on host or guest. Usually it is the host, and usually it is use of port 8080. Seems like only thing that surely solves that is a vagrant halt, which should say that the instance is not running, reboot and then vagrant up --provision.

It could be other processes that use the ports, and if those starts again after reboot you're stuck. Try to track them down with netstat -na | grep 8080 (or whatever offending port) and kill them, or reassign the ports. If it is port 8080 on the host then the port is set in the file settings.d/wikis/wgConf.php and the config settings.d/wikis/wiki/wgConf.php.


Unless the provisioning is fixed (symfony/process dependency in SyntaxHighlight not loaded) there will be a lot of red error messages at this point if you skipped vagrant git-update, or there will be complaints about missing classes when you open the main page for you mediawiki instance. The following should preferably be done before setting up any roles.

Use a vagrant git-update and possibly a vagrant reload --provision to make the complaint go away. If they still don't go away try to use vagrant ssh to tunnel into the vagrant box and then cd /vagrant/mediawiki/extensions and for each extension cd into the directory and do a composer update. Afterward, do a vagrant reload --provision.

Test does not use all cores

Composer tries to get fastest, but unless composer update is run, that is vagrant git-update, it isn't available. It isn't that much that can be run in parallel on Mediawiki, so the tests are slow anyhow. With fastest I get a 20% drop in overall run time for the tests. The ordinary Lua tests run from PHP are awfully slow.


Running boxes can be listed with

vagrant global-status

Abandoned boxes can be pruned with

vagrant global-status --prune
generated by LDoc 1.4.6