It's a blog

Tag: PHP

mediawiki-docker-dev v1 rewrite

Back in 2017 at the Wikimedia Hackathon, I played around with Docker and docker-compose in relation to MediaWiki and testing with multiple setups at once while developing, meaning multiple PHP versions, web servers and databases. My original slides can still be found here.

Since then mediawiki-docker-dev evolved into less of a testing system and more of a development environment, allowing the use of a master replica DB setup, easily swappable PHP versions, debugging and more. The project on GitHub currently has 40 stars, 38 forks and has seen 17 people contributing back.

Over the past couple of years, developer productivity and development environments have been a big discussion area. The Wikimedia technical conference in 2019 had the main topic of Developer Productivity. There have also been a few efforts in a few directions trying to figure out what is best for the majority of people. These include local-charts (Kubernetes based environment) and MediaWiki-Docker (simple docker-compose based environment).

Continue reading

sMite

sMite stands for ‘simple Mite’, which to most people still means nothing at all. Mite is a time tracking web service, and depending on how companies make use of it things can become more complicated than they should be.
smite is how I tried to tackle this complexity in less than 8 hours!

Continue reading

My Joomla Component development workflow

Joomla20Symbol20Color20FLATMy first and currently only Joomla component development was for the SWA UK website. The component manages memberships, events, tickets, results and more and is a rewrite of a previous component for Joomla 1.

But in this post lets ignore what the component does and instead concentrate the development workflow that is used. After lots of research at the beginning of development I decided to ignore other  methods of developing a component and this is what I ended up coming up with.

Continue reading

mediawiki-api-base 2.0.0

Roughly a year and a half ago I started writing a collection of PHP libraries to make interaction with the Mediawiki API and extension APIs super easy. The base library has just made it to 2.0.0!

The new release really only uses the new version of the Guzzle HTTP library which makes use of PSR-7 and adds async get and post methods using the Guzzle promise library.

This library is the first of the addwiki collection that has actually reached 1.0.0 let alone 2.0.0! All of the other libraries, including wikibase-api and mediawiki-api are still a work in progress with lots to be added. The next likely to be released will be the wikibase-api library once I try to also add async functionality there!

A snippet of the async functionality added in mediawiki-api-base can be seen below:

// Get an API object and login
$api = MediawikiApi::newFromPage( 'https://en.wikipedia.org/wiki/Berlin' );
$api->login( new ApiUser( 'username', 'password' ) );

// Initiate each request but do not block
$requestPromises = array(
    'Page1' => $api->postRequest( FluentRequest::factory()->setAction( 'purge' )->setParam( 'titles', 'Page1' ) ),
    'Page2' => $api->postRequest( FluentRequest::factory()->setAction( 'purge' )->setParam( 'titles', 'Page2' ) ),
    'Page3' => $api->postRequest( FluentRequest::factory()->setAction( 'purge' )->setParam( 'titles', 'Page3' ) ),
);

// Wait on all of the requests to complete.
$results = Promise\unwrap( $requestPromises );

// You can access each result using the key provided to the unwrap function.
print_r( $results['Page1'], $results['Page2'], $results['Page3'] )

 

MediaWiki CRAP – The worst of it

I don’t mean Mediawiki is crap! The Change Risk Anti-Patterns (CRAP) Index is calculated based on the cyclomatic complexity and code coverage of a unit of code. Complex code and untested code will have a higher CRAP index compared with simple well tested code. Over the last 2 years I have been tracking the CRAP index of some of Mediawikis more complex classes as reported by the automatic coverage reports, and this is a simple summary of what has been happening.

Continue reading

Misled by PHPUnit at() method

So it turns out the at() method doesn’t quite do what I had initially thought….

I have recently been working on some tests for the new Newsletter extension for Mediawiki, specifically to test the NewslettterTablePager class. This thing extends the TablePager class in Mediawiki which is designed to make displaying information from a database table on a special page on a mediawiki site easy, and also easily enable things such as sorting.

The code interacts with the database and gets a ResultWrapper object, and the Pager uses the numRows(), seek() and fetchObject() methods, all of which I thought would be incredibly simple to mock.

Attempt 1

My first attempt where I first notice I have been thinking about the at() method all wrong can be seen below:

   private function getMockDatabase( array $resultObjects ) {
        $mockResult = $this->getMock( 'ResultWrapper' );
        $mockResult->expects( $this->atLeastOnce() )
            ->method( 'numRows' )
            ->will( $this->returnValue( count( $resultObjects ) ) );
        $mockResult->expects( $this->any() )
            ->method( 'seek' );
        foreach ( $resultObjects as $index => $resultObject ) {
            $mockResult->expects( $this->at( $index ) )
                ->method( 'fetchObject' )
                ->will( $this->returnValue( $resultObject ) );
        }
        $mockDb = $this->getMock( 'IDatabase' );
        $mockDb->expects( $this->atLeastOnce() )
            ->method( 'select' )
            ->will( $this->returnValue( $mockResult ) );
        return $mockDb;
    }

This methods returns a mock Database that the Pager will use. As you can see the only parameter is an array of objects to be returned by fetchObject() and I am using the at() method provided by phpunit to return each object at the index that it is stored in the array. This is when I discovered that at() in phpunit does not work in the way I first thought…

at() refers to the index of calls made to the mocked object as a whole. This means that in the code sample above, all of the calles to numRows() and seek() are increasing the current call counter index for the object and thus my mocked fetchObject() method is never returning the correct value or returning null.

Attempt 2

In my second attempt I made a guess that phpunit might allow multiple method mocks to stack and thus the return values of those methods be returned in the order that they were created. Thus I changed my loop to simply use any():

       foreach ( $resultObjects as $index => $resultObject ) {
            $mockResult->expects( $this->any() )
                ->method( 'fetchObject' )
                ->will( $this->returnValue( $resultObject ) );
        }

But of course this also does not work and this result in the same $resultObject being returned for all calls.

Final version

I ended up having to to do something a little bit nasty (in my opinion) and use returnCallback() and use a private member of the testcase within the callback as a call counter / per method index:

       $testcase = $this;
        $mockResult->expects( $this->any() )
            ->method( 'fetchObject' )
            ->will( $this->returnCallback( function () use ( $testCase, $resultObjects ) {
                $obj = $resultObjects[$testCase->mockSeekCounter];
                $testCase->mockSeekCounter =+ 1;
                return $obj;
            } ) );

Notes

It would be great if phpunit would have some form of per method index expectation!

Some of the code examples here are slightly cut down, the full change can be seen at https://gerrit.wikimedia.org/r/#/c/234727/ in the NewsletterTablePagerTest file.

If only I had Googled the issue sooner! http://www.andrejfarkas.com/2012/07/phpunit-at-method-to-check-method-invocation-at-certain-index/ (Blog post now dead :()

The importance of a strict comparison

A cloudNow if you have ever come across issues caused by non strict comparisons before then this is going to seem like a piece of cake, but remember, everyone makes mistakes.

Strict equality compares two values for equality where the values must also be the same type. Non strict or loose equality compares values while not caring about their type. Strict equality is almost always the correct comparison to use, and if it is not used when it should be many unexpected things can happen.

Continue reading

© 2020 Addshore

Theme by Anders NorénUp ↑