Unverified Commit f2ddea4f authored by Andreas Braun's avatar Andreas Braun

Merge pull request #715

parents 02bd5856 37c8e99f
...@@ -5,6 +5,14 @@ addons: ...@@ -5,6 +5,14 @@ addons:
apt: apt:
packages: packages:
- gdb - gdb
- libcurl3
- libgssapi-krb5-2
- libkrb5-dbg
- libldap-2.4-2
- libpcap0.8
- libsasl2-2
- snmp
- openssl
cache: cache:
directories: directories:
...@@ -17,7 +25,7 @@ env: ...@@ -17,7 +25,7 @@ env:
- DRIVER_VERSION=1.7.0 - DRIVER_VERSION=1.7.0
# TODO: remove once a 1.7 driver release has been tagged # TODO: remove once a 1.7 driver release has been tagged
- DRIVER_BRANCH="master" - DRIVER_BRANCH="master"
- SERVER_DISTRO=ubuntu1604 - SERVER_DISTRO=enterprise-ubuntu1604
- SERVER_VERSION=4.2.0 - SERVER_VERSION=4.2.0
- DEPLOYMENT=STANDALONE - DEPLOYMENT=STANDALONE
- COMPOSER_OPTIONS= - COMPOSER_OPTIONS=
...@@ -65,7 +73,7 @@ jobs: ...@@ -65,7 +73,7 @@ jobs:
php: "7.0" php: "7.0"
dist: trusty dist: trusty
env: env:
- SERVER_DISTRO=ubuntu1404 - SERVER_DISTRO=enterprise-ubuntu1404
- SERVER_VERSION=3.0.15 - SERVER_VERSION=3.0.15
- DEPLOYMENT=STANDALONE_OLD - DEPLOYMENT=STANDALONE_OLD
- stage: Test - stage: Test
...@@ -131,7 +139,7 @@ jobs: ...@@ -131,7 +139,7 @@ jobs:
before_install: before_install:
- pip install "mongo-orchestration>=0.6.7,<1.0" --user `whoami` - pip install "mongo-orchestration>=0.6.7,<1.0" --user `whoami`
- export SERVER_FILENAME=mongodb-linux-x86_64-${SERVER_DISTRO}-${SERVER_VERSION} - export SERVER_FILENAME=mongodb-linux-x86_64-${SERVER_DISTRO}-${SERVER_VERSION}
- wget -qO- http://fastdl.mongodb.org/linux/${SERVER_FILENAME}.tgz | tar xz - wget -qO- https://downloads.mongodb.com/linux/${SERVER_FILENAME}.tgz | tar xz
- export PATH=${PWD}/${SERVER_FILENAME}/bin:${PATH} - export PATH=${PWD}/${SERVER_FILENAME}/bin:${PATH}
- mongod --version - mongod --version
- mongo-orchestration --version - mongo-orchestration --version
......
#!/bin/sh #!/bin/sh
if [ "${TRAVIS_OS_NAME}" != "osx" ]; then if [ "${TRAVIS_OS_NAME}" = "osx" ]; then
# https://www.ics.uci.edu/~pattis/common/handouts/macmingweclipse/allexperimental/mac-gdb-install.html # https://www.ics.uci.edu/~pattis/common/handouts/macmingweclipse/allexperimental/mac-gdb-install.html
echo "Cannot debug core files on macOS: ${1}" echo "Cannot debug core files on macOS: ${1}"
exit 1 exit 1
......
...@@ -26,9 +26,15 @@ use function is_array; ...@@ -26,9 +26,15 @@ use function is_array;
use function is_object; use function is_object;
use function is_string; use function is_string;
use function key; use function key;
use function ob_get_clean;
use function ob_start;
use function parse_url; use function parse_url;
use function phpinfo;
use function preg_match; use function preg_match;
use function preg_quote;
use function sprintf;
use function version_compare; use function version_compare;
use const INFO_MODULES;
abstract class FunctionalTestCase extends TestCase abstract class FunctionalTestCase extends TestCase
{ {
...@@ -375,6 +381,17 @@ abstract class FunctionalTestCase extends TestCase ...@@ -375,6 +381,17 @@ abstract class FunctionalTestCase extends TestCase
} }
} }
protected function skipIfClientSideEncryptionIsNotSupported()
{
if (version_compare($this->getFeatureCompatibilityVersion(), '4.2', '<')) {
$this->markTestSkipped('Client Side Encryption only supported on FCV 4.2 or higher');
}
if ($this->getModuleInfo('libmongocrypt') === 'disabled') {
$this->markTestSkipped('Client Side Encryption is not enabled in the MongoDB extension');
}
}
protected function skipIfTransactionsAreNotSupported() protected function skipIfTransactionsAreNotSupported()
{ {
if ($this->getPrimaryServer()->getType() === Server::TYPE_STANDALONE) { if ($this->getPrimaryServer()->getType() === Server::TYPE_STANDALONE) {
...@@ -420,6 +437,26 @@ abstract class FunctionalTestCase extends TestCase ...@@ -420,6 +437,26 @@ abstract class FunctionalTestCase extends TestCase
} }
} }
/**
* @param string $row
*
* @return string|null
*/
private function getModuleInfo($row)
{
ob_start();
phpinfo(INFO_MODULES);
$info = ob_get_clean();
$pattern = sprintf('/^%s([\w ]+)$/m', preg_quote($row . ' => '));
if (preg_match($pattern, $info, $matches) !== 1) {
return null;
}
return $matches[1];
}
/** /**
* Checks if the failCommand command is supported on this server version * Checks if the failCommand command is supported on this server version
* *
......
...@@ -27,8 +27,6 @@ class ChangeStreamsSpecTest extends FunctionalTestCase ...@@ -27,8 +27,6 @@ class ChangeStreamsSpecTest extends FunctionalTestCase
/** /**
* Assert that the expected and actual command documents match. * Assert that the expected and actual command documents match.
* *
* Note: this method may modify the $expected object.
*
* @param stdClass $expected Expected command document * @param stdClass $expected Expected command document
* @param stdClass $actual Actual command document * @param stdClass $actual Actual command document
*/ */
...@@ -180,7 +178,7 @@ class ChangeStreamsSpecTest extends FunctionalTestCase ...@@ -180,7 +178,7 @@ class ChangeStreamsSpecTest extends FunctionalTestCase
switch ($test->target) { switch ($test->target) {
case 'client': case 'client':
return $context->client->watch($pipeline, $options); return $context->getClient()->watch($pipeline, $options);
case 'database': case 'database':
return $context->getDatabase()->watch($pipeline, $options); return $context->getDatabase()->watch($pipeline, $options);
case 'collection': case 'collection':
...@@ -228,7 +226,7 @@ class ChangeStreamsSpecTest extends FunctionalTestCase ...@@ -228,7 +226,7 @@ class ChangeStreamsSpecTest extends FunctionalTestCase
{ {
$context = $this->getContext(); $context = $this->getContext();
$database = $context->client->selectDatabase($databaseName); $database = $context->getClient()->selectDatabase($databaseName);
$database->drop($context->defaultWriteOptions); $database->drop($context->defaultWriteOptions);
$database->createCollection($collectionName, $context->defaultWriteOptions); $database->createCollection($collectionName, $context->defaultWriteOptions);
} }
......
This diff is collapsed.
...@@ -77,6 +77,16 @@ class CommandExpectations implements CommandSubscriber ...@@ -77,6 +77,16 @@ class CommandExpectations implements CommandSubscriber
return $o; return $o;
} }
public static function fromClientSideEncryption(array $expectedEvents)
{
$o = new self($expectedEvents);
$o->ignoreCommandFailed = true;
$o->ignoreCommandSucceeded = true;
return $o;
}
public static function fromCommandMonitoring(array $expectedEvents) public static function fromCommandMonitoring(array $expectedEvents)
{ {
return new self($expectedEvents); return new self($expectedEvents);
......
...@@ -8,11 +8,14 @@ use MongoDB\Driver\ReadConcern; ...@@ -8,11 +8,14 @@ use MongoDB\Driver\ReadConcern;
use MongoDB\Driver\ReadPreference; use MongoDB\Driver\ReadPreference;
use MongoDB\Driver\Session; use MongoDB\Driver\Session;
use MongoDB\Driver\WriteConcern; use MongoDB\Driver\WriteConcern;
use PHPUnit\Framework\SkippedTestError;
use stdClass; use stdClass;
use function array_diff_key; use function array_diff_key;
use function array_keys; use function array_keys;
use function getenv;
use function implode; use function implode;
use function mt_rand; use function mt_rand;
use function uniqid;
/** /**
* Execution context for spec tests. * Execution context for spec tests.
...@@ -26,7 +29,7 @@ final class Context ...@@ -26,7 +29,7 @@ final class Context
public $bucketName; public $bucketName;
/** @var Client|null */ /** @var Client|null */
public $client; private $client;
/** @var string */ /** @var string */
public $collectionName; public $collectionName;
...@@ -55,6 +58,12 @@ final class Context ...@@ -55,6 +58,12 @@ final class Context
/** @var object */ /** @var object */
public $session1Lsid; public $session1Lsid;
/** @var Client|null */
private $encryptedClient;
/** @var bool */
private $useEncryptedClient = false;
/** /**
* @param string $databaseName * @param string $databaseName
* @param string $collectionName * @param string $collectionName
...@@ -66,6 +75,20 @@ final class Context ...@@ -66,6 +75,20 @@ final class Context
$this->outcomeCollectionName = $collectionName; $this->outcomeCollectionName = $collectionName;
} }
public function disableEncryption()
{
$this->useEncryptedClient = false;
}
public function enableEncryption()
{
if (! $this->encryptedClient instanceof Client) {
throw new LogicException('Cannot enable encryption without autoEncryption options');
}
$this->useEncryptedClient = true;
}
public static function fromChangeStreams(stdClass $test, $databaseName, $collectionName) public static function fromChangeStreams(stdClass $test, $databaseName, $collectionName)
{ {
$o = new self($databaseName, $collectionName); $o = new self($databaseName, $collectionName);
...@@ -75,6 +98,41 @@ final class Context ...@@ -75,6 +98,41 @@ final class Context
return $o; return $o;
} }
public static function fromClientSideEncryption(stdClass $test, $databaseName, $collectionName)
{
$o = new self($databaseName, $collectionName);
$clientOptions = isset($test->clientOptions) ? (array) $test->clientOptions : [];
/* mongocryptd caches collection information, which causes test failures
* if we reuse the client. Thus, we add a random value to ensure we're
* creating a new client for each test. */
$driverOptions = ['random' => uniqid()];
$autoEncryptionOptions = [];
if (isset($clientOptions['autoEncryptOpts'])) {
$autoEncryptionOptions = (array) $clientOptions['autoEncryptOpts'] + ['keyVaultNamespace' => 'admin.datakeys'];
unset($clientOptions['autoEncryptOpts']);
if (isset($autoEncryptionOptions['kmsProviders']->aws)) {
$autoEncryptionOptions['kmsProviders']->aws = self::getAWSCredentials();
}
}
if (isset($test->outcome->collection->name)) {
$o->outcomeCollectionName = $test->outcome->collection->name;
}
$o->client = new Client(FunctionalTestCase::getUri(), $clientOptions, $driverOptions);
if ($autoEncryptionOptions !== []) {
$o->encryptedClient = new Client(FunctionalTestCase::getUri(), $clientOptions, $driverOptions + ['autoEncryption' => $autoEncryptionOptions]);
}
return $o;
}
public static function fromCommandMonitoring(stdClass $test, $databaseName, $collectionName) public static function fromCommandMonitoring(stdClass $test, $databaseName, $collectionName)
{ {
$o = new self($databaseName, $collectionName); $o = new self($databaseName, $collectionName);
...@@ -173,12 +231,29 @@ final class Context ...@@ -173,12 +231,29 @@ final class Context
return $o; return $o;
} }
/**
* @return array
*
* @throws SkippedTestError
*/
public static function getAWSCredentials()
{
if (! getenv('AWS_ACCESS_KEY_ID') || ! getenv('AWS_SECRET_ACCESS_KEY')) {
throw new SkippedTestError('Please configure AWS credentials to use AWS KMS provider.');
}
return [
'accessKeyId' => getenv('AWS_ACCESS_KEY_ID'),
'secretAccessKey' => getenv('AWS_SECRET_ACCESS_KEY'),
];
}
/** /**
* @return Client * @return Client
*/ */
public function getClient() public function getClient()
{ {
return $this->client; return $this->useEncryptedClient && $this->encryptedClient ? $this->encryptedClient : $this->client;
} }
public function getCollection(array $collectionOptions = []) public function getCollection(array $collectionOptions = [])
...@@ -310,7 +385,7 @@ final class Context ...@@ -310,7 +385,7 @@ final class Context
public function selectCollection($databaseName, $collectionName, array $collectionOptions = []) public function selectCollection($databaseName, $collectionName, array $collectionOptions = [])
{ {
return $this->client->selectCollection( return $this->getClient()->selectCollection(
$databaseName, $databaseName,
$collectionName, $collectionName,
$this->prepareOptions($collectionOptions) $this->prepareOptions($collectionOptions)
...@@ -319,7 +394,7 @@ final class Context ...@@ -319,7 +394,7 @@ final class Context
public function selectDatabase($databaseName, array $databaseOptions = []) public function selectDatabase($databaseName, array $databaseOptions = [])
{ {
return $this->client->selectDatabase( return $this->getClient()->selectDatabase(
$databaseName, $databaseName,
$this->prepareOptions($databaseOptions) $this->prepareOptions($databaseOptions)
); );
......
...@@ -17,8 +17,6 @@ class CrudSpecTest extends FunctionalTestCase ...@@ -17,8 +17,6 @@ class CrudSpecTest extends FunctionalTestCase
/** /**
* Assert that the expected and actual command documents match. * Assert that the expected and actual command documents match.
* *
* Note: this method may modify the $expected object.
*
* @param stdClass $expected Expected command document * @param stdClass $expected Expected command document
* @param stdClass $actual Actual command document * @param stdClass $actual Actual command document
*/ */
......
...@@ -4,9 +4,28 @@ namespace MongoDB\Tests\SpecTests; ...@@ -4,9 +4,28 @@ namespace MongoDB\Tests\SpecTests;
use ArrayObject; use ArrayObject;
use InvalidArgumentException; use InvalidArgumentException;
use MongoDB\BSON\BinaryInterface;
use MongoDB\BSON\DBPointer;
use MongoDB\BSON\Decimal128;
use MongoDB\BSON\Int64;
use MongoDB\BSON\Javascript;
use MongoDB\BSON\MaxKey;
use MongoDB\BSON\MinKey;
use MongoDB\BSON\ObjectId;
use MongoDB\BSON\Regex;
use MongoDB\BSON\Symbol;
use MongoDB\BSON\Timestamp;
use MongoDB\BSON\Undefined;
use MongoDB\BSON\UTCDateTime;
use MongoDB\Model\BSONArray; use MongoDB\Model\BSONArray;
use MongoDB\Model\BSONDocument; use MongoDB\Model\BSONDocument;
use PHPUnit\Framework\Constraint\Constraint; use PHPUnit\Framework\Constraint\Constraint;
use PHPUnit\Framework\Constraint\IsInstanceOf;
use PHPUnit\Framework\Constraint\IsNull;
use PHPUnit\Framework\Constraint\IsType;
use PHPUnit\Framework\Constraint\LogicalAnd;
use PHPUnit\Framework\Constraint\LogicalNot;
use PHPUnit\Framework\Constraint\LogicalOr;
use RuntimeException; use RuntimeException;
use SebastianBergmann\Comparator\ComparisonFailure; use SebastianBergmann\Comparator\ComparisonFailure;
use SebastianBergmann\Comparator\Factory; use SebastianBergmann\Comparator\Factory;
...@@ -14,11 +33,14 @@ use stdClass; ...@@ -14,11 +33,14 @@ use stdClass;
use Symfony\Bridge\PhpUnit\ConstraintTrait; use Symfony\Bridge\PhpUnit\ConstraintTrait;
use function array_values; use function array_values;
use function get_class; use function get_class;
use function gettype;
use function in_array; use function in_array;
use function is_array; use function is_array;
use function is_object; use function is_object;
use function is_scalar; use function is_scalar;
use function method_exists;
use function sprintf; use function sprintf;
use const PHP_INT_SIZE;
/** /**
* Constraint that checks if one document matches another. * Constraint that checks if one document matches another.
...@@ -112,6 +134,128 @@ class DocumentsMatchConstraint extends Constraint ...@@ -112,6 +134,128 @@ class DocumentsMatchConstraint extends Constraint
} }
} }
/**
* @param string $expectedType
* @param mixed $actualValue
*/
private function assertBSONType($expectedType, $actualValue)
{
switch ($expectedType) {
case 'double':
(new IsType('float'))->evaluate($actualValue);
return;
case 'string':
(new IsType('string'))->evaluate($actualValue);
return;
case 'object':
$constraints = [
new IsType('object'),
new LogicalNot(new IsInstanceOf(BSONArray::class)),
];
// LogicalAnd::fromConstraints was introduced in PHPUnit 6.5.0.
// This check can be removed when the PHPUnit dependency is bumped to that version
if (method_exists(LogicalAnd::class, 'fromConstraints')) {
$constraint = LogicalAnd::fromConstraints(...$constraints);
} else {
$constraint = new LogicalAnd();
$constraint->setConstraints($constraints);
}
$constraint->evaluate($actualValue);
return;
case 'array':
$constraints = [
new IsType('array'),
new IsInstanceOf(BSONArray::class),
];
// LogicalOr::fromConstraints was introduced in PHPUnit 6.5.0.
// This check can be removed when the PHPUnit dependency is bumped to that version
if (method_exists(LogicalOr::class, 'fromConstraints')) {
$constraint = LogicalOr::fromConstraints(...$constraints);
} else {
$constraint = new LogicalOr();
$constraint->setConstraints($constraints);
}
$constraint->evaluate($actualValue);
return;
case 'binData':
(new IsInstanceOf(BinaryInterface::class))->evaluate($actualValue);
return;
case 'undefined':
(new IsInstanceOf(Undefined::class))->evaluate($actualValue);
return;
case 'objectId':
(new IsInstanceOf(ObjectId::class))->evaluate($actualValue);
return;
case 'boolean':
(new IsType('bool'))->evaluate($actualValue);
return;
case 'date':
(new IsInstanceOf(UTCDateTime::class))->evaluate($actualValue);
return;
case 'null':
(new IsNull())->evaluate($actualValue);
return;
case 'regex':
(new IsInstanceOf(Regex::class))->evaluate($actualValue);
return;
case 'dbPointer':
(new IsInstanceOf(DBPointer::class))->evaluate($actualValue);
return;
case 'javascript':
(new IsInstanceOf(Javascript::class))->evaluate($actualValue);
return;
case 'symbol':
(new IsInstanceOf(Symbol::class))->evaluate($actualValue);
return;
case 'int':
(new IsType('int'))->evaluate($actualValue);
return;
case 'timestamp':
(new IsInstanceOf(Timestamp::class))->evaluate($actualValue);
return;
case 'long':
if (PHP_INT_SIZE == 4) {
(new IsInstanceOf(Int64::class))->evaluate($actualValue);
} else {
(new IsType('int'))->evaluate($actualValue);
}
return;
case 'decimal':
(new IsInstanceOf(Decimal128::class))->evaluate($actualValue);
return;
case 'minKey':
(new IsInstanceOf(MinKey::class))->evaluate($actualValue);
return;
case 'maxKey':
(new IsInstanceOf(MaxKey::class))->evaluate($actualValue);
return;
}
}
/** /**
* Compares two documents recursively. * Compares two documents recursively.
* *
...@@ -144,6 +288,11 @@ class DocumentsMatchConstraint extends Constraint ...@@ -144,6 +288,11 @@ class DocumentsMatchConstraint extends Constraint
$actualValue = $actual[$key]; $actualValue = $actual[$key];
if ($expectedValue instanceof BSONDocument && isset($expectedValue['$$type'])) {
$this->assertBSONType($expectedValue['$$type'], $actualValue);
continue;
}
if (($expectedValue instanceof BSONArray && $actualValue instanceof BSONArray) || if (($expectedValue instanceof BSONArray && $actualValue instanceof BSONArray) ||
($expectedValue instanceof BSONDocument && $actualValue instanceof BSONDocument)) { ($expectedValue instanceof BSONDocument && $actualValue instanceof BSONDocument)) {
$this->assertEquals($expectedValue, $actualValue, $this->ignoreExtraKeysInEmbedded, $keyPrefix . $key . '.'); $this->assertEquals($expectedValue, $actualValue, $this->ignoreExtraKeysInEmbedded, $keyPrefix . $key . '.');
...@@ -165,8 +314,11 @@ class DocumentsMatchConstraint extends Constraint ...@@ -165,8 +314,11 @@ class DocumentsMatchConstraint extends Constraint
continue; continue;
} }
$expectedType = is_object($expectedValue) ? get_class($expectedValue) : gettype($expectedValue);
$actualType = is_object($expectedValue) ? get_class($actualValue) : gettype($actualValue);
// Workaround for ObjectComparator printing the whole actual object // Workaround for ObjectComparator printing the whole actual object
if (get_class($expectedValue) !== get_class($actualValue)) { if ($expectedType !== $actualType) {
throw new ComparisonFailure( throw new ComparisonFailure(
$expectedValue, $expectedValue,
$actualValue, $actualValue,
...@@ -174,10 +326,10 @@ class DocumentsMatchConstraint extends Constraint ...@@ -174,10 +326,10 @@ class DocumentsMatchConstraint extends Constraint
'', '',
false, false,
sprintf( sprintf(
'Field path "%s": %s is not instance of expected class "%s".', 'Field path "%s": %s is not instance of expected type "%s".',
$keyPrefix . $key, $keyPrefix . $key,
$this->exporter()->shortenedExport($actualValue), $this->exporter()->shortenedExport($actualValue),
get_class($expectedValue) $expectedType
) )
); );
} }
...@@ -293,6 +445,12 @@ class DocumentsMatchConstraint extends Constraint ...@@ -293,6 +445,12 @@ class DocumentsMatchConstraint extends Constraint
$bson[$key] = $this->prepareBSON($value, false, $sortKeys); $bson[$key] = $this->prepareBSON($value, false, $sortKeys);
continue; continue;
} }
/* Convert Int64 objects to integers on 64-bit platforms for
* compatibility reasons. */
if ($value instanceof Int64 && PHP_INT_SIZE != 4) {
$bson[$key] = (int) ((string) $value);
}
} }
return $bson; return $bson;
......
...@@ -2,9 +2,23 @@ ...@@ -2,9 +2,23 @@
namespace MongoDB\Tests\SpecTests; namespace MongoDB\Tests\SpecTests;
use MongoDB\BSON\Binary;
use MongoDB\BSON\Decimal128;
use MongoDB\BSON\Javascript;
use MongoDB\BSON\MaxKey;
use MongoDB\BSON\MinKey;
use MongoDB\BSON\ObjectId;
use MongoDB\BSON\Regex;
use MongoDB\BSON\Timestamp;
use MongoDB\BSON\UTCDateTime;
use MongoDB\Model\BSONArray; use MongoDB\Model\BSONArray;
use MongoDB\Model\BSONDocument;
use MongoDB\Tests\TestCase; use MongoDB\Tests\TestCase;
use PHPUnit\Framework\ExpectationFailedException; use PHPUnit\Framework\ExpectationFailedException;
use function MongoDB\BSON\fromJSON;
use function MongoDB\BSON\toPHP;
use function unserialize;
use const PHP_INT_SIZE;
class DocumentsMatchConstraintTest extends TestCase class DocumentsMatchConstraintTest extends TestCase
{ {
...@@ -57,6 +71,46 @@ class DocumentsMatchConstraintTest extends TestCase ...@@ -57,6 +71,46 @@ class DocumentsMatchConstraintTest extends TestCase
$this->assertResult(true, $c, ['x' => '42', 'y' => 42, 'z' => ['a' => 24]], 'Exact match'); $this->assertResult(true, $c, ['x' => '42', 'y' => 42, 'z' => ['a' => 24]], 'Exact match');
} }
/**
* @dataProvider provideBSONTypes
*/
public function testBSONTypeAssertions($type, $value)
{
$constraint = new DocumentsMatchConstraint(['x' => ['$$type' => $type]]);
$this->assertResult(true, $constraint, ['x' => $value], 'Type matches');
}
public function provideBSONTypes()
{
$undefined = toPHP(fromJSON('{ "undefined": {"$undefined": true} }'));
$symbol = toPHP(fromJSON('{ "symbol": {"$symbol": "test"} }'));
$dbPointer = toPHP(fromJSON('{ "dbPointer": {"$dbPointer": {"$ref": "phongo.test", "$id" : { "$oid" : "5a2e78accd485d55b405ac12" } }} }'));
return [
'double' => ['double', 1.4],
'string' => ['string', 'foo'],
'object' => ['object', new BSONDocument()],
'array' => ['array', ['foo']],
'binData' => ['binData', new Binary('', 0)],
'undefined' => ['undefined', $undefined->undefined],
'objectId' => ['objectId', new ObjectId()],
'boolean' => ['boolean', true],
'date' => ['date', new UTCDateTime()],
'null' => ['null', null],
'regex' => ['regex', new Regex('.*')],
'dbPointer' => ['dbPointer', $dbPointer->dbPointer],
'javascript' => ['javascript', new Javascript('foo = 1;')],
'symbol' => ['symbol', $symbol->symbol],
'int' => ['int', 1],
'timestamp' => ['timestamp', new Timestamp(0, 0)],
'long' => ['long', PHP_INT_SIZE == 4 ? unserialize('C:18:"MongoDB\BSON\Int64":38:{a:1:{s:7:"integer";s:10:"4294967296";}}') : 4294967296],
'decimal' => ['decimal', new Decimal128('18446744073709551616')],
'minKey' => ['minKey', new MinKey()],
'maxKey' => ['maxKey', new MaxKey()],
];
}
/** /**
* @dataProvider errorMessageProvider * @dataProvider errorMessageProvider
*/ */
...@@ -100,7 +154,7 @@ class DocumentsMatchConstraintTest extends TestCase ...@@ -100,7 +154,7 @@ class DocumentsMatchConstraintTest extends TestCase
['foo' => '42'], ['foo' => '42'],
], ],
'Type mismatch' => [ 'Type mismatch' => [
'Field path "foo": MongoDB\Model\BSONDocument Object (...) is not instance of expected class "MongoDB\Model\BSONArray".', 'Field path "foo": MongoDB\Model\BSONDocument Object (...) is not instance of expected type "MongoDB\Model\BSONArray".',
new DocumentsMatchConstraint(['foo' => ['bar']]), new DocumentsMatchConstraint(['foo' => ['bar']]),
['foo' => (object) ['bar']], ['foo' => (object) ['bar']],
], ],
......
...@@ -75,6 +75,11 @@ final class ErrorExpectation ...@@ -75,6 +75,11 @@ final class ErrorExpectation
return $o; return $o;
} }
public static function fromClientSideEncryption(stdClass $operation)
{
return self::fromGenericOperation($operation);
}
public static function fromCrud(stdClass $result) public static function fromCrud(stdClass $result)
{ {
$o = new self(); $o = new self();
...@@ -113,41 +118,7 @@ final class ErrorExpectation ...@@ -113,41 +118,7 @@ final class ErrorExpectation
*/ */
public static function fromTransactions(stdClass $operation) public static function fromTransactions(stdClass $operation)
{ {
$o = new self(); return self::fromGenericOperation($operation);
if (isset($operation->error)) {
$o->isExpected = $operation->error;
}
$result = isset($operation->result) ? $operation->result : null;
if (isset($result->errorContains)) {
$o->messageContains = $result->errorContains;
$o->isExpected = true;
}
if (isset($result->errorCodeName)) {
$o->codeName = $result->errorCodeName;
$o->isExpected = true;
}
if (isset($result->errorLabelsContain)) {
if (! self::isArrayOfStrings($result->errorLabelsContain)) {
throw InvalidArgumentException::invalidType('errorLabelsContain', $result->errorLabelsContain, 'string[]');
}
$o->includedLabels = $result->errorLabelsContain;
$o->isExpected = true;
}
if (isset($result->errorLabelsOmit)) {
if (! self::isArrayOfStrings($result->errorLabelsOmit)) {
throw InvalidArgumentException::invalidType('errorLabelsOmit', $result->errorLabelsOmit, 'string[]');
}
$o->excludedLabels = $result->errorLabelsOmit;
$o->isExpected = true;
}
return $o;
} }
public static function noError() public static function noError()
...@@ -173,7 +144,7 @@ final class ErrorExpectation ...@@ -173,7 +144,7 @@ final class ErrorExpectation
$test->assertNotNull($actual); $test->assertNotNull($actual);
if (isset($this->messageContains)) { if (isset($this->messageContains) && $this->messageContains !== '') {
$test->assertStringContainsStringIgnoringCase($this->messageContains, $actual->getMessage()); $test->assertStringContainsStringIgnoringCase($this->messageContains, $actual->getMessage());
} }
...@@ -232,6 +203,48 @@ final class ErrorExpectation ...@@ -232,6 +203,48 @@ final class ErrorExpectation
$test->assertSame($this->codeName, $result->codeName); $test->assertSame($this->codeName, $result->codeName);
} }
/**
* @throws InvalidArgumentException
*/
private static function fromGenericOperation(stdClass $operation)
{
$o = new self();
if (isset($operation->error)) {
$o->isExpected = $operation->error;
}
$result = isset($operation->result) ? $operation->result : null;
if (isset($result->errorContains)) {
$o->messageContains = $result->errorContains;
$o->isExpected = true;
}
if (isset($result->errorCodeName)) {
$o->codeName = $result->errorCodeName;
$o->isExpected = true;
}
if (isset($result->errorLabelsContain)) {
if (! self::isArrayOfStrings($result->errorLabelsContain)) {
throw InvalidArgumentException::invalidType('errorLabelsContain', $result->errorLabelsContain, 'string[]');
}
$o->includedLabels = $result->errorLabelsContain;
$o->isExpected = true;
}
if (isset($result->errorLabelsOmit)) {
if (! self::isArrayOfStrings($result->errorLabelsOmit)) {
throw InvalidArgumentException::invalidType('errorLabelsOmit', $result->errorLabelsOmit, 'string[]');
}
$o->excludedLabels = $result->errorLabelsOmit;
$o->isExpected = true;
}
return $o;
}
private static function isArrayOfStrings($array) private static function isArrayOfStrings($array)
{ {
if (! is_array($array)) { if (! is_array($array)) {
......
...@@ -98,8 +98,9 @@ class FunctionalTestCase extends BaseFunctionalTestCase ...@@ -98,8 +98,9 @@ class FunctionalTestCase extends BaseFunctionalTestCase
* Assert data within the outcome collection. * Assert data within the outcome collection.
* *
* @param array $expectedDocuments * @param array $expectedDocuments
* @param int $resultExpectation
*/ */
protected function assertOutcomeCollectionData(array $expectedDocuments) protected function assertOutcomeCollectionData(array $expectedDocuments, $resultExpectation = ResultExpectation::ASSERT_SAME_DOCUMENT)
{ {
$outcomeCollection = $this->getOutcomeCollection($this->getContext()->outcomeReadOptions); $outcomeCollection = $this->getOutcomeCollection($this->getContext()->outcomeReadOptions);
...@@ -111,7 +112,19 @@ class FunctionalTestCase extends BaseFunctionalTestCase ...@@ -111,7 +112,19 @@ class FunctionalTestCase extends BaseFunctionalTestCase
list($expectedDocument, $actualDocument) = $documents; list($expectedDocument, $actualDocument) = $documents;
$this->assertNotNull($expectedDocument); $this->assertNotNull($expectedDocument);
$this->assertNotNull($actualDocument); $this->assertNotNull($actualDocument);
$this->assertSameDocument($expectedDocument, $actualDocument);
switch ($resultExpectation) {
case ResultExpectation::ASSERT_SAME_DOCUMENT:
$this->assertSameDocument($expectedDocument, $actualDocument);
break;
case ResultExpectation::ASSERT_DOCUMENTS_MATCH:
$this->assertDocumentsMatch($expectedDocument, $actualDocument);
break;
default:
$this->fail(sprintf('Invalid result expectation "%d" for %s', $resultExpectation, __METHOD__));
}
} }
} }
...@@ -220,6 +233,7 @@ class FunctionalTestCase extends BaseFunctionalTestCase ...@@ -220,6 +233,7 @@ class FunctionalTestCase extends BaseFunctionalTestCase
$context = $this->getContext(); $context = $this->getContext();
$collection = $collectionName ? $context->selectCollection($context->databaseName, $collectionName) : $context->getCollection(); $collection = $collectionName ? $context->selectCollection($context->databaseName, $collectionName) : $context->getCollection();
$collection->insertMany($documents, $context->defaultWriteOptions); $collection->insertMany($documents, $context->defaultWriteOptions);
return; return;
......
...@@ -116,6 +116,20 @@ final class Operation ...@@ -116,6 +116,20 @@ final class Operation
return $o; return $o;
} }
public static function fromClientSideEncryption(stdClass $operation)
{
$o = new self($operation);
$o->errorExpectation = ErrorExpectation::fromClientSideEncryption($operation);
$o->resultExpectation = ResultExpectation::fromClientSideEncryption($operation, $o->getResultAssertionType());
if (isset($operation->collectionOptions)) {
$o->collectionOptions = (array) $operation->collectionOptions;
}
return $o;
}
public static function fromCommandMonitoring(stdClass $operation) public static function fromCommandMonitoring(stdClass $operation)
{ {
$o = new self($operation); $o = new self($operation);
......
...@@ -9,7 +9,6 @@ use MongoDB\Driver\WriteResult; ...@@ -9,7 +9,6 @@ use MongoDB\Driver\WriteResult;
use MongoDB\Exception\InvalidArgumentException; use MongoDB\Exception\InvalidArgumentException;
use MongoDB\InsertManyResult; use MongoDB\InsertManyResult;
use MongoDB\InsertOneResult; use MongoDB\InsertOneResult;
use MongoDB\Tests\TestCase;
use MongoDB\UpdateResult; use MongoDB\UpdateResult;
use stdClass; use stdClass;
use function call_user_func; use function call_user_func;
...@@ -34,6 +33,7 @@ final class ResultExpectation ...@@ -34,6 +33,7 @@ final class ResultExpectation
const ASSERT_MATCHES_DOCUMENT = 9; const ASSERT_MATCHES_DOCUMENT = 9;
const ASSERT_NULL = 10; const ASSERT_NULL = 10;
const ASSERT_CALLABLE = 11; const ASSERT_CALLABLE = 11;
const ASSERT_DOCUMENTS_MATCH = 12;
/** @var integer */ /** @var integer */
private $assertionType = self::ASSERT_NOTHING; private $assertionType = self::ASSERT_NOTHING;
...@@ -85,6 +85,19 @@ final class ResultExpectation ...@@ -85,6 +85,19 @@ final class ResultExpectation
return $o; return $o;
} }
public static function fromClientSideEncryption(stdClass $operation, $defaultAssertionType)
{
if (property_exists($operation, 'result') && ! self::isErrorResult($operation->result)) {
$assertionType = $operation->result === null ? self::ASSERT_NULL : $defaultAssertionType;
$expectedValue = $operation->result;
} else {
$assertionType = self::ASSERT_NOTHING;
$expectedValue = null;
}
return new self($assertionType, $expectedValue);
}
public static function fromCrud(stdClass $operation, $defaultAssertionType) public static function fromCrud(stdClass $operation, $defaultAssertionType)
{ {
if (property_exists($operation, 'result') && ! self::isErrorResult($operation->result)) { if (property_exists($operation, 'result') && ! self::isErrorResult($operation->result)) {
...@@ -140,11 +153,11 @@ final class ResultExpectation ...@@ -140,11 +153,11 @@ final class ResultExpectation
/** /**
* Assert that the result expectation matches the actual outcome. * Assert that the result expectation matches the actual outcome.
* *
* @param TestCase $test Test instance for performing assertions * @param FunctionalTestCase $test Test instance for performing assertions
* @param mixed $result Result (if any) from the actual outcome * @param mixed $result Result (if any) from the actual outcome
* @throws LogicException if the assertion type is unsupported * @throws LogicException if the assertion type is unsupported
*/ */
public function assert(TestCase $test, $actual) public function assert(FunctionalTestCase $test, $actual)
{ {
$expected = $this->expectedValue; $expected = $this->expectedValue;
...@@ -274,6 +287,10 @@ final class ResultExpectation ...@@ -274,6 +287,10 @@ final class ResultExpectation
$test->assertSameDocuments($expected, $actual); $test->assertSameDocuments($expected, $actual);
break; break;
case self::ASSERT_DOCUMENTS_MATCH:
$test->assertDocumentsMatch($expected, $actual);
break;
case self::ASSERT_UPDATE: case self::ASSERT_UPDATE:
$test->assertInstanceOf(UpdateResult::class, $actual); $test->assertInstanceOf(UpdateResult::class, $actual);
......
...@@ -28,8 +28,6 @@ class RetryableReadsSpecTest extends FunctionalTestCase ...@@ -28,8 +28,6 @@ class RetryableReadsSpecTest extends FunctionalTestCase
/** /**
* Assert that the expected and actual command documents match. * Assert that the expected and actual command documents match.
* *
* Note: this method may modify the $expected object.
*
* @param stdClass $expected Expected command document * @param stdClass $expected Expected command document
* @param stdClass $actual Actual command document * @param stdClass $actual Actual command document
*/ */
......
{
"status": {
"$numberInt": "1"
},
"_id": {
"$binary": {
"base64": "AWSAAAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
},
"masterKey": {
"region": "us-east-1",
"key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0",
"provider": "aws"
},
"updateDate": {
"$date": {
"$numberLong": "1557827033449"
}
},
"keyMaterial": {
"$binary": {
"base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO",
"subType": "00"
}
},
"creationDate": {
"$date": {
"$numberLong": "1557827033449"
}
},
"keyAltNames": ["aws"]
}
\ No newline at end of file
{
"status": {
"$numberInt": "1"
},
"_id": {
"$binary": {
"base64": "LOCALAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
},
"masterKey": {
"provider": "local"
},
"updateDate": {
"$date": {
"$numberLong": "1557827033449"
}
},
"keyMaterial": {
"$binary": {
"base64": "Ce9HSz/HKKGkIt4uyy+jDuKGA+rLC2cycykMo6vc8jXxqa1UVDYHWq1r+vZKbnnSRBfB981akzRKZCFpC05CTyFqDhXv6OnMjpG97OZEREGIsHEYiJkBW0jJJvfLLgeLsEpBzsro9FztGGXASxyxFRZFhXvHxyiLOKrdWfs7X1O/iK3pEoHMx6uSNSfUOgbebLfIqW7TO++iQS5g1xovXA==",
"subType": "00"
}
},
"creationDate": {
"$date": {
"$numberLong": "1557827033449"
}
},
"keyAltNames": [ "local" ]
}
\ No newline at end of file
This diff is collapsed.
{
"status": {
"$numberInt": "1"
},
"_id": {
"$binary": {
"base64": "LOCALAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
},
"masterKey": {
"provider": "local"
},
"updateDate": {
"$date": {
"$numberLong": "1557827033449"
}
},
"keyMaterial": {
"$binary": {
"base64": "Ce9HSz/HKKGkIt4uyy+jDuKGA+rLC2cycykMo6vc8jXxqa1UVDYHWq1r+vZKbnnSRBfB981akzRKZCFpC05CTyFqDhXv6OnMjpG97OZEREGIsHEYiJkBW0jJJvfLLgeLsEpBzsro9FztGGXASxyxFRZFhXvHxyiLOKrdWfs7X1O/iK3pEoHMx6uSNSfUOgbebLfIqW7TO++iQS5g1xovXA==",
"subType": "00"
}
},
"creationDate": {
"$date": {
"$numberLong": "1557827033449"
}
},
"keyAltNames": [ "local" ]
}
\ No newline at end of file
{
"properties": {
"encrypted": {
"encrypt": {
"keyId": [
{
"$binary": {
"base64": "LOCALAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
}
],
"bsonType": "string",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
}
}
},
"bsonType": "object"
}
{
"00": "a",
"01": "a",
"02": "a",
"03": "a",
"04": "a",
"05": "a",
"06": "a",
"07": "a",
"08": "a",
"09": "a",
"10": "a",
"11": "a",
"12": "a",
"13": "a",
"14": "a",
"15": "a",
"16": "a",
"17": "a",
"18": "a",
"19": "a",
"20": "a",
"21": "a",
"22": "a",
"23": "a",
"24": "a",
"25": "a",
"26": "a",
"27": "a",
"28": "a",
"29": "a",
"30": "a",
"31": "a",
"32": "a",
"33": "a",
"34": "a",
"35": "a",
"36": "a",
"37": "a",
"38": "a",
"39": "a",
"40": "a",
"41": "a",
"42": "a",
"43": "a",
"44": "a",
"45": "a",
"46": "a",
"47": "a",
"48": "a",
"49": "a",
"50": "a",
"51": "a",
"52": "a",
"53": "a",
"54": "a",
"55": "a",
"56": "a",
"57": "a",
"58": "a",
"59": "a",
"60": "a",
"61": "a",
"62": "a",
"63": "a",
"64": "a",
"65": "a",
"66": "a",
"67": "a",
"68": "a",
"69": "a",
"70": "a",
"71": "a",
"72": "a",
"73": "a",
"74": "a",
"75": "a",
"76": "a",
"77": "a",
"78": "a",
"79": "a",
"80": "a",
"81": "a",
"82": "a",
"83": "a",
"84": "a",
"85": "a",
"86": "a",
"87": "a",
"88": "a",
"89": "a",
"90": "a",
"91": "a",
"92": "a",
"93": "a",
"94": "a",
"95": "a",
"96": "a",
"97": "a",
"98": "a",
"99": "a"
}
\ No newline at end of file
{
"status": {
"$numberInt": "1"
},
"_id": {
"$binary": {
"base64": "LOCALAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
},
"masterKey": {
"provider": "local"
},
"updateDate": {
"$date": {
"$numberLong": "1557827033449"
}
},
"keyMaterial": {
"$binary": {
"base64": "Ce9HSz/HKKGkIt4uyy+jDuKGA+rLC2cycykMo6vc8jXxqa1UVDYHWq1r+vZKbnnSRBfB981akzRKZCFpC05CTyFqDhXv6OnMjpG97OZEREGIsHEYiJkBW0jJJvfLLgeLsEpBzsro9FztGGXASxyxFRZFhXvHxyiLOKrdWfs7X1O/iK3pEoHMx6uSNSfUOgbebLfIqW7TO++iQS5g1xovXA==",
"subType": "00"
}
},
"creationDate": {
"$date": {
"$numberLong": "1557827033449"
}
},
"keyAltNames": [ "local" ]
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
{
"runOn": [
{
"minServerVersion": "4.1.10"
}
],
"database_name": "default",
"collection_name": "default",
"data": [],
"key_vault_data": [
{
"status": 1,
"_id": {
"$binary": {
"base64": "AAAAAAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
},
"masterKey": {
"provider": "aws",
"key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0",
"region": "us-east-1"
},
"updateDate": {
"$date": {
"$numberLong": "1552949630483"
}
},
"keyMaterial": {
"$binary": {
"base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO",
"subType": "00"
}
},
"creationDate": {
"$date": {
"$numberLong": "1552949630483"
}
},
"keyAltNames": [
"altname",
"another_altname"
]
}
],
"tests": [
{
"description": "Schema with an encrypted field in an array",
"clientOptions": {
"autoEncryptOpts": {
"schemaMap": {
"default.default": {
"properties": {
"encrypted_string": {
"encrypt": {
"keyId": [
{
"$binary": {
"base64": "AAAAAAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
}
],
"bsonType": "string",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
}
}
},
"bsonType": "array"
}
},
"kmsProviders": {
"aws": {}
}
}
},
"operations": [
{
"name": "insertOne",
"arguments": {
"document": {
"_id": 1,
"encrypted_string": "string0"
}
},
"result": {
"errorContains": "Invalid schema"
}
}
],
"outcome": {
"collection": {
"data": []
}
}
},
{
"description": "Schema without specifying parent object types",
"clientOptions": {
"autoEncryptOpts": {
"schemaMap": {
"default.default": {
"properties": {
"foo": {
"properties": {
"bar": {
"encrypt": {
"keyId": [
{
"$binary": {
"base64": "AAAAAAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
}
],
"bsonType": "string",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
}
}
}
}
}
}
},
"kmsProviders": {
"aws": {}
}
}
},
"operations": [
{
"name": "insertOne",
"arguments": {
"document": {
"_id": 1,
"encrypted_string": "string0"
}
},
"result": {
"errorContains": "Invalid schema"
}
}
],
"outcome": {
"collection": {
"data": []
}
}
},
{
"description": "Schema with siblings of encrypt document",
"clientOptions": {
"autoEncryptOpts": {
"schemaMap": {
"default.default": {
"properties": {
"encrypted_string": {
"encrypt": {
"keyId": [
{
"$binary": {
"base64": "AAAAAAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
}
],
"bsonType": "string",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
},
"bsonType": "object"
}
}
}
},
"kmsProviders": {
"aws": {}
}
}
},
"operations": [
{
"name": "insertOne",
"arguments": {
"document": {
"_id": 1,
"encrypted_string": "string0"
}
},
"result": {
"errorContains": "'encrypt' cannot be used in conjunction with 'bsonType'"
}
}
],
"outcome": {
"collection": {
"data": []
}
}
},
{
"description": "Schema with logical keywords",
"clientOptions": {
"autoEncryptOpts": {
"schemaMap": {
"default.default": {
"anyOf": [
{
"properties": {
"encrypted_string": {
"encrypt": {
"keyId": [
{
"$binary": {
"base64": "AAAAAAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
}
],
"bsonType": "string",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
}
}
}
}
]
}
},
"kmsProviders": {
"aws": {}
}
}
},
"operations": [
{
"name": "insertOne",
"arguments": {
"document": {
"_id": 1,
"encrypted_string": "string0"
}
},
"result": {
"errorContains": "Invalid schema"
}
}
],
"outcome": {
"collection": {
"data": []
}
}
}
]
}
{
"runOn": [
{
"minServerVersion": "4.1.10"
}
],
"database_name": "default",
"collection_name": "default",
"data": [],
"json_schema": {
"properties": {
"encrypted_w_altname": {
"encrypt": {
"keyId": "/altname",
"bsonType": "string",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
}
},
"encrypted_string": {
"encrypt": {
"keyId": [
{
"$binary": {
"base64": "AAAAAAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
}
],
"bsonType": "string",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
}
},
"random": {
"encrypt": {
"keyId": [
{
"$binary": {
"base64": "AAAAAAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
}
],
"bsonType": "string",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
}
},
"encrypted_string_equivalent": {
"encrypt": {
"keyId": [
{
"$binary": {
"base64": "AAAAAAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
}
],
"bsonType": "string",
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
}
}
},
"bsonType": "object"
},
"key_vault_data": [
{
"status": 1,
"_id": {
"$binary": {
"base64": "AAAAAAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
},
"masterKey": {
"provider": "aws",
"key": "arn:aws:kms:us-east-1:579766882180:key/89fcc2c4-08b0-4bd9-9f25-e30687b580d0",
"region": "us-east-1"
},
"updateDate": {
"$date": {
"$numberLong": "1552949630483"
}
},
"keyMaterial": {
"$binary": {
"base64": "AQICAHhQNmWG2CzOm1dq3kWLM+iDUZhEqnhJwH9wZVpuZ94A8gEqnsxXlR51T5EbEVezUqqKAAAAwjCBvwYJKoZIhvcNAQcGoIGxMIGuAgEAMIGoBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDHa4jo6yp0Z18KgbUgIBEIB74sKxWtV8/YHje5lv5THTl0HIbhSwM6EqRlmBiFFatmEWaeMk4tO4xBX65eq670I5TWPSLMzpp8ncGHMmvHqRajNBnmFtbYxN3E3/WjxmdbOOe+OXpnGJPcGsftc7cB2shRfA4lICPnE26+oVNXT6p0Lo20nY5XC7jyCO",
"subType": "00"
}
},
"creationDate": {
"$date": {
"$numberLong": "1552949630483"
}
},
"keyAltNames": [
"altname",
"another_altname"
]
}
],
"tests": [
{
"description": "Insert with deterministic encryption, then find it",
"clientOptions": {
"autoEncryptOpts": {
"kmsProviders": {
"aws": {}
}
}
},
"operations": [
{
"name": "insertOne",
"arguments": {
"document": {
"_id": 1,
"encrypted_string": "string0"
}
}
},
{
"name": "find",
"arguments": {
"filter": {
"_id": 1
}
},
"result": [
{
"_id": 1,
"encrypted_string": "string0"
}
]
}
],
"expectations": [
{
"command_started_event": {
"command": {
"listCollections": 1,
"filter": {
"name": "default"
}
},
"command_name": "listCollections"
}
},
{
"command_started_event": {
"command": {
"listCollections": 1,
"filter": {
"name": "datakeys"
},
"$db": "admin"
},
"command_name": "listCollections"
}
},
{
"command_started_event": {
"command": {
"find": "datakeys",
"filter": {
"$or": [
{
"_id": {
"$in": [
{
"$binary": {
"base64": "AAAAAAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
}
]
}
},
{
"keyAltNames": {
"$in": []
}
}
]
},
"$db": "admin",
"readConcern": {
"level": "majority"
}
},
"command_name": "find"
}
},
{
"command_started_event": {
"command": {
"insert": "default",
"documents": [
{
"_id": 1,
"encrypted_string": {
"$binary": {
"base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==",
"subType": "06"
}
}
}
],
"ordered": true
},
"command_name": "insert"
}
},
{
"command_started_event": {
"command": {
"find": "default",
"filter": {
"_id": 1
}
},
"command_name": "find"
}
}
],
"outcome": {
"collection": {
"data": [
{
"_id": 1,
"encrypted_string": {
"$binary": {
"base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==",
"subType": "06"
}
}
}
]
}
}
},
{
"description": "Insert with randomized encryption, then find it",
"clientOptions": {
"autoEncryptOpts": {
"kmsProviders": {
"aws": {}
}
}
},
"operations": [
{
"name": "insertOne",
"arguments": {
"document": {
"_id": 1,
"random": "123"
}
}
},
{
"name": "find",
"arguments": {
"filter": {
"_id": 1
}
},
"result": [
{
"_id": 1,
"random": "123"
}
]
}
],
"expectations": [
{
"command_started_event": {
"command": {
"listCollections": 1,
"filter": {
"name": "default"
}
},
"command_name": "listCollections"
}
},
{
"command_started_event": {
"command": {
"listCollections": 1,
"filter": {
"name": "datakeys"
},
"$db": "admin"
},
"command_name": "listCollections"
}
},
{
"command_started_event": {
"command": {
"find": "datakeys",
"filter": {
"$or": [
{
"_id": {
"$in": [
{
"$binary": {
"base64": "AAAAAAAAAAAAAAAAAAAAAA==",
"subType": "04"
}
}
]
}
},
{
"keyAltNames": {
"$in": []
}
}
]
},
"$db": "admin",
"readConcern": {
"level": "majority"
}
},
"command_name": "find"
}
},
{
"command_started_event": {
"command": {
"insert": "default",
"documents": [
{
"_id": 1,
"random": {
"$$type": "binData"
}
}
],
"ordered": true
},
"command_name": "insert"
}
},
{
"command_started_event": {
"command": {
"find": "default",
"filter": {
"_id": 1
}
},
"command_name": "find"
}
}
],
"outcome": {
"collection": {
"data": [
{
"_id": 1,
"random": {
"$$type": "binData"
}
}
]
}
}
}
]
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment