Skip to content

PHPLIB-794: Use single/multi-mongos LB URIs when available #1019

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .evergreen/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,8 @@ functions:
API_VERSION=${API_VERSION} \
CRYPT_SHARED_LIB_PATH=${CRYPT_SHARED_LIB_PATH} \
MONGODB_URI="${MONGODB_URI}" \
MONGODB_SINGLE_MONGOS_LB_URI="${SINGLE_MONGOS_LB_URI}" \
MONGODB_MULTI_MONGOS_LB_URI="${MULTI_MONGOS_LB_URI}" \
PHP_VERSION=${PHP_VERSION} \
SKIP_CRYPT_SHARED=${SKIP_CRYPT_SHARED} \
SSL=${SSL} \
Expand Down
25 changes: 20 additions & 5 deletions .evergreen/run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ CRYPT_SHARED_LIB_PATH="${CRYPT_SHARED_LIB_PATH:-}" # Optional path to crypt_shar
DRIVER_MONGODB_VERSION=${DRIVER_MONGODB_VERSION:-} # Required if IS_MATRIX_TESTING is "true"
IS_MATRIX_TESTING=${IS_MATRIX_TESTING:-} # Specify "true" to enable matrix testing. Defaults to empty string. If "true", DRIVER_MONGODB_VERSION and MONGODB_VERSION will also be checked.
MONGODB_URI=${MONGODB_URI:-} # Connection string (including credentials and topology info)
MONGODB_SINGLE_MONGOS_LB_URI=${MONGODB_SINGLE_MONGOS_LB_URI:-} # Single-mongos LB connection string
MONGODB_MULTI_MONGOS_LB_URI=${MONGODB_MULTI_MONGOS_LB_URI:-} # Multi-mongos LB connection string
MONGODB_VERSION=${MONGODB_VERSION:-} # Required if IS_MATRIX_TESTING is "true"
SKIP_CRYPT_SHARED="${SKIP_CRYPT_SHARED:-no}" # Specify "yes" to ignore CRYPT_SHARED_LIB_PATH. Defaults to "no"
SSL=${SSL:-no} # Specify "yes" to enable SSL. Defaults to "no"
Expand Down Expand Up @@ -44,14 +46,25 @@ fi
# Enable verbose output to see skipped and incomplete tests
PHPUNIT_OPTS="${PHPUNIT_OPTS} -v --configuration phpunit.evergreen.xml"

# Determine if MONGODB_URI already has a query string
SUFFIX=$(echo "$MONGODB_URI" | grep -Eo "\?(.*)" | cat)

if [ "$SSL" = "yes" ]; then
SSL_OPTS="ssl=true&sslallowinvalidcertificates=true"

# Determine if MONGODB_URI already has a query string
SUFFIX=$(echo "$MONGODB_URI" | grep -Eo "\?(.*)" | cat)

if [ -z "$SUFFIX" ]; then
MONGODB_URI="${MONGODB_URI}/?ssl=true&sslallowinvalidcertificates=true"
MONGODB_URI="${MONGODB_URI}/?${SSL_OPTS}"
else
MONGODB_URI="${MONGODB_URI}&ssl=true&sslallowinvalidcertificates=true"
MONGODB_URI="${MONGODB_URI}&${SSL_OPTS}"
fi

# Assume LB URIs already have a query string (e.g. "?loadBalanced=true")
if [ -n "${MONGODB_SINGLE_MONGOS_LB_URI}" ]; then
MONGODB_SINGLE_MONGOS_LB_URI="${MONGODB_SINGLE_MONGOS_LB_URI}&${SSL_OPTS}"
fi

if [ -n "${MONGODB_MULTI_MONGOS_LB_URI}" ]; then
MONGODB_MULTI_MONGOS_LB_URI="${MONGODB_MULTI_MONGOS_LB_URI}&${SSL_OPTS}"
fi
fi

Expand All @@ -65,6 +78,8 @@ export SYMFONY_DEPRECATIONS_HELPER=999999
export API_VERSION="${API_VERSION}"
export CRYPT_SHARED_LIB_PATH="${CRYPT_SHARED_LIB_PATH}"
export MONGODB_URI="${MONGODB_URI}"
export MONGODB_SINGLE_MONGOS_LB_URI="${MONGODB_SINGLE_MONGOS_LB_URI}"
export MONGODB_MULTI_MONGOS_LB_URI="${MONGODB_MULTI_MONGOS_LB_URI}"

# Run the tests, and store the results in a junit result file
case "$TESTS" in
Expand Down
126 changes: 71 additions & 55 deletions tests/FunctionalTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
use stdClass;
use UnexpectedValueException;

