Skip to content

Commit 4f83a13

Browse files
committed
test(encryption): refactor encrpytion tests to use filter
Use the filter instead of the by-hand check to see if encryption tests can be run
1 parent c1d49d4 commit 4f83a13

File tree

4 files changed

+159
-177
lines changed

4 files changed

+159
-177
lines changed

test/functional/client_side_encryption/corpus_tests.js

Lines changed: 135 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,14 @@ chai.config.showDiff = true;
1212
chai.config.truncateThreshold = 0;
1313

1414
describe('Client Side Encryption Corpus', function() {
15-
// See if we can run these tests
16-
if (process.env.AWS_ACCESS_KEY_ID == null || process.env.AWS_SECRET_ACCESS_KEY == null) {
17-
console.log('skipping Client Side Encryption Corpus tests due to lack of AWS credentials');
18-
return;
19-
}
20-
21-
let mongodbClientEncryption;
22-
try {
23-
mongodbClientEncryption = require('mongodb-client-encryption')(require('../../index'));
24-
} catch (e) {
25-
console.log(
26-
'skipping Client Side Encryption Corpus tests due to inability to load mongodb-client-encryption'
27-
);
28-
return;
29-
}
15+
const metadata = {
16+
requires: {
17+
mongodb: '>=4.2.0',
18+
clientSideEncryption: true
19+
}
20+
};
3021

31-
const corpusDir = path.resolve(__dirname, 'spec', 'client-side-encryption', 'corpus');
22+
const corpusDir = path.resolve(__dirname, '..', 'spec', 'client-side-encryption', 'corpus');
3223
function loadCorpusData(filename) {
3324
return EJSON.parse(fs.readFileSync(path.resolve(corpusDir, filename), { strict: true }));
3425
}
@@ -39,20 +30,10 @@ describe('Client Side Encryption Corpus', function() {
3930
return JSON.parse(EJSON.stringify({ value }, { strict: true }));
4031
}
4132

42-
function getCredentials() {
43-
return {
44-
local: {
45-
key: Buffer.from(
46-
'Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk',
47-
'base64'
48-
)
49-
},
50-
aws: {
51-
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
52-
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
53-
}
54-
};
55-
}
33+
const localKey = Buffer.from(
34+
'Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk',
35+
'base64'
36+
);
5637

5738
// Filters out tests that have to do with dbPointer
5839
// TODO: fix dbpointer and get rid of this.
@@ -168,6 +149,7 @@ describe('Client Side Encryption Corpus', function() {
168149
function defineCorpusTests(corpus, corpusEncryptedExpected, useClientSideSchema) {
169150
let clientEncrypted, clientEncryption;
170151
beforeEach(function() {
152+
const mongodbClientEncryption = this.configuration.mongodbClientEncryption;
171153
return Promise.resolve()
172154
.then(() => {
173155
// 2. Using ``client``, drop and create the collection ``db.coll`` configured with the included JSON schema `corpus/corpus-schema.json <../corpus/corpus-schema.json>`_.
@@ -197,7 +179,7 @@ describe('Client Side Encryption Corpus', function() {
197179
// Configure both objects with ``keyVaultNamespace`` set to ``admin.datakeys``.
198180
const autoEncryption = {
199181
keyVaultNamespace,
200-
kmsProviders: getCredentials()
182+
kmsProviders: this.configuration.kmsProviders(null, localKey)
201183
};
202184
if (useClientSideSchema) {
203185
autoEncryption.schemaMap = {
@@ -216,7 +198,7 @@ describe('Client Side Encryption Corpus', function() {
216198
return clientEncrypted.connect().then(() => {
217199
clientEncryption = new mongodbClientEncryption.ClientEncryption(client, {
218200
keyVaultNamespace,
219-
kmsProviders: getCredentials()
201+
kmsProviders: this.configuration.kmsProviders(null, localKey)
220202
});
221203
});
222204
});
@@ -230,128 +212,132 @@ describe('Client Side Encryption Corpus', function() {
230212
}, Promise.resolve());
231213
}
232214

233-
it(`should pass corpus ${useClientSideSchema ? 'with' : 'without'} client schema`, function() {
234-
const corpusCopied = {};
235-
return Promise.resolve()
236-
.then(() => {
237-
// 5. Load `corpus/corpus.json <../corpus/corpus.json>`_ to a variable named ``corpus``. The corpus contains subdocuments with the following fields:
238-
//
239-
// - ``kms`` is either ``aws`` or ``local``
240-
// - ``type`` is a BSON type string `names coming from here <https://docs.mongodb.com/manual/reference/operator/query/type/>`_)
241-
// - ``algo`` is either ``rand`` or ``det`` for random or deterministic encryption
242-
// - ``method`` is either ``auto``, for automatic encryption or ``explicit`` for explicit encryption
243-
// - ``identifier`` is either ``id`` or ``altname`` for the key identifier
244-
// - ``allowed`` is a boolean indicating whether the encryption for the given parameters is permitted.
245-
// - ``value`` is the value to be tested.
246-
//
247-
// Create a new BSON document, named ``corpus_copied``.
248-
//
249-
// Iterate over each field of ``corpus``.
250-
// - If the field name is ``_id``, ``altname_aws`` and ``altname_local``, copy the field to ``corpus_copied``.
251-
// - If ``method`` is ``auto``, copy the field to ``corpus_copied``.
252-
// - If ``method`` is ``explicit``, use ``client_encryption`` to explicitly encrypt the value.
253-
// - Encrypt with the algorithm described by ``algo``.
254-
// - If ``identifier`` is ``id``
255-
// - If ``kms`` is ``local`` set the key_id to the UUID with base64 value ``LOCALAAAAAAAAAAAAAAAAA==``.
256-
// - If ``kms`` is ``aws`` set the key_id to the UUID with base64 value ``AWSAAAAAAAAAAAAAAAAAAA==``.
257-
// - If ``identifier`` is ``altname``
258-
// - If ``kms`` is ``local`` set the key_alt_name to "local".
259-
// - If ``kms`` is ``aws`` set the key_alt_name to "aws".
260-
// If ``allowed`` is true, copy the field and encrypted value to ``corpus_copied``.
261-
// If ``allowed`` is false. verify that an exception is thrown. Copy the unencrypted value to to ``corpus_copied``.
262-
return forEachP(Object.keys(corpus), key => {
263-
const field = corpus[key];
264-
if (copyOverValues.has(key)) {
265-
corpusCopied[key] = field;
266-
return;
267-
}
268-
if (field.method === 'auto') {
269-
corpusCopied[key] = Object.assign({}, field);
270-
return;
271-
}
272-
if (field.method === 'explicit') {
273-
const encryptOptions = {
274-
algorithm: algorithmMap.get(field.algo)
275-
};
276-
if (field.identifier === 'id') {
277-
encryptOptions.keyId = identifierMap.get(field.kms);
278-
} else if (field.identifier === 'altname') {
279-
encryptOptions.keyAltName = keyAltNameMap.get(field.kms);
280-
} else {
281-
throw new Error('wtf how did u get here?');
215+
it(
216+
`should pass corpus ${useClientSideSchema ? 'with' : 'without'} client schema`,
217+
metadata,
218+
function() {
219+
const corpusCopied = {};
220+
return Promise.resolve()
221+
.then(() => {
222+
// 5. Load `corpus/corpus.json <../corpus/corpus.json>`_ to a variable named ``corpus``. The corpus contains subdocuments with the following fields:
223+
//
224+
// - ``kms`` is either ``aws`` or ``local``
225+
// - ``type`` is a BSON type string `names coming from here <https://docs.mongodb.com/manual/reference/operator/query/type/>`_)
226+
// - ``algo`` is either ``rand`` or ``det`` for random or deterministic encryption
227+
// - ``method`` is either ``auto``, for automatic encryption or ``explicit`` for explicit encryption
228+
// - ``identifier`` is either ``id`` or ``altname`` for the key identifier
229+
// - ``allowed`` is a boolean indicating whether the encryption for the given parameters is permitted.
230+
// - ``value`` is the value to be tested.
231+
//
232+
// Create a new BSON document, named ``corpus_copied``.
233+
//
234+
// Iterate over each field of ``corpus``.
235+
// - If the field name is ``_id``, ``altname_aws`` and ``altname_local``, copy the field to ``corpus_copied``.
236+
// - If ``method`` is ``auto``, copy the field to ``corpus_copied``.
237+
// - If ``method`` is ``explicit``, use ``client_encryption`` to explicitly encrypt the value.
238+
// - Encrypt with the algorithm described by ``algo``.
239+
// - If ``identifier`` is ``id``
240+
// - If ``kms`` is ``local`` set the key_id to the UUID with base64 value ``LOCALAAAAAAAAAAAAAAAAA==``.
241+
// - If ``kms`` is ``aws`` set the key_id to the UUID with base64 value ``AWSAAAAAAAAAAAAAAAAAAA==``.
242+
// - If ``identifier`` is ``altname``
243+
// - If ``kms`` is ``local`` set the key_alt_name to "local".
244+
// - If ``kms`` is ``aws`` set the key_alt_name to "aws".
245+
// If ``allowed`` is true, copy the field and encrypted value to ``corpus_copied``.
246+
// If ``allowed`` is false. verify that an exception is thrown. Copy the unencrypted value to to ``corpus_copied``.
247+
return forEachP(Object.keys(corpus), key => {
248+
const field = corpus[key];
249+
if (copyOverValues.has(key)) {
250+
corpusCopied[key] = field;
251+
return;
282252
}
283-
284-
return Promise.resolve()
285-
.then(() => clientEncryption.encrypt(field.value, encryptOptions))
286-
.then(
287-
encryptedValue => {
288-
if (field.allowed === true) {
289-
corpusCopied[key] = Object.assign({}, field, { value: encryptedValue });
290-
} else {
291-
throw new Error(
292-
`Expected encryption to fail for case ${key} on value ${field.value}`
293-
);
294-
}
295-
},
296-
e => {
297-
if (field.allowed === false) {
298-
corpusCopied[key] = Object.assign({}, field);
299-
} else {
300-
throw e;
253+
if (field.method === 'auto') {
254+
corpusCopied[key] = Object.assign({}, field);
255+
return;
256+
}
257+
if (field.method === 'explicit') {
258+
const encryptOptions = {
259+
algorithm: algorithmMap.get(field.algo)
260+
};
261+
if (field.identifier === 'id') {
262+
encryptOptions.keyId = identifierMap.get(field.kms);
263+
} else if (field.identifier === 'altname') {
264+
encryptOptions.keyAltName = keyAltNameMap.get(field.kms);
265+
} else {
266+
throw new Error('wtf how did u get here?');
267+
}
268+
269+
return Promise.resolve()
270+
.then(() => clientEncryption.encrypt(field.value, encryptOptions))
271+
.then(
272+
encryptedValue => {
273+
if (field.allowed === true) {
274+
corpusCopied[key] = Object.assign({}, field, { value: encryptedValue });
275+
} else {
276+
throw new Error(
277+
`Expected encryption to fail for case ${key} on value ${field.value}`
278+
);
279+
}
280+
},
281+
e => {
282+
if (field.allowed === false) {
283+
corpusCopied[key] = Object.assign({}, field);
284+
} else {
285+
throw e;
286+
}
301287
}
302-
}
303-
);
304-
}
288+
);
289+
}
305290

306-
throw new Error('how did u get here?');
307-
});
308-
})
309-
.then(() => {
310-
// 6. Using ``client_encrypted``, insert ``corpus_copied`` into ``db.coll``.
311-
return clientEncrypted
312-
.db(dataDbName)
313-
.collection(dataCollName)
314-
.insertOne(corpusCopied);
315-
})
316-
.then(() => {
317-
// 7. Using ``client_encrypted``, find the inserted document from ``db.coll`` to a variable named ``corpus_decrypted``.
318-
// Since it should have been automatically decrypted, assert the document exactly matches ``corpus``.
319-
return clientEncrypted
320-
.db(dataDbName)
321-
.collection(dataCollName)
322-
.findOne({ _id: corpusCopied._id }, { promoteLongs: false, promoteValues: false });
323-
})
324-
.then(corpusDecrypted => {
325-
expect(toComparableExtendedJSON(corpusDecrypted)).to.deep.equal(
326-
toComparableExtendedJSON(corpus)
327-
);
328-
})
329-
.then(() => {
330-
// 8. Load `corpus/corpus_encrypted.json <../corpus/corpus-encrypted.json>`_ to a variable named ``corpus_encrypted_expected``.
331-
// Using ``client`` find the inserted document from ``db.coll`` to a variable named ``corpus_encrypted_actual``.
332-
333-
// Iterate over each field of ``corpus_encrypted_expected`` and check the following:
334-
335-
// - If the ``algo`` is ``det``, that the value equals the value of the corresponding field in ``corpus_encrypted_actual``.
336-
// - If the ``algo`` is ``rand`` and ``allowed`` is true, that the value does not equal the value of the corresponding field in ``corpus_encrypted_actual``.
337-
// - If ``allowed`` is true, decrypt the value with ``client_encryption``. Decrypt the value of the corresponding field of ``corpus_encrypted`` and validate that they are both equal.
338-
// - If ``allowed`` is false, validate the value exactly equals the value of the corresponding field of ``corpus`` (neither was encrypted).
339-
return client
340-
.db(dataDbName)
341-
.collection(dataCollName)
342-
.findOne({ _id: corpusCopied._id }, { promoteLongs: false, promoteValues: false });
343-
})
344-
.then(corpusEncryptedActual => {
345-
return forEachP(Object.keys(corpusEncryptedExpected), key => {
346-
return assertion(
347-
clientEncryption,
348-
key,
349-
corpusEncryptedExpected[key],
350-
corpusEncryptedActual[key]
291+
throw new Error('how did u get here?');
292+
});
293+
})
294+
.then(() => {
295+
// 6. Using ``client_encrypted``, insert ``corpus_copied`` into ``db.coll``.
296+
return clientEncrypted
297+
.db(dataDbName)
298+
.collection(dataCollName)
299+
.insertOne(corpusCopied);
300+
})
301+
.then(() => {
302+
// 7. Using ``client_encrypted``, find the inserted document from ``db.coll`` to a variable named ``corpus_decrypted``.
303+
// Since it should have been automatically decrypted, assert the document exactly matches ``corpus``.
304+
return clientEncrypted
305+
.db(dataDbName)
306+
.collection(dataCollName)
307+
.findOne({ _id: corpusCopied._id }, { promoteLongs: false, promoteValues: false });
308+
})
309+
.then(corpusDecrypted => {
310+
expect(toComparableExtendedJSON(corpusDecrypted)).to.deep.equal(
311+
toComparableExtendedJSON(corpus)
351312
);
313+
})
314+
.then(() => {
315+
// 8. Load `corpus/corpus_encrypted.json <../corpus/corpus-encrypted.json>`_ to a variable named ``corpus_encrypted_expected``.
316+
// Using ``client`` find the inserted document from ``db.coll`` to a variable named ``corpus_encrypted_actual``.
317+
318+
// Iterate over each field of ``corpus_encrypted_expected`` and check the following:
319+
320+
// - If the ``algo`` is ``det``, that the value equals the value of the corresponding field in ``corpus_encrypted_actual``.
321+
// - If the ``algo`` is ``rand`` and ``allowed`` is true, that the value does not equal the value of the corresponding field in ``corpus_encrypted_actual``.
322+
// - If ``allowed`` is true, decrypt the value with ``client_encryption``. Decrypt the value of the corresponding field of ``corpus_encrypted`` and validate that they are both equal.
323+
// - If ``allowed`` is false, validate the value exactly equals the value of the corresponding field of ``corpus`` (neither was encrypted).
324+
return client
325+
.db(dataDbName)
326+
.collection(dataCollName)
327+
.findOne({ _id: corpusCopied._id }, { promoteLongs: false, promoteValues: false });
328+
})
329+
.then(corpusEncryptedActual => {
330+
return forEachP(Object.keys(corpusEncryptedExpected), key => {
331+
return assertion(
332+
clientEncryption,
333+
key,
334+
corpusEncryptedExpected[key],
335+
corpusEncryptedActual[key]
336+
);
337+
});
352338
});
353-
});
354-
});
339+
}
340+
);
355341
}
356342

357343
// Note: You can uncomment the block below to run the corpus for each individial item

test/functional/client_side_encryption/driver_tests.js

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,19 @@ chai.config.truncateThreshold = 0;
1111
chai.use(require('chai-subset'));
1212

1313
describe('Client Side Encryption Functional', function() {
14-
// See if we can run these tests
15-
if (process.env.AWS_ACCESS_KEY_ID == null || process.env.AWS_SECRET_ACCESS_KEY == null) {
16-
console.log('skipping Client Side Encryption Corpus tests due to lack of AWS credentials');
17-
return;
18-
}
19-
20-
let mongodbClientEncryption;
21-
try {
22-
mongodbClientEncryption = require('mongodb-client-encryption')(require('../../../index'));
23-
} catch (e) {
24-
console.log(
25-
'skipping Client Side Encryption Functional tests due to inability to load mongodb-client-encryption'
26-
);
27-
return;
28-
}
29-
3014
const dataDbName = 'db';
3115
const dataCollName = 'coll';
3216
const keyVaultDbName = 'admin';
3317
const keyVaultCollName = 'datakeys';
3418
const keyVaultNamespace = `${keyVaultDbName}.${keyVaultCollName}`;
3519

20+
const metadata = {
21+
requires: {
22+
mongodb: '>=4.2.0',
23+
clientSideEncryption: true
24+
}
25+
};
26+
3627
describe('BSON Options', function() {
3728
beforeEach(function() {
3829
this.client = this.configuration.newClient({}, { useUnifiedTopology: true });
@@ -52,11 +43,8 @@ describe('Client Side Encryption Functional', function() {
5243
let dataDb;
5344
let keyVaultDb;
5445

55-
const kmsProviders = {
56-
local: {
57-
key: crypto.randomBytes(96)
58-
}
59-
};
46+
const mongodbClientEncryption = this.configuration.mongodbClientEncryption;
47+
const kmsProviders = this.configuration.kmsProviders('local', crypto.randomBytes(96));
6048
return this.client
6149
.connect()
6250
.then(() => {
@@ -133,7 +121,7 @@ describe('Client Side Encryption Functional', function() {
133121
testCases.forEach(bsonOptions => {
134122
const name = `should respect bson options ${JSON.stringify(bsonOptions)}`;
135123

136-
it(name, function() {
124+
it(name, metadata, function() {
137125
const data = {
138126
a: 12,
139127
b: new BSON.Int32(12),

test/functional/client_side_encryption/prose_tests.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ chai.use(require('chai-subset'));
1313
// Mng0NCt4ZHVUYUJCa1kxNkVyNUR1QURhZ2h2UzR2d2RrZzh0cFBwM3R6NmdWMDFBMUN3YkQ5aXRRMkhGRGdQV09wOGVNYUMxT2k3NjZKelhaQmRCZGJkTXVyZG9uSjFk
1414

1515
describe('Client Side Encryption Prose Tests', function() {
16-
const metadata = { requires: { clientSideEncryption: true } };
16+
const metadata = { requires: { clientSideEncryption: true, mongodb: '>=4.2.0' } };
1717
const dataDbName = 'db';
1818
const dataCollName = 'coll';
1919
const dataNamespace = `${dataDbName}.${dataCollName}`;

0 commit comments

Comments
 (0)