Skip to content

Commit 48a78c7

Browse files
authored
PHPLIB-1541: Include specs repository as a submodule (#1429)
* Add submodule for specifications * Run spec tests from submodule * Add dependabot configuration to update spec submodule * Add submodule update to contributing docs * Initialise spec submodule through composer * Add guidance for fixing spec test failures in dependabot PRs * PHPLIB-1458: Update aggregate-write-readPreference tests * Update spec test paths * Allow skipping duplicate tests in data providers * Skip all clientBulkWrite tests * PHPLIB-1450: Consolidate and improve skipping of tests * Update to latest specs commit * Use str_starts_with instead of regex logic * Add annotations to type-qualify arrays * Always require passing test group in provideTests * Consistent wrapping * PHPLIB-1492: Skip spec tests for sort in update operations * Remove obsolete imports
1 parent 85e8502 commit 48a78c7

File tree

529 files changed

+176
-235022
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

529 files changed

+176
-235022
lines changed

.github/dependabot.yml

+4
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,7 @@ updates:
44
directory: "/"
55
schedule:
66
interval: "weekly"
7+
- package-ecosystem: "gitsubmodule"
8+
directory: "/"
9+
schedule:
10+
interval: "weekly"

.github/workflows/tests.yml

+1
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ jobs:
6060
uses: "actions/checkout@v4"
6161
with:
6262
fetch-depth: 2
63+
submodules: true
6364

6465
- id: setup-mongodb
6566
uses: mongodb-labs/drivers-evergreen-tools@master

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "specifications"]
2+
path = tests/specifications
3+
url = https://github.com/mongodb/specifications

CONTRIBUTING.md

