Skip to content

Commit

Permalink
Merge pull request #58 from open-sausages/pulls/2.2/pending-requests-…
Browse files Browse the repository at this point in the history
…awaited

ADD / TestSessionState initial implementation
  • Loading branch information
maxime-rainville authored Jan 8, 2019
2 parents e6c9817 + 0c078e5 commit fc0f7ba
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 0 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ is a random token stored in the browser session, in order to make the
test session specific to the executing browser, and allow multiple
people using their own test session in the same webroot.

The module also keeps some metadata about the session state in the database,
so that it may be available for the clients as well.
E.g. the silverstripe-behat-extension may use it through this module APIs,
allowing us to introduce some grey-box testing techniques.

The module also serves as an initializer for the
[SilverStripe Behat Extension](https://github.com/silverstripe-labs/silverstripe-behat-extension/).
It is required for Behat because the Behat CLI test runner needs to persist
Expand Down
37 changes: 37 additions & 0 deletions src/TestSessionEnvironment.php
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,8 @@ public function applyState($state)
// Connect to the new database, overwriting the old DB connection (if any)
DB::connect($databaseConfig);
}

TestSessionState::create()->write(); // initialize the session state
}

// Mailer
Expand Down Expand Up @@ -363,6 +365,7 @@ public function applyState($state)
}

$this->saveState($state);

$this->extend('onAfterApplyState');
}

Expand Down Expand Up @@ -558,4 +561,38 @@ protected function getAssetsBackupfolder()
{
return PUBLIC_PATH . DIRECTORY_SEPARATOR . 'assets_backup';
}


/**
* Wait for pending requests
*
* @param int $await Time to wait (in ms) after the last response (to allow the browser react)
* @param int $timeout For how long (in ms) do we wait before giving up
*
* @return bool Whether there are no more pending requests
*/
public function waitForPendingRequests($await = 700, $timeout = 10000)
{
$now = static function () {
return microtime(true) * 10000;
};

$timeout = $now() + $timeout;
$interval = max(300, $await);
do {
$model = TestSessionState::get()->byID(1);

$pendingRequests = $model->PendingRequests > 0;
$lastRequestAwait = ($model->LastResponseTimestamp + $await) > $now();

$pending = $pendingRequests || $lastRequestAwait;

if ($timeout < $now()) {
// timed out
return false;
}
} while ($pending && (usleep($interval * 1000) || true));

return true;
}
}
2 changes: 2 additions & 0 deletions src/TestSessionHTTPMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,14 @@ public function process(HTTPRequest $request, callable $delegate)

// Load test state
$this->loadTestState($request);
TestSessionState::incrementState();

// Call with safe teardown
try {
return $delegate($request);
} finally {
$this->restoreTestState($request);
TestSessionState::decrementState();
}
}

Expand Down
60 changes: 60 additions & 0 deletions src/TestSessionState.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

namespace SilverStripe\TestSession;

use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\Queries\SQLUpdate;

/**
* The session state keeps some metadata about the current test session.
* This may allow the client (Behat) to get some insight into the
* server side affairs (e.g. if the server is handling some number requests at the moment).
*
* The client side (Behat) must not use this class straightforwardly, but rather
* rely on the API of {@see TestSessionEnvironment} or {@see TestSessionController}.
*
* @property int PendingRequests keeps information about how many requests are in progress
* @property float LastResponseTimestamp microtime of the last response made by the server
*/
class TestSessionState extends DataObject
{
private static $table_name = 'TestSessionState';

private static $db = [
'PendingRequests' => 'Int',
'LastResponseTimestamp' => 'Decimal(14, 0)'
];

/**
* Increments TestSessionState.PendingRequests number by 1
* to indicate we have one more request in progress
*/
public static function incrementState()
{
$schema = DataObject::getSchema();

$update = SQLUpdate::create(sprintf('"%s"', $schema->tableName(self::class)))
->addWhere(['ID' => 1])
->assignSQL('"PendingRequests"', '"PendingRequests" + 1');

$update->execute();
}

/**
* Decrements TestSessionState.PendingRequests number by 1
* to indicate we have one more request in progress.
* Also updates TestSessionState.LastResponseTimestamp
* to the current timestamp.
*/
public static function decrementState()
{
$schema = DataObject::getSchema();

$update = SQLUpdate::create(sprintf('"%s"', $schema->tableName(self::class)))
->addWhere(['ID' => 1])
->assignSQL('"PendingRequests"', '"PendingRequests" - 1')
->assign('"LastResponseTimestamp"', microtime(true) * 10000);

$update->execute();
}
}

0 comments on commit fc0f7ba

Please sign in to comment.