Merge pull request #95 from creative-commoners/pulls/3/db-replica

FIX Ensure primary connection is updated with temporary database
This commit is contained in:
Guy Sartorelli 2024-10-11 10:53:58 +13:00 committed by GitHub
commit a247a44a19
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 29 additions and 17 deletions

View File

@ -12,7 +12,7 @@ TestSessionEnvironment::singleton()->loadFromFile();
*/ */
if (class_exists('Resque_Event') && class_exists('SSResqueRun')) { if (class_exists('Resque_Event') && class_exists('SSResqueRun')) {
Resque_Event::listen('beforeFork', function ($data) { Resque_Event::listen('beforeFork', function ($data) {
$databaseConfig = DB::getConfig(); $databaseConfig = DB::getConfig(DB::CONN_PRIMARY);
// Reconnect to the database - this may connect to the old DB first, but is required because these processes // Reconnect to the database - this may connect to the old DB first, but is required because these processes
// are long-lived, and MySQL connections often get closed in between worker runs. We need to connect before // are long-lived, and MySQL connections often get closed in between worker runs. We need to connect before

View File

@ -326,7 +326,7 @@ class TestSessionController extends Controller
} }
/** /**
* As with {@link self::start()}, if you want to extend the functionality of this, then look at * As with {@link TestSessionController::start()}, if you want to extend the functionality of this, then look at
* {@link TestSessionEnvironent::endTestSession()} as the extension points have moved to there now that the logic * {@link TestSessionEnvironent::endTestSession()} as the extension points have moved to there now that the logic
* is there. * is there.
*/ */

View File

@ -63,7 +63,7 @@ class TestSessionEnvironment
/** /**
* @var string The original database name, before we overrode it with our tmpdb. * @var string The original database name, before we overrode it with our tmpdb.
* *
* Used in {@link self::resetDatabaseName()} when we want to restore the normal DB connection. * Used in {@link TestSessionEnvironment::resetDatabaseName()} when we want to restore the normal DB connection.
*/ */
private $oldDatabaseName; private $oldDatabaseName;
@ -137,14 +137,16 @@ class TestSessionEnvironment
/** /**
* Creates a temp database, sets up any extra requirements, and writes the state file. The database will be * Creates a temp database, sets up any extra requirements, and writes the state file. The database will be
* connected to as part of {@link self::applyState()}, so if you're continuing script execution after calling this * connected to as part of {@link TestSessionEnvironment::applyState()}, so if you're continuing script
* execution after calling this
* method, be aware that the database will be different - so various things may break (e.g. administrator logins * method, be aware that the database will be different - so various things may break (e.g. administrator logins
* using the SS_DEFAULT_USERNAME / SS_DEFAULT_PASSWORD constants). * using the SS_DEFAULT_USERNAME / SS_DEFAULT_PASSWORD constants).
* *
* If something isn't explicitly handled here, and needs special handling, then it should be taken care of by an * If something isn't explicitly handled here, and needs special handling, then it should be taken care of by an
* extension to TestSessionEnvironment. You can either extend onBeforeStartTestSession() or * extension to TestSessionEnvironment. You can either extend onBeforeStartTestSession() or
* onAfterStartTestSession(). Alternatively, for more fine-grained control, you can also extend * onAfterStartTestSession(). Alternatively, for more fine-grained control, you can also extend
* onBeforeApplyState() and onAfterApplyState(). See the {@link self::applyState()} method for more. * onBeforeApplyState() and onAfterApplyState(). See the {@link TestSessionEnvironment::applyState()}
* method for more.
* *
* @param array $state An array of test state options to write. * @param array $state An array of test state options to write.
* @param mixed $id * @param mixed $id
@ -270,7 +272,7 @@ class TestSessionEnvironment
$this->extend('onBeforeApplyState', $state); $this->extend('onBeforeApplyState', $state);
// back up source // back up source
$databaseConfig = DB::getConfig(); $databaseConfig = DB::getConfig(DB::CONN_PRIMARY);
$this->oldDatabaseName = $databaseConfig['database']; $this->oldDatabaseName = $databaseConfig['database'];
// Load existing state from $this->state into $state, if there is any // Load existing state from $this->state into $state, if there is any
@ -445,7 +447,8 @@ class TestSessionEnvironment
/** /**
* Cleans up the test session state by restoring the normal database connect (for the rest of this request, if any) * Cleans up the test session state by restoring the normal database connect (for the rest of this request, if any)
* and removes the {@link self::$test_state_file} so that future requests don't use this test state. * and removes the {@link TestSessionEnvironment::$test_state_file} so that future requests don't use this
* test state.
* *
* Can be extended by implementing either onBeforeEndTestSession() or onAfterEndTestSession(). * Can be extended by implementing either onBeforeEndTestSession() or onAfterEndTestSession().
* *
@ -514,14 +517,15 @@ class TestSessionEnvironment
} }
/** /**
* Reset the database connection to use the original database. Called by {@link self::endTestSession()}. * Reset the database connection to use the original database.
* Called by {@link TestSessionEnvironment::endTestSession()}.
*/ */
public function resetDatabaseName() public function resetDatabaseName()
{ {
if ($this->oldDatabaseName) { if ($this->oldDatabaseName) {
$databaseConfig = DB::getConfig(); $databaseConfig = DB::getConfig(DB::CONN_PRIMARY);
$databaseConfig['database'] = $this->oldDatabaseName; $databaseConfig['database'] = $this->oldDatabaseName;
DB::setConfig($databaseConfig); DB::setConfig($databaseConfig, DB::CONN_PRIMARY);
$conn = DB::get_conn(); $conn = DB::get_conn();
@ -532,7 +536,7 @@ class TestSessionEnvironment
} }
/** /**
* @return stdClass Data as taken from the JSON object in {@link self::loadFromFile()} * @return stdClass Data as taken from the JSON object in {@link TestSessionEnvironment::loadFromFile()}
*/ */
public function getState() public function getState()
{ {
@ -564,7 +568,7 @@ class TestSessionEnvironment
$state = $this->getState(); $state = $this->getState();
} }
$databaseConfig = DB::getConfig(); $databaseConfig = DB::getConfig(DB::CONN_PRIMARY);
if (isset($state->database) && $state->database) { if (isset($state->database) && $state->database) {
if (!DB::get_conn()) { if (!DB::get_conn()) {
@ -575,14 +579,14 @@ class TestSessionEnvironment
} }
// Connect to database // Connect to database
DB::connect($databaseConfig); $this->connectToDB($databaseConfig);
} else { } else {
// We've already connected to the database, do a fast check to see what database we're currently using // We've already connected to the database, do a fast check to see what database we're currently using
$db = DB::get_conn()->getSelectedDatabase(); $db = DB::get_conn()->getSelectedDatabase();
if (isset($state->database) && $db != $state->database) { if (isset($state->database) && $db != $state->database) {
$this->oldDatabaseName = $databaseConfig['database']; $this->oldDatabaseName = $databaseConfig['database'];
$databaseConfig['database'] = $state->database; $databaseConfig['database'] = $state->database;
DB::connect($databaseConfig); $this->connectToDB($databaseConfig);
} }
} }
} }
@ -618,4 +622,12 @@ class TestSessionEnvironment
return true; return true;
} }
private function connectToDB(array $databaseConfig): void
{
// Ensure we connect the primary connection and not a replica
// which can happen if we use the default value of DB::CONN_DYNAMIC
// and there is a replica database configured
DB::connect($databaseConfig, DB::CONN_PRIMARY);
}
} }