+30
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ $ composer update
1414
In addition to installing project dependencies, Composer will check that the
1515
required extension version is installed. Directions for installing the extension
1616
may be found [here](https://php.net/manual/en/mongodb.installation.php).
17+
Composer will also install the submodule required for running spec tests.
1718

1819
Installation directions for Composer may be found in its
1920
[Getting Started](https://getcomposer.org/doc/00-intro.md) guide.
@@ -100,6 +101,35 @@ The following environment variables are used for [CSFLE testing](https://github.
100101
* `KMS_TLS_CA_FILE`
101102
* `KMS_TLS_CERTIFICATE_KEY_FILE`
102103

104+
### Updating spec tests
105+
106+
Tests from the MongoDB Specifications repository are included through a
107+
submodule and updated automatically through Dependabot. To update tests
108+
manually, switch to the `tests/specifications` directory and update the
109+
repository to the appropriate commit. Remember to commit this change to the
110+
library repository.
111+
112+
#### Handling test failures on updates
113+
114+
Failures on updates can occur for multiple reasons, and the remedy to this will
115+
depend on the type of failure. Note that only tests for implemented
116+
specifications are run in the test runner.
117+
118+
* If a specification is not fully implemented (e.g. a recent change to the spec
119+
has not been applied yet), skip the test in question with a reference to the
120+
ticket that covers the change
121+
* If a test fails because it uses features not yet implemented in the unified
122+
test runner, skip the corresponding test with a reference to the ticket that
123+
covers implementing the new features
124+
* If the test failure points to a bug in the spec, consider the effort required
125+
to fix the failure. If it's a small change, commit and push the fix directly
126+
to the pull request. Otherwise, skip the test with a reference to a ticket to
127+
fix the failing test.
128+
129+
The goal is that the library passes tests with the latest spec version at all
130+
times, either by implementing small changes quickly, or by skipping tests as
131+
necessary.
132+
103133
## Code quality
104134

105135
Before submitting a pull request, please ensure that your code adheres to the

composer.json

+2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
}
4040
},
4141
"scripts": {
42+
"pre-install-cmd": "git submodule update --init",
43+
"pre-update-cmd": "git submodule update --init",
4244
"bench": "cd benchmark && composer update && vendor/bin/phpbench run --report=aggregate",
4345
"checks": [
4446
"@check:cs",

tests/SpecTests/ClientSideEncryption/Prose22_RangeExplicitEncryptionTest.php

+4-2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ class Prose22_RangeExplicitEncryptionTest extends FunctionalTestCase
3838
private ?Client $encryptedClient = null;
3939
private $key1Id;
4040

41+
private static string $specDir = __DIR__ . '/../../specifications/source/client-side-encryption';
42+
4143
public function setUp(): void
4244
{
4345
parent::setUp();
@@ -50,7 +52,7 @@ public function setUp(): void
5052

5153
$client = static::createTestClient();
5254

53-
$key1Document = $this->decodeJson(file_get_contents(__DIR__ . '/../client-side-encryption/etc/data/keys/key1-document.json'));
55+
$key1Document = $this->decodeJson(file_get_contents(self::$specDir . '/etc/data/keys/key1-document.json'));
5456
$this->key1Id = $key1Document->_id;
5557

5658
// Drop the key vault collection and insert key1Document with a majority write concern
@@ -85,7 +87,7 @@ public function setUpWithTypeAndRangeOpts(string $type, array $rangeOpts): void
8587
* for 64-bit integers. This means that DropEncryptedCollection and
8688
* CreateEncryptedCollection will be unable to inspect the option for
8789
* metadata collection names, but that's not necessary for the test. */
88-
$encryptedFields = Document::fromJSON(file_get_contents(__DIR__ . '/../client-side-encryption/etc/data/range-encryptedFields-' . $type . '.json'));
90+
$encryptedFields = Document::fromJSON(file_get_contents(self::$specDir . '/etc/data/range-encryptedFields-' . $type . '.json'));
8991

9092
$database = $this->encryptedClient->selectDatabase($this->getDatabaseName());
9193
$database->dropCollection('explicit_encryption', ['encryptedFields' => $encryptedFields]);

tests/SpecTests/ClientSideEncryptionSpecTest.php

+20-18
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ class ClientSideEncryptionSpecTest extends FunctionalTestCase
118118
'fle2v2-Compact: Compact works' => 'Failing due to bug in libmongocrypt (LIBMONGOCRYPT-699)',
119119
];
120120

121+
private static string $specDir = __DIR__ . '/../specifications/source/client-side-encryption';
122+
121123
public function setUp(): void
122124
{
123125
parent::setUp();
@@ -222,7 +224,7 @@ public static function provideTests()
222224
{
223225
$testArgs = [];
224226

225-
foreach (glob(__DIR__ . '/client-side-encryption/tests/*.json') as $filename) {
227+
foreach (glob(self::$specDir . '/tests/legacy/*.json') as $filename) {
226228
$group = basename($filename, '.json');
227229

228230
/* Some tests need to differentiate int32 and int64 BSON types.
@@ -421,7 +423,7 @@ public function testExternalKeyVault($withExternalKeyVault): void
421423
$client->selectCollection('db', 'coll')->drop();
422424

423425
self::insertKeyVaultData($client, [
424-
$this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/external/external-key.json')),
426+
$this->decodeJson(file_get_contents(self::$specDir . '/external/external-key.json')),
425427
]);
426428

427429
$encryptionOpts = [
@@ -437,7 +439,7 @@ public function testExternalKeyVault($withExternalKeyVault): void
437439

438440
$autoEncryptionOpts = $encryptionOpts + [
439441
'schemaMap' => [
440-
'db.coll' => $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/external/external-schema.json')),
442+
'db.coll' => $this->decodeJson(file_get_contents(self::$specDir . '/external/external-schema.json')),
441443
],
442444
];
443445

@@ -567,10 +569,10 @@ public function testBSONSizeLimitsAndBatchSplitting(Closure $test): void
567569
$client = static::createTestClient();
568570

569571
$client->selectCollection('db', 'coll')->drop();
570-
$client->selectDatabase('db')->createCollection('coll', ['validator' => ['$jsonSchema' => $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/limits/limits-schema.json'))]]);
572+
$client->selectDatabase('db')->createCollection('coll', ['validator' => ['$jsonSchema' => $this->decodeJson(file_get_contents(self::$specDir . '/limits/limits-schema.json'))]]);
571573

572574
self::insertKeyVaultData($client, [
573-
$this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/limits/limits-key.json')),
575+
$this->decodeJson(file_get_contents(self::$specDir . '/limits/limits-key.json')),
574576
]);
575577

576578
$autoEncryptionOpts = [
@@ -585,7 +587,7 @@ public function testBSONSizeLimitsAndBatchSplitting(Closure $test): void
585587

586588
$collection = $clientEncrypted->selectCollection('db', 'coll');
587589

588-
$document = json_decode(file_get_contents(__DIR__ . '/client-side-encryption/limits/limits-doc.json'), true, 512, JSON_THROW_ON_ERROR);
590+
$document = json_decode(file_get_contents(self::$specDir . '/limits/limits-doc.json'), true, 512, JSON_THROW_ON_ERROR);
589591

590592
$test($this, $collection, $document);
591593
}
@@ -634,18 +636,18 @@ public function testCorpus($schemaMap = true): void
634636
$client = static::createTestClient();
635637
$client->selectDatabase('db')->dropCollection('coll');
636638

637-
$schema = $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus-schema.json'));
639+
$schema = $this->decodeJson(file_get_contents(self::$specDir . '/corpus/corpus-schema.json'));
638640

639641
if (! $schemaMap) {
640642
$client->selectDatabase('db')->createCollection('coll', ['validator' => ['$jsonSchema' => $schema]]);
641643
}
642644

643645
self::insertKeyVaultData($client, [
644-
$this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus-key-local.json')),
645-
$this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus-key-aws.json')),
646-
$this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus-key-azure.json')),
647-
$this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus-key-gcp.json')),
648-
$this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus-key-kmip.json')),
646+
$this->decodeJson(file_get_contents(self::$specDir . '/corpus/corpus-key-local.json')),
647+
$this->decodeJson(file_get_contents(self::$specDir . '/corpus/corpus-key-aws.json')),
648+
$this->decodeJson(file_get_contents(self::$specDir . '/corpus/corpus-key-azure.json')),
649+
$this->decodeJson(file_get_contents(self::$specDir . '/corpus/corpus-key-gcp.json')),
650+
$this->decodeJson(file_get_contents(self::$specDir . '/corpus/corpus-key-kmip.json')),
649651
]);
650652

651653
$encryptionOpts = [
@@ -670,7 +672,7 @@ public function testCorpus($schemaMap = true): void
670672
];
671673
}
672674

673-
$corpus = (array) $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus.json'));
675+
$corpus = (array) $this->decodeJson(file_get_contents(self::$specDir . '/corpus/corpus.json'));
674676
$corpusCopied = [];
675677

676678
$clientEncrypted = static::createTestClient(null, [], ['autoEncryption' => $autoEncryptionOpts]);
@@ -701,7 +703,7 @@ public function testCorpus($schemaMap = true): void
701703

702704
$this->assertDocumentsMatch($corpus, $corpusDecrypted);
703705

704-
$corpusEncryptedExpected = (array) $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/corpus/corpus-encrypted.json'));
706+
$corpusEncryptedExpected = (array) $this->decodeJson(file_get_contents(self::$specDir . '/corpus/corpus-encrypted.json'));
705707
$corpusEncryptedActual = $client->selectCollection('db', 'coll')->findOne(['_id' => 'client_side_encryption_corpus'], ['typeMap' => ['root' => 'array', 'document' => stdClass::class, 'array' => 'array']]);
706708

707709
foreach ($corpusEncryptedExpected as $fieldName => $expectedData) {
@@ -913,7 +915,7 @@ public function testBypassSpawningMongocryptdViaLoadingSharedLibrary(): void
913915
'local' => ['key' => new Binary(base64_decode(self::LOCAL_MASTERKEY))],
914916
],
915917
'schemaMap' => [
916-
'db.coll' => $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/external/external-schema.json')),
918+
'db.coll' => $this->decodeJson(file_get_contents(self::$specDir . '/external/external-schema.json')),
917919
],
918920
'extraOptions' => [
919921
'mongocryptdBypassSpawn' => true,
@@ -955,7 +957,7 @@ public function testBypassSpawningMongocryptdViaBypassSpawn(): void
955957
'local' => ['key' => new Binary(base64_decode(self::LOCAL_MASTERKEY))],
956958
],
957959
'schemaMap' => [
958-
'db.coll' => $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/external/external-schema.json')),
960+
'db.coll' => $this->decodeJson(file_get_contents(self::$specDir . '/external/external-schema.json')),
959961
],
960962
'extraOptions' => [
961963
'mongocryptdBypassSpawn' => true,
@@ -1335,8 +1337,8 @@ public function testExplicitEncryption(Closure $test): void
13351337
$this->skipIfServerVersion('<', '7.0.0', 'Explicit encryption tests require MongoDB 7.0 or later');
13361338

13371339
// Test setup
1338-
$encryptedFields = $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/etc/data/encryptedFields.json'));
1339-
$key1Document = $this->decodeJson(file_get_contents(__DIR__ . '/client-side-encryption/etc/data/keys/key1-document.json'));
1340+
$encryptedFields = $this->decodeJson(file_get_contents(self::$specDir . '/etc/data/encryptedFields.json'));
1341+
$key1Document = $this->decodeJson(file_get_contents(self::$specDir . '/etc/data/keys/key1-document.json'));
13401342
$key1Id = $key1Document->_id;
13411343

13421344
$client = static::createTestClient();

0 commit comments

Comments
 (0)