diff --git a/README.md b/README.md index 15fae1f..d8d9cb9 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/src/TestSessionEnvironment.php b/src/TestSessionEnvironment.php index 6e62a7d..9ebd0cc 100644 --- a/src/TestSessionEnvironment.php +++ b/src/TestSessionEnvironment.php @@ -335,6 +335,8 @@ class TestSessionEnvironment // Connect to the new database, overwriting the old DB connection (if any) DB::connect($databaseConfig); } + + TestSessionState::create()->write(); // initialize the session state } // Mailer @@ -363,6 +365,7 @@ class TestSessionEnvironment } $this->saveState($state); + $this->extend('onAfterApplyState'); } @@ -558,4 +561,34 @@ class TestSessionEnvironment { 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) + { + $timeout = microtime(true) * 10000 + $timeout; + $interval = $await < 300 ? 300 : $await; + do { + $model = TestSessionState::get()->byID(1); + + $pendingRequests = $model->PendingRequests > 0; + $lastRequestAwait = $model->LastResponseTimestamp + $await > microtime(true) * 10000; + + $pending = $pendingRequests || $lastRequestAwait; + + if ($timeout < microtime(true) * 10000) { + // timed out + return false; + } + } while ($pending && (usleep($interval * 1000) || true)); + + return true; + } } diff --git a/src/TestSessionHTTPMiddleware.php b/src/TestSessionHTTPMiddleware.php index c75bc38..42e316b 100644 --- a/src/TestSessionHTTPMiddleware.php +++ b/src/TestSessionHTTPMiddleware.php @@ -8,8 +8,10 @@ use SilverStripe\Control\Email\Mailer; use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\Middleware\HTTPMiddleware; use SilverStripe\Core\Injector\Injector; +use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DB; use SilverStripe\ORM\FieldType\DBDatetime; +use SilverStripe\ORM\Queries\SQLUpdate; /** * Sets state previously initialized through {@link TestSessionController}. @@ -39,15 +41,42 @@ class TestSessionHTTPMiddleware implements HTTPMiddleware // Load test state $this->loadTestState($request); + $this->incrementModelState(); // Call with safe teardown try { return $delegate($request); } finally { $this->restoreTestState($request); + $this->decrementModelState(); } } + protected function incrementModelState() { + $schema = DataObject::getSchema(); + + $update = SQLUpdate::create(sprintf('"%s"', $schema->tableName(TestSessionState::class))) + ->addWhere(['ID' => 1]) + ->addAssignments([ + 'PendingRequests' => [ '"PendingRequests" + 1' => [] ] + ]); + + $update->execute(); + } + + protected function decrementModelState() { + $schema = DataObject::getSchema(); + + $update = SQLUpdate::create(sprintf('"%s"', $schema->tableName(TestSessionState::class))) + ->addWhere(['ID' => 1]) + ->addAssignments([ + '"PendingRequests"' => [ '"PendingRequests" - 1' => [] ], + '"LastResponseTimestamp"' => microtime(true) * 10000 + ]); + + $update->execute(); + } + /** * Load test state from environment into "real" environment * diff --git a/src/TestSessionState.php b/src/TestSessionState.php new file mode 100644 index 0000000..21c29ed --- /dev/null +++ b/src/TestSessionState.php @@ -0,0 +1,33 @@ + 'Int', + + /** + * The microtime stamp of the last response + * made by the server. + * (well, actually that's rather TestSessionMiddleware) + */ + 'LastResponseTimestamp' => 'Decimal(14, 0)' + ]; +}