@@ -30,6 +30,57 @@ async function refresh(browser: CompassBrowser, connectionName: string) {
3030 ) ;
3131}
3232
33+ function fieldOldNewByMode ( mode : string ) {
34+ switch ( mode ) {
35+ case 'indexed' :
36+ case 'unindexed' :
37+ return [ 'phoneNumber' , '"30303030"' , '"10101010"' ] ;
38+
39+ case 'range' :
40+ return [
41+ 'date' ,
42+ 'new Date("1999-01-01T00:00:00.000Z")' ,
43+ 'new Date("2023-02-10T11:08:34.456Z")' ,
44+ ] ;
45+
46+ case 'prefixPreview' :
47+ return [ 'encryptedText' , '"prefixFoo"' , '"prefixBar"' ] ;
48+
49+ case 'suffixPreview' :
50+ return [ 'encryptedText' , '"fooSuffix"' , '"barSuffix"' ] ;
51+
52+ case 'substringPreview' :
53+ return [ 'encryptedText' , '"fooSubstringFoo"' , '"barSubstringBar"' ] ;
54+
55+ default :
56+ throw new Error ( `Unknown mode ${ mode } ` ) ;
57+ }
58+ }
59+
60+ function filterByMode (
61+ mode : string ,
62+ { _id, field, newValue } : { _id : string ; field : string ; newValue : string }
63+ ) : string {
64+ switch ( mode ) {
65+ case 'unindexed' :
66+ // Querying on encrypted fields when they are unindexed is not
67+ // supported, so we use document _id instead
68+ return `{ _id: ${ _id } }` ;
69+
70+ case 'prefixPreview' :
71+ return `{ $expr: { $encStrStartsWith: { input: '$${ field } ', prefix: 'prefix' } } }` ;
72+
73+ case 'suffixPreview' :
74+ return `{ $expr: { $encStrEndsWith: { input: '$${ field } ', suffix: 'Suffix' } } }` ;
75+
76+ case 'substringPreview' :
77+ return `{ $expr: { $encStrContains: { input: '$${ field } ', substring: 'Substring' } } }` ;
78+
79+ default :
80+ return `{ ${ field } : ${ newValue } }` ;
81+ }
82+ }
83+
3384/**
3485 * @securityTest In-Use Encryption Testing
3586 *
@@ -56,6 +107,7 @@ describe('CSFLE / QE', function () {
56107 describe ( 'server version gte 4.2.20 and not a linux platform' , function ( ) {
57108 const databaseName = 'fle-test' ;
58109 const collectionName = 'my-another-collection' ;
110+
59111 let compass : Compass ;
60112 let browser : CompassBrowser ;
61113
@@ -283,6 +335,10 @@ describe('CSFLE / QE', function () {
283335 const collectionName = 'my-another-collection' ;
284336 const collectionNameUnindexed = 'my-another-collection2' ;
285337 const collectionNameRange = 'my-range-collection' ;
338+ const collectionNamePrefixPreview = 'my-prefix-collection' ;
339+ const collectionNameSuffixPreview = 'my-suffix-collection' ;
340+ const collectionNameSubstringPreview = 'my-substring-collection' ;
341+
286342 let compass : Compass ;
287343 let browser : CompassBrowser ;
288344 let plainMongo : MongoClient ;
@@ -332,15 +388,73 @@ describe('CSFLE / QE', function () {
332388 keyId: UUID("28bbc608-524e-4717-9246-33633361788e"),
333389 bsonType: 'date',
334390 queries: [{
335- queryType: " range" ,
391+ queryType: ' range' ,
336392 contention: 4,
337393 sparsity: 1,
338394 min: new Date('1970'),
339395 max: new Date('2100')
340396 }]
341397 }
342398 ]
343- }
399+ },
400+ '${ databaseName } .${ collectionNamePrefixPreview } ': {
401+ fields: [
402+ {
403+ path: 'encryptedText',
404+ keyId: UUID("28bbc608-524e-4717-9246-33633361788e"),
405+ bsonType: 'string',
406+ queries: [
407+ {
408+ queryType: 'prefixPreview',
409+ contention: 0,
410+ strMinQueryLength: 3,
411+ strMaxQueryLength: 30,
412+ caseSensitive: true,
413+ diacriticSensitive: true,
414+ }
415+ ]
416+ }
417+ ]
418+ },
419+ '${ databaseName } .${ collectionNameSuffixPreview } ': {
420+ fields: [
421+ {
422+ path: 'encryptedText',
423+ keyId: UUID("28bbc608-524e-4717-9246-33633361788e"),
424+ bsonType: 'string',
425+ queries: [
426+ {
427+ queryType: 'suffixPreview',
428+ contention: 0,
429+ strMinQueryLength: 3,
430+ strMaxQueryLength: 30,
431+ caseSensitive: true,
432+ diacriticSensitive: true,
433+ }
434+ ]
435+ }
436+ ]
437+ },
438+ '${ databaseName } .${ collectionNameSubstringPreview } ': {
439+ fields: [
440+ {
441+ path: 'encryptedText',
442+ keyId: UUID("28bbc608-524e-4717-9246-33633361788e"),
443+ bsonType: 'string',
444+ queries: [
445+ {
446+ queryType: 'substringPreview',
447+ contention: 0,
448+ strMinQueryLength: 3,
449+ strMaxQueryLength: 10,
450+ strMaxLength: 20,
451+ caseSensitive: true,
452+ diacriticSensitive: true
453+ }
454+ ]
455+ }
456+ ]
457+ },
344458 }` ,
345459 connectionName,
346460 } ) ;
@@ -513,21 +627,28 @@ describe('CSFLE / QE', function () {
513627 [ 'indexed' , collectionName ] ,
514628 [ 'unindexed' , collectionNameUnindexed ] ,
515629 [ 'range' , collectionNameRange ] ,
630+ [ 'prefixPreview' , collectionNamePrefixPreview ] ,
631+ [ 'suffixPreview' , collectionNameSuffixPreview ] ,
632+ [ 'substringPreview' , collectionNameSubstringPreview ] ,
516633 ] as const ) {
517634 it ( `can edit and query the ${ mode } encrypted field in the CRUD view` , async function ( ) {
518635 if ( mode === 'range' && serverSatisfies ( '< 7.99.99' , true ) ) {
519636 // We are using latest crypt libraries which only support range algorithm.
520637 console . log ( 'Skipping range test for server version < 7.99.99' ) ;
521638 return this . skip ( ) ;
522639 }
523- const [ field , oldValue , newValue ] =
524- mode !== 'range'
525- ? [ 'phoneNumber' , '"30303030"' , '"10101010"' ]
526- : [
527- 'date' ,
528- 'new Date("1999-01-01T00:00:00.000Z")' ,
529- 'new Date("2023-02-10T11:08:34.456Z")' ,
530- ] ;
640+
641+ if (
642+ [ 'prefixPreview' , 'suffixPreview' , 'substringPreview' ] . includes (
643+ mode as string
644+ ) &&
645+ ! serverSatisfies ( '>= 8.2.0-rc4' , true )
646+ ) {
647+ // QE Prefix/Suffix/Substring Support only available on 8.2+
648+ return this . skip ( ) ;
649+ }
650+
651+ const [ field , oldValue , newValue ] = fieldOldNewByMode ( mode ) ;
531652 const oldValueJS = eval ( oldValue ) ;
532653 const newValueJS = eval ( newValue ) ;
533654 const toString = ( v : any ) =>
@@ -587,14 +708,12 @@ describe('CSFLE / QE', function () {
587708 }
588709 await footer . waitForDisplayed ( { reverse : true } ) ;
589710
590- await browser . runFindOperation (
591- 'Documents' ,
592- // Querying on encrypted fields when they are unindexed is not
593- // supported, so we use document _id instead
594- mode === 'unindexed'
595- ? `{ _id: ${ result . _id } }`
596- : `{ ${ field } : ${ newValue } }`
597- ) ;
711+ const filter = filterByMode ( mode , {
712+ _id : result . _id ,
713+ field,
714+ newValue,
715+ } ) ;
716+ await browser . runFindOperation ( 'Documents' , filter ) ;
598717
599718 const modifiedResult = await browser . getFirstListDocument ( ) ;
600719 expect ( modifiedResult [ field ] ) . to . be . equal ( toString ( newValueJS ) ) ;
0 commit comments