use function array_merge;
use function call_user_func;
use function count;
use function current;
Expand Down Expand Up @@ -90,63 +89,16 @@ public static function createTestManager(?string $uri = null, array $options = [

public static function getUri($allowMultipleMongoses = false): string
{
$uri = parent::getUri();

/* If multiple mongoses are allowed, the multi-mongos load balanced URI
* can be used if available; otherwise, fall back MONGODB_URI. */
if ($allowMultipleMongoses) {
return $uri;
}

$urlParts = parse_url($uri);
if ($urlParts === false) {
return $uri;
}

// Only modify URIs using the mongodb scheme
if ($urlParts['scheme'] !== 'mongodb') {
return $uri;
return getenv('MONGODB_MULTI_MONGOS_LB_URI') ?: parent::getUri();
}

$hosts = explode(',', $urlParts['host']);
$numHosts = count($hosts);
if ($numHosts === 1) {
return $uri;
}

$manager = static::createTestManager($uri);
if ($manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY))->getType() !== Server::TYPE_MONGOS) {
return $uri;
}

// Re-append port to last host
if (isset($urlParts['port'])) {
$hosts[$numHosts - 1] .= ':' . $urlParts['port'];
}

$parts = ['mongodb://'];

if (isset($urlParts['user'], $urlParts['pass'])) {
$parts += [
$urlParts['user'],
':',
$urlParts['pass'],
'@',
];
}

$parts[] = $hosts[0];

if (isset($urlParts['path'])) {
$parts[] = $urlParts['path'];
}

if (isset($urlParts['query'])) {
$parts = array_merge($parts, [
'?',
$urlParts['query'],
]);
}

return implode('', $parts);
/* If multiple mongoses are prohibited, the single-mongos load balanced
* URI can be used if available; otherwise, we need to conditionally
* process MONGODB_URI. */
return getenv('MONGODB_SINGLE_MONGOS_LB_URI') ?: static::getUriWithoutMultipleMongoses();
}

protected function assertCollectionCount($namespace, $count): void
Expand Down Expand Up @@ -629,6 +581,70 @@ private function disableFailPoints(): void
}
}

private static function getUriWithoutMultipleMongoses(): string
{
/* Cache the result. We can safely assume the topology type will remain
* constant for the duration of the test suite. */
static $uri;

if (isset($uri)) {
return $uri;
}

$uri = parent::getUri();
$parsed = parse_url($uri);

if (! isset($parsed['scheme'], $parsed['host'])) {
throw new UnexpectedValueException('Failed to parse scheme and host components from URI: ' . $uri);
}

// Only modify URIs using the mongodb scheme
if ($parsed['scheme'] !== 'mongodb') {
return $uri;
}

$hosts = explode(',', $parsed['host']);
$numHosts = count($hosts);

if ($numHosts === 1) {
return $uri;
}

$manager = static::createTestManager($uri);
if ($manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY))->getType() !== Server::TYPE_MONGOS) {
return $uri;
}

// Re-append port to last host
if (isset($parsed['port'])) {
$hosts[$numHosts - 1] .= ':' . $parsed['port'];
}

$parts = ['mongodb://'];

if (isset($parsed['user'], $parsed['pass'])) {
$parts[] = $parsed['user'] . ':' . $parsed['pass'] . '@';
}

$parts[] = $hosts[0];

if (isset($parsed['path'])) {
$parts[] = $parsed['path'];
} elseif (isset($parsed['query'])) {
/* URIs containing connection options but no auth database component
* still require a slash before the question mark */
$parts[] = '/';
}

if (isset($parsed['query'])) {
$parts[] = '?' . $parsed['query'];
}

$uri = implode('', $parts);

return $uri;
}

/**
* Checks if the failCommand command is supported on this server version
*/
Expand Down
4 changes: 2 additions & 2 deletions tests/SpecTests/TransactionsSpecTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ public function testStartingNewTransactionOnPinnedSessionUnpinsSession(): void
$this->markTestSkipped('Pinning tests require mongos');
}

$client = self::createTestClient($this->getUri(true));
$client = self::createTestClient(static::getUri(true));

$session = $client->startSession();
$collection = $client->selectCollection($this->getDatabaseName(), $this->getCollectionName());
Expand Down Expand Up @@ -275,7 +275,7 @@ public function testRunningNonTransactionOperationOnPinnedSessionUnpinsSession()
$this->markTestSkipped('Pinning tests require mongos');
}

$client = self::createTestClient($this->getUri(true));
$client = self::createTestClient(static::getUri(true));

$session = $client->startSession();
$collection = $client->selectCollection($this->getDatabaseName(), $this->getCollectionName());
Expand Down
8 changes: 3 additions & 5 deletions tests/UnifiedSpecTests/UnifiedTestRunner.php
Original file line number Diff line number Diff line change
Expand Up @@ -543,14 +543,12 @@ private function createContext(): Context
$context->setUrisForUseMultipleMongoses($singleMongosUri, $multiMongosUri);
}

/* TODO: Enable this logic once PHPLIB-794 is implemented. For now, load
* balancer tests will continue to use MONGODB_URI. */
if (false && $this->getPrimaryServer()->getType() === Server::TYPE_LOAD_BALANCER && ! $this->isServerless()) {
if ($this->getPrimaryServer()->getType() === Server::TYPE_LOAD_BALANCER && ! $this->isServerless()) {
$singleMongosUri = getenv('MONGODB_SINGLE_MONGOS_LB_URI');
$multiMongosUri = getenv('MONGODB_MULTI_MONGOS_LB_URI');

assertNotFalse($singleMongosUri);
assertNotFalse($multiMongosUri);
assertNotEmpty($singleMongosUri);
assertNotEmpty($multiMongosUri);

$context->setUrisForUseMultipleMongoses($singleMongosUri, $multiMongosUri);
}
Expand Down