Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I test race conditions created by multiple ajax requests to php?

I'm using PHP to create some objects in a DB. Sometimes, if a user requests an object while it is being created they can see the partially created object (the main db entry exists but not all of the child objects are inserted yet). I recently implemented a fix, where my code will only serve up the object after it has been fully created by adding a 'creating' flag to the db entry.

How do I test this? I'm using phpunit. The two problems as I see it are that I need parallel threads to make the create and get requests at the same time, and I need to ensure that the timing is right so I can actually test the race condition (and not just get the object after it has been fully created). I want my test to look like this, but am open to suggestions:

  1. thread 1: create the object
  2. thread 2: try to get the object before its fully created (should return an error)
  3. thread 1: get the object after its created (should work)
like image 704
jtfairbank Avatar asked Nov 02 '22 04:11

jtfairbank


1 Answers

Testing for race conditions is already hard in languages that actually do support threads - with PHP, this is even harder. In a single-threaded context you'd have to trigger multiple requests in parallel, maintaining the correct order of these requests so that the test will not randomly fail.

I did it once with a test that checks whether the PHP session locking works correctly:

In PHPUnit I created a curl_multi_query firing three requests against the webserver at a special prepared php script that essentially only starts a session and then sleeps for one second.

The test is successful if the execution of the three requests lasts longer than about 2.5 seconds (don't ask about that time).

I assume the requests will be answered in any (possibly random) order. I am not sure the curl extension will guarantee to start the requests in a certain order. Additionally, I am not sure how the webserver will act when receiving three requests almost instantly. I must assume that the only way to detect locking was successful is to measure the time that passed.

Especially I am not sure that creating a test that will fire two parallel requests, expecting the first request to be successful, the second to always fail, like you want it, will reliably succeed. The only expectation would be that one request out of the two will fail.

like image 190
Sven Avatar answered Nov 08 '22 08:11

Sven