Viewing File: /opt/alt/tests/alt-php82-pecl-mongodb_1.18.1-1.el8/utils/tools.php
<?php
use MongoDB\Driver\BulkWrite;
use MongoDB\Driver\Command;
use MongoDB\Driver\Manager;
use MongoDB\Driver\ReadPreference;
use MongoDB\Driver\Server;
use MongoDB\Driver\ServerApi;
use MongoDB\Driver\WriteConcern;
use MongoDB\Driver\WriteConcernError;
use MongoDB\Driver\WriteError;
use MongoDB\Driver\WriteResult;
use MongoDB\Driver\Exception\ConnectionException;
use MongoDB\Driver\Exception\RuntimeException;
/**
* Appends an option to a URI string and returns a new URI.
*
* @param string $uri
* @param string $option
* @param string $value
* @return string
*/
function append_uri_option($uri, $option)
{
// Append to existing query string
if (strpos($uri, '?') !== false) {
return $uri . '&' . $option;
}
// Terminate host list and append new query string
if (parse_url($uri, PHP_URL_PATH) === null) {
return $uri . '/?' . $option;
}
// Append query string after terminated host list and possible auth database
return $uri . '?' . $option;
}
/**
* Drops a collection on the primary server.
*
* @param string $uri Connection string
* @param string $databaseName Database name
* @param string $collectionName Collection name
* @throws RuntimeException
*/
function drop_collection($uri, $databaseName, $collectionName)
{
$server = get_primary_server($uri);
$command = new Command(['drop' => $collectionName]);
try {
/* Unless we are dropping a collection within the "local" database,
* which does not support a write concern, we need to use w:majority due
* to the issue explained in SERVER-35613: "drop" uses a two phase
* commit, and due to that, it is possible that a lock can't be acquired
* for a transaction that gets quickly started as the "drop" reaper
* hasn't completed yet. */
$wc = $databaseName === 'local' ? new WriteConcern(1) : new WriteConcern(WriteConcern::MAJORITY);
$server->executeCommand(
$databaseName,
$command,
['writeConcern' => $wc]
);
} catch (RuntimeException $e) {
if ($e->getMessage() !== 'ns not found') {
throw $e;
}
}
}
/**
* Returns the value of a module row from phpinfo(), or null if it's not found.
*
* @param string $row
* @return string|null
*/
function get_module_info($row)
{
ob_start();
phpinfo(INFO_MODULES);
$info = ob_get_clean();
$pattern = sprintf('/^%s(.*)$/m', preg_quote($row . ' => '));
if (preg_match($pattern, $info, $matches) !== 1) {
return null;
}
return $matches[1];
}
function create_test_manager(string $uri = null, array $options = [], array $driverOptions = [])
{
if (getenv('API_VERSION') && ! isset($driverOptions['serverApi'])) {
$driverOptions['serverApi'] = new ServerApi(getenv('API_VERSION'));
}
if (getenv('CRYPT_SHARED_LIB_PATH') && isset($driverOptions['autoEncryption'])) {
if (is_array($driverOptions['autoEncryption']) &&
(! isset($driverOptions['autoEncryption']['extraOptions']) || is_array($driverOptions['autoEncryption']['extraOptions'])) &&
! isset($driverOptions['autoEncryption']['extraOptions']['cryptSharedLibPath'])) {
$driverOptions['autoEncryption']['extraOptions']['cryptSharedLibPath'] = getenv('CRYPT_SHARED_LIB_PATH');
}
}
return new Manager($uri ?? URI, $options, $driverOptions);
}
/**
* Returns the primary server.
*
* @param string $uri Connection string
* @return Server
* @throws ConnectionException
*/
function get_primary_server($uri)
{
return create_test_manager($uri)->selectServer(new ReadPreference('primary'));
}
/**
* Returns a secondary server.
*
* @param string $uri Connection string
* @return Server
* @throws ConnectionException
*/
function get_secondary_server($uri)
{
return create_test_manager($uri)->selectServer(new ReadPreference('secondary'));
}
/**
* Runs a command and returns whether an exception was thrown or not
*
* @param string $uri Connection string
* @param array|object $commandSpec
* @return bool
* @throws RuntimeException
*/
function command_works($uri, $commandSpec)
{
$command = new Command($commandSpec);
$server = get_primary_server($uri);
try {
$cursor = $server->executeCommand('admin', $command);
return true;
} catch (Exception $e) {
return false;
}
}
/**
* Returns a parameter of the primary server.
*
* @param string $uri Connection string
* @return mixed
* @throws RuntimeException
*/
function get_server_parameter($uri, $parameter)
{
$server = get_primary_server($uri);
$command = new Command(['getParameter' => 1, $parameter => 1]);
$cursor = $server->executeCommand('admin', $command);
return current($cursor->toArray())->$parameter;
}
/**
* Returns the storage engine of the primary server.
*
* @param string $uri Connection string
* @return string
* @throws RuntimeException
*/
function get_server_storage_engine($uri)
{
$server = get_primary_server($uri);
$command = new Command(['serverStatus' => 1]);
$cursor = $server->executeCommand('admin', $command);
return current($cursor->toArray())->storageEngine->name;
}
/**
* Helper to return the version of a specific server.
*
* @param Server $server
* @return string
* @throws RuntimeException
*/
function get_server_version_from_server(Server $server)
{
$command = new Command(['buildInfo' => 1]);
$cursor = $server->executeCommand('admin', $command);
return current($cursor->toArray())->version;
}
/**
* Returns the version of the primary server.
*
* @param string $uri Connection string
* @return string
* @throws RuntimeException
*/
function get_server_version($uri)
{
$server = get_primary_server($uri);
return get_server_version_from_server($server);
}
/**
* Returns the value of a URI option, or null if it's not found.
*
* @param string $uri
* @return string|null
*/
function get_uri_option($uri, $option)
{
$pattern = sprintf('/[?&]%s=([^&]+)/i', preg_quote($option));
if (preg_match($pattern, $uri, $matches) !== 1) {
return null;
}
return $matches[1];
}
/**
* Checks that the topology is load balanced.
*
* @param string $uri
* @return boolean
*/
function is_load_balanced($uri)
{
return get_primary_server($uri)->getType() === Server::TYPE_LOAD_BALANCER;
}
/**
* Checks that the topology is a sharded cluster.
*
* @param string $uri
* @return boolean
*/
function is_mongos($uri)
{
return get_primary_server($uri)->getType() === Server::TYPE_MONGOS;
}
/**
* Checks that the topology is a sharded cluster using a replica set.
*
* Note: only the first shard is checked.
*/
function is_sharded_cluster_with_replica_set($uri)
{
$server = get_primary_server($uri);
if ($server->getType() !== Server::TYPE_MONGOS && $server->getType() !== Server::TYPE_LOAD_BALANCER) {
return false;
}
$cursor = $server->executeQuery('config.shards', new \MongoDB\Driver\Query([], ['limit' => 1]));
$cursor->setTypeMap(['root' => 'array', 'document' => 'array']);
$document = current($cursor->toArray());
if (! $document) {
return false;
}
/**
* Use regular expression to distinguish between standalone or replicaset:
* Without a replicaset: "host" : "localhost:4100"
* With a replicaset: "host" : "dec6d8a7-9bc1-4c0e-960c-615f860b956f/localhost:4400,localhost:4401"
*/
return preg_match('@^.*/.*:\d+@', $document['host']);
}
/**
* Checks that the topology is a replica set.
*
* @param string $uri
* @return boolean
*/
function is_replica_set($uri)
{
if (get_primary_server($uri)->getType() !== Server::TYPE_RS_PRIMARY) {
return false;
}
/* Note: this may return a false negative if replicaSet is specified through
* a TXT record for a mongodb+srv connection string. */
if (get_uri_option($uri, 'replicaSet') === NULL) {
return false;
}
return true;
}
/**
* Checks if the connection string uses authentication.
*
* @param string $uri
* @return boolean
*/
function is_auth($uri)
{
if (stripos($uri, 'authmechanism=') !== false) {
return true;
}
if (strpos($uri, ':') !== false && strpos($uri, '@') !== false) {
return true;
}
return false;
}
/**
* Checks if the connection string uses SSL.
*
* @param string $uri
* @return boolean
*/
function is_ssl($uri)
{
return stripos($uri, 'ssl=true') !== false || stripos($uri, 'tls=true') !== false;
}
/**
* Checks that the topology is a standalone.
*
* @param string $uri
* @return boolean
*/
function is_standalone($uri)
{
return get_primary_server($uri)->getType() === Server::TYPE_STANDALONE;
}
/**
* Converts the server type constant to a string.
*
* @see http://php.net/manual/en/class.mongodb-driver-server.php
* @param integer $type
* @return string
*/
function server_type_as_string($type)
{
switch ($type) {
case Server::TYPE_STANDALONE:
return 'Standalone';
case Server::TYPE_MONGOS:
return 'Mongos';
case Server::TYPE_POSSIBLE_PRIMARY:
return 'PossiblePrimary';
case Server::TYPE_RS_PRIMARY:
return 'RSPrimary';
case Server::TYPE_RS_SECONDARY:
return 'RSSecondary';
case Server::TYPE_RS_ARBITER:
return 'RSArbiter';
case Server::TYPE_RS_OTHER:
return 'RSOther';
case Server::TYPE_RS_GHOST:
return 'RSGhost';
default:
return 'Unknown';
}
}
/**
* Converts an errno number to a string.
*
* @see http://php.net/manual/en/errorfunc.constants.php
* @param integer $errno
* @param string
*/
function errno_as_string($errno)
{
$errors = [
'E_ERROR',
'E_WARNING',
'E_PARSE',
'E_NOTICE',
'E_CORE_ERROR',
'E_CORE_WARNING',
'E_COMPILE_ERROR',
'E_COMPILE_WARNING',
'E_USER_ERROR',
'E_USER_WARNING',
'E_USER_NOTICE',
'E_STRICT',
'E_RECOVERABLE_ERROR',
'E_DEPRECATED',
'E_USER_DEPRECATED',
'E_ALL',
];
foreach ($errors as $error) {
if ($errno === constant($error)) {
return $error;
}
}
return 'Unknown';
}
/**
* Prints a traditional hex dump of byte values and printable characters.
*
* @see http://stackoverflow.com/a/4225813/162228
* @param string $data Binary data
* @param integer $width Bytes displayed per line
*/
function hex_dump($data, $width = 16)
{
static $pad = '.'; // Placeholder for non-printable characters
static $from = '';
static $to = '';
if ($from === '') {
for ($i = 0; $i <= 0xFF; $i++) {
$from .= chr($i);
$to .= ($i >= 0x20 && $i <= 0x7E) ? chr($i) : $pad;
}
}
$hex = str_split(bin2hex($data), $width * 2);
$chars = str_split(strtr($data, $from, $to), $width);
$offset = 0;
$length = $width * 3;
foreach ($hex as $i => $line) {
printf("%6X : %-{$length}s [%s]\n", $offset, implode(' ', str_split($line, 2)), $chars[$i]);
$offset += $width;
}
}
/**
* Canonicalizes a JSON string.
*
* @param string $json
* @return string
*/
function json_canonicalize($json)
{
$json = json_encode(json_decode($json));
/* Canonicalize string values for $numberDouble to ensure they are converted
* the same as number literals in legacy and relaxed output. This is needed
* because the printf format in _bson_as_json_visit_double uses a high level
* of precision and may not produce the exponent notation expected by the
* BSON corpus tests. */
$json = preg_replace_callback(
'/{"\$numberDouble":"(-?\d+(\.\d+([eE]\+\d+)?)?)"}/',
function ($matches) {
return '{"$numberDouble":"' . json_encode(json_decode($matches[1])) . '"}';
},
$json
);
return $json;
}
/**
* Return a collection name to use for the test file.
*
* The filename will be stripped of the base path to the test suite (prefix) as
* well as the PHP file extension (suffix). Special characters (including hyphen
* for shell compatibility) will be replaced with underscores.
*
* @param string $filename
* @return string
*/
function makeCollectionNameFromFilename($filename)
{
$filename = realpath($filename);
$prefix = realpath(dirname(__FILE__) . '/..') . DIRECTORY_SEPARATOR;
$replacements = array(
// Strip test path prefix
sprintf('/^%s/', preg_quote($prefix, '/')) => '',
// Strip file extension suffix
'/\.php$/' => '',
// SKIPIFs add ".skip" between base name and extension
'/\.skip$/' => '',
// Replace special characters with underscores
sprintf('/[%s]/', preg_quote('-$/\\', '/')) => '_',
);
return preg_replace(array_keys($replacements), array_values($replacements), $filename);
}
function NEEDS($configuration) {
if (!constant($configuration)) {
exit("skip -- need '$configuration' defined");
}
}
function SLOW() {
if (getenv("SKIP_SLOW_TESTS")) {
exit("skip SKIP_SLOW_TESTS");
}
}
function loadFixtures(Manager $manager, $dbname = DATABASE_NAME, $collname = COLLECTION_NAME, $filename = null)
{
if (!$filename) {
$filename = "compress.zlib://" . __DIR__ . "/" . "PHONGO-FIXTURES.json.gz";
}
$bulk = new BulkWrite(['ordered' => false]);
$server = $manager->selectServer(new ReadPreference(ReadPreference::RP_PRIMARY));
$data = file_get_contents($filename);
$array = json_decode($data);
foreach($array as $document) {
$bulk->insert($document);
}
$retval = $server->executeBulkWrite("$dbname.$collname", $bulk);
if ($retval->getInsertedCount() !== count($array)) {
exit(sprintf('skip Fixtures were not loaded (expected: %d, actual: %d)', $total, $retval->getInsertedCount()));
}
}
function createTemporaryMongoInstance(array $options = [])
{
$id = 'mo_' . COLLECTION_NAME;
$options += [
"name" => "mongod",
"id" => $id,
'procParams' => [
'logpath' => "/tmp/MO/phongo/{$id}.log",
'ipv6' => true,
'setParameter' => [ 'enableTestCommands' => 1 ],
],
];
$opts = array(
"http" => array(
"timeout" => 60,
"method" => "PUT",
"header" => "Accept: application/json\r\n" .
"Content-type: application/x-www-form-urlencoded",
"content" => json_encode($options),
"ignore_errors" => true,
),
);
$ctx = stream_context_create($opts);
$json = file_get_contents(MONGO_ORCHESTRATION_URI . "/servers/$id", false, $ctx);
$result = json_decode($json, true);
/* Failed -- or was already started */
if (!isset($result["mongodb_uri"])) {
destroyTemporaryMongoInstance($id);
throw new Exception("Could not start temporary server instance\n");
} else {
return $result['mongodb_uri'];
}
}
function destroyTemporaryMongoInstance($id = NULL)
{
if ($id == NULL) {
$id = 'mo_' . COLLECTION_NAME;
}
$opts = array(
"http" => array(
"timeout" => 60,
"method" => "DELETE",
"header" => "Accept: application/json\r\n",
"ignore_errors" => true,
),
);
$ctx = stream_context_create($opts);
$json = file_get_contents(MONGO_ORCHESTRATION_URI . "/servers/$id", false, $ctx);
}
/**
* Converts an error level (constant or bitmask) to a string description.
*/
function severityToString(int $severity): string {
static $constants = [
'E_ERROR' => E_ERROR,
'E_WARNING' => E_WARNING,
'E_PARSE' => E_PARSE,
'E_NOTICE' => E_NOTICE,
'E_CORE_ERROR' => E_CORE_ERROR,
'E_CORE_WARNING' => E_CORE_WARNING,
'E_COMPILE_ERROR' => E_COMPILE_ERROR,
'E_COMPILE_WARNING' => E_COMPILE_WARNING,
'E_USER_ERROR' => E_USER_ERROR,
'E_USER_WARNING' => E_USER_WARNING,
'E_USER_NOTICE' => E_USER_NOTICE,
'E_STRICT' => E_STRICT,
'E_RECOVERABLE_ERROR' => E_RECOVERABLE_ERROR,
'E_DEPRECATED' => E_DEPRECATED,
'E_USER_DEPRECATED' => E_USER_DEPRECATED,
// E_ALL is handled separately
];
if ($severity === E_ALL) {
return 'E_ALL';
}
foreach ($constants as $constant => $value) {
if ($severity & $value) {
$matches[] = $constant;
}
}
return empty($matches) ? 'UNKNOWN' : implode('|', $matches);
}
/**
* Expects the callable to raise an error matching the expected severity, which
* may be a constant or bitmask. May optionally expect the error to be raised
* from a particular function. Returns the message from the raised error or
* exception, or an empty string if neither was thrown.
*/
function raises(callable $callable, int $expectedSeverity, string $expectedFromFunction = null): string
{
set_error_handler(function(int $severity, string $message, string $file, int $line) {
throw new ErrorException($message, 0, $severity, $file, $line);
});
try {
call_user_func($callable);
} catch (ErrorException $e) {
if (!($e->getSeverity() & $expectedSeverity)) {
printf("ALMOST: Got %s - expected %s\n", severityToString($e->getSeverity()), severityToString($expectedSeverity));
return $e->getMessage();
}
if ($expectedFromFunction === null) {
printf("OK: Got %s\n", severityToString($e->getSeverity()));
return $e->getMessage();
}
$fromFunction = $e->getTrace()[0]['function'];
if (strcasecmp($fromFunction, $expectedFromFunction) !== 0) {
printf("ALMOST: Got %s - but was raised from %s, not %s\n", errorLevelToString($e->getSeverity()), $fromFunction, $expectedFromFunction);
return $e->getMessage();
}
printf("OK: Got %s raised from %s\n", severityToString($e->getSeverity()), $fromFunction);
return $e->getMessage();
} catch (Throwable $e) {
printf("ALMOST: Got %s - expected %s\n", get_class($e), ErrorException::class);
return $e->getMessage();
} finally {
restore_error_handler();
}
printf("FAILED: Expected %s, but no error raised!\n", ErrorException::class);
return '';
}
/**
* Expects the callable to throw an expected exception. May optionally expect
* the exception to be thrown from a particular function. Returns the message
* from the thrown exception, or an empty string if one was not thrown.
*/
function throws(callable $callable, string $expectedException, string $expectedFromFunction = null): string
{
try {
call_user_func($callable);
} catch (Throwable $e) {
if (!($e instanceof $expectedException)) {
printf("ALMOST: Got %s - expected %s\n", get_class($e), $expectedException);
return $e->getMessage();
}
if ($expectedFromFunction === null) {
printf("OK: Got %s\n", $expectedException);
return $e->getMessage();
}
$fromFunction = $e->getTrace()[0]['function'];
if (strcasecmp($fromFunction, $expectedFromFunction) !== 0) {
printf("ALMOST: Got %s - but was thrown from %s, not %s\n", $expectedException, $fromFunction, $expectedFromFunction);
return $e->getMessage();
}
printf("OK: Got %s thrown from %s\n", $expectedException, $fromFunction);
return $e->getMessage();
}
printf("FAILED: Expected %s, but no exception thrown!\n", $expectedException);
return '';
}
function printServer(Server $server)
{
printf("server: %s:%d\n", $server->getHost(), $server->getPort());
}
function printWriteResult(WriteResult $result, $details = true)
{
printServer($result->getServer());
printf("insertedCount: %d\n", $result->getInsertedCount());
printf("matchedCount: %d\n", $result->getMatchedCount());
printf("modifiedCount: %d\n", $result->getModifiedCount());
printf("upsertedCount: %d\n", $result->getUpsertedCount());
printf("deletedCount: %d\n", $result->getDeletedCount());
foreach ($result->getUpsertedIds() as $index => $id) {
printf("upsertedId[%d]: ", $index);
var_dump($id);
}
$writeConcernError = $result->getWriteConcernError();
printWriteConcernError($writeConcernError ? $writeConcernError : null, $details);
foreach ($result->getWriteErrors() as $writeError) {
printWriteError($writeError);
}
}
function printWriteConcernError(WriteConcernError $error = null, $details)
{
if ($error) {
/* This stuff is generated by the server, no need for us to test it */
if (!$details) {
printf("writeConcernError: %s (%d)\n", $error->getMessage(), $error->getCode());
return;
}
var_dump($error);
printf("writeConcernError.message: %s\n", $error->getMessage());
printf("writeConcernError.code: %d\n", $error->getCode());
printf("writeConcernError.info: ");
var_dump($error->getInfo());
}
}
function printWriteError(WriteError $error)
{
var_dump($error);
printf("writeError[%d].message: %s\n", $error->getIndex(), $error->getMessage());
printf("writeError[%d].code: %d\n", $error->getIndex(), $error->getCode());
}
function getInsertCount($retval) {
return $retval->getInsertedCount();
}
function getModifiedCount($retval) {
return $retval->getModifiedCount();
}
function getDeletedCount($retval) {
return $retval->getDeletedCount();
}
function getUpsertedCount($retval) {
return $retval->getUpsertedCount();
}
function getWriteErrors($retval) {
return (array)$retval->getWriteErrors();
}
function def($arr) {
foreach($arr as $const => $value) {
define($const, getenv("PHONGO_TEST_$const") ?: $value);
}
}
function configureFailPoint(Manager $manager, $failPoint, $mode, array $data = [])
{
$doc = [
'configureFailPoint' => $failPoint,
'mode' => $mode,
];
if ($data) {
$doc['data'] = $data;
}
$cmd = new Command($doc);
$manager->executeCommand('admin', $cmd);
}
function configureTargetedFailPoint(Server $server, $failPoint, $mode, array $data = [])
{
$doc = array(
'configureFailPoint' => $failPoint,
'mode' => $mode,
);
if ($data) {
$doc['data'] = $data;
}
$cmd = new Command($doc);
$server->executeCommand('admin', $cmd);
}
function failMaxTimeMS(Server $server)
{
configureTargetedFailPoint($server, 'maxTimeAlwaysTimeOut', [ 'times' => 1 ]);
}
function toPHP($var, $typemap = array()) {
return MongoDB\BSON\toPHP($var, $typemap);
}
function fromPHP($var) {
return MongoDB\BSON\fromPHP($var);
}
function toJSON($var) {
return MongoDB\BSON\toJSON($var);
}
function toCanonicalExtendedJSON($var) {
return MongoDB\BSON\toCanonicalExtendedJSON($var);
}
function toRelaxedExtendedJSON($var) {
return MongoDB\BSON\toRelaxedExtendedJSON($var);
}
function fromJSON($var) {
return MongoDB\BSON\fromJSON($var);
}
/* Note: this fail point may terminate the mongod process, so you may want to
* use this in conjunction with a throwaway server. */
function failGetMore(Manager $manager)
{
/* We need to do version detection here */
$primary = $manager->selectServer(new ReadPreference('primary'));
$version = get_server_version_from_server($primary);
if (version_compare($version, "4.0", ">=")) {
/* We use 237 here, as that's the same original code that MongoD would
* throw if a cursor had already gone by the time we call getMore. This
* allows us to make things consistent with the getMore OP behaviour
* from previous mongod versions. An errorCode is required here for the
* failPoint to work. */
configureFailPoint($manager, 'failCommand', 'alwaysOn', [ 'errorCode' => 237, 'failCommands' => ['getMore'] ]);
return;
}
throw new Exception("Trying to configure a getMore fail point for a server version ($version) that doesn't support it");
}
function getAtlasConnectivityUrls(): array
{
$atlasUriString = getenv('ATLAS_CONNECTIVITY_URIS') ?: '';
if (!$atlasUriString) {
return [];
}
$rawUrls = explode("\n", $atlasUriString);
$urls = [];
foreach ($rawUrls as $url) {
$url = trim($url);
if ($url == '') {
continue;
}
$urls[] = $url;
}
return $urls;
}
Back to Directory
File Manager
<