View File

@ -33,7 +33,7 @@ class TestSessionState extends DataObject
{ {
$schema = DataObject::getSchema(); $schema = DataObject::getSchema();
$update = SQLUpdate::create(sprintf('"%s"', $schema->tableName(self::class))) $update = SQLUpdate::create(sprintf('"%s"', $schema->tableName(TestSessionState::class)))
->addWhere(['ID' => 1]) ->addWhere(['ID' => 1])
->assignSQL('"PendingRequests"', '"PendingRequests" + 1'); ->assignSQL('"PendingRequests"', '"PendingRequests" + 1');
@ -50,10 +50,10 @@ class TestSessionState extends DataObject
{ {
$schema = DataObject::getSchema(); $schema = DataObject::getSchema();
$update = SQLUpdate::create(sprintf('"%s"', $schema->tableName(self::class))) $update = SQLUpdate::create(sprintf('"%s"', $schema->tableName(TestSessionState::class)))
->addWhere(['ID' => 1]) ->addWhere(['ID' => 1])
->assignSQL('"PendingRequests"', '"PendingRequests" - 1') ->assignSQL('"PendingRequests"', '"PendingRequests" - 1')
->assign('"LastResponseTimestamp"', self::millitime()); ->assign('"LastResponseTimestamp"', TestSessionState::millitime());
$update->execute(); $update->execute();
} }