Skip to content

Commit eeceb63

Browse files
authored
JAVA-5767 Support $lookup in CSFLE and QE (#1638)
JAVA-5767
1 parent 3b3ebc9 commit eeceb63

File tree

21 files changed

+481
-36
lines changed

21 files changed

+481
-36
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"_id": {
3+
"$binary": {
4+
"base64": "EjRWeBI0mHYSNBI0VniQEg==",
5+
"subType": "04"
6+
}
7+
},
8+
"keyMaterial": {
9+
"$binary": {
10+
"base64": "sHe0kz57YW7v8g9VP9sf/+K1ex4JqKc5rf/URX3n3p8XdZ6+15uXPaSayC6adWbNxkFskuMCOifDoTT+rkqMtFkDclOy884RuGGtUysq3X7zkAWYTKi8QAfKkajvVbZl2y23UqgVasdQu3OVBQCrH/xY00nNAs/52e958nVjBuzQkSb1T8pKJAyjZsHJ60+FtnfafDZSTAIBJYn7UWBCwQ==",
11+
"subType": "00"
12+
}
13+
},
14+
"creationDate": {
15+
"$date": {
16+
"$numberLong": "1648914851981"
17+
}
18+
},
19+
"updateDate": {
20+
"$date": {
21+
"$numberLong": "1648914851981"
22+
}
23+
},
24+
"status": {
25+
"$numberInt": "0"
26+
},
27+
"masterKey": {
28+
"provider": "local"
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"properties": {
3+
"csfle": {
4+
"encrypt": {
5+
"keyId": [
6+
{
7+
"$binary": {
8+
"base64": "EjRWeBI0mHYSNBI0VniQEg==",
9+
"subType": "04"
10+
}
11+
}
12+
],
13+
"bsonType": "string",
14+
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
15+
}
16+
}
17+
},
18+
"bsonType": "object"
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"properties": {
3+
"csfle2": {
4+
"encrypt": {
5+
"keyId": [
6+
{
7+
"$binary": {
8+
"base64": "EjRWeBI0mHYSNBI0VniQEg==",
9+
"subType": "04"
10+
}
11+
}
12+
],
13+
"bsonType": "string",
14+
"algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic"
15+
}
16+
}
17+
},
18+
"bsonType": "object"
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"escCollection": "enxcol_.qe.esc",
3+
"ecocCollection": "enxcol_.qe.ecoc",
4+
"fields": [
5+
{
6+
"keyId": {
7+
"$binary": {
8+
"base64": "EjRWeBI0mHYSNBI0VniQEg==",
9+
"subType": "04"
10+
}
11+
},
12+
"path": "qe",
13+
"bsonType": "string",
14+
"queries": {
15+
"queryType": "equality",
16+
"contention": 0
17+
}
18+
}
19+
]
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"escCollection": "enxcol_.qe2.esc",
3+
"ecocCollection": "enxcol_.qe2.ecoc",
4+
"fields": [
5+
{
6+
"keyId": {
7+
"$binary": {
8+
"base64": "EjRWeBI0mHYSNBI0VniQEg==",
9+
"subType": "04"
10+
}
11+
},
12+
"path": "qe2",
13+
"bsonType": "string",
14+
"queries": {
15+
"queryType": "equality",
16+
"contention": 0
17+
}
18+
}
19+
]
20+
}

driver-core/src/test/unit/com/mongodb/client/model/bulk/BaseClientDeleteOptionsTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
package com.mongodb.client.model.bulk;
1818

19-
import com.mongodb.MongoBaseInterfaceAssertions;
19+
import com.mongodb.testing.MongoBaseInterfaceAssertions;
2020
import org.junit.jupiter.api.Test;
2121

2222
class BaseClientDeleteOptionsTest {

driver-core/src/test/unit/com/mongodb/client/model/bulk/BaseClientUpdateOptionsTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
package com.mongodb.client.model.bulk;
1818

19-
import com.mongodb.MongoBaseInterfaceAssertions;
19+
import com.mongodb.testing.MongoBaseInterfaceAssertions;
2020
import org.junit.jupiter.api.Test;
2121

2222
class BaseClientUpdateOptionsTest {

driver-core/src/test/unit/com/mongodb/client/model/bulk/BaseClientUpsertableWriteModelOptionsTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
package com.mongodb.client.model.bulk;
1818

19-
import com.mongodb.MongoBaseInterfaceAssertions;
19+
import com.mongodb.testing.MongoBaseInterfaceAssertions;
2020
import org.junit.jupiter.api.Test;
2121

2222
final class BaseClientUpsertableWriteModelOptionsTest {

driver-core/src/test/unit/com/mongodb/client/model/bulk/BaseClientWriteModelOptionsTest.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
package com.mongodb.client.model.bulk;
1818

19-
import com.mongodb.MongoBaseInterfaceAssertions;
19+
import com.mongodb.testing.MongoBaseInterfaceAssertions;
2020
import org.junit.jupiter.api.Test;
2121

2222
final class BaseClientWriteModelOptionsTest {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.mongodb.testing;
18+
19+
import org.junit.jupiter.api.function.Executable;
20+
import org.opentest4j.AssertionFailedError;
21+
22+
import static org.junit.jupiter.api.Assertions.assertThrows;
23+
24+
public final class MongoAssertions {
25+
26+
private MongoAssertions() {
27+
//NOP
28+
}
29+
30+
public static <T extends Throwable> void assertCause(
31+
final Class<T> expectedCause, final String expectedMessageFragment, final Executable e) {
32+
Throwable cause = assertThrows(Throwable.class, e);
33+
while (cause.getCause() != null) {
34+
cause = cause.getCause();
35+
}
36+
if (!cause.getMessage().contains(expectedMessageFragment)) {
37+
throw new AssertionFailedError("Unexpected message: " + cause.getMessage(), cause);
38+
}
39+
if (!expectedCause.isInstance(cause)) {
40+
throw new AssertionFailedError("Unexpected cause: " + cause.getClass(), assertThrows(Throwable.class, e));
41+
}
42+
}
43+
}

driver-core/src/test/unit/com/mongodb/MongoBaseInterfaceAssertions.java renamed to driver-core/src/test/unit/com/mongodb/testing/MongoBaseInterfaceAssertions.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
package com.mongodb;
17+
package com.mongodb.testing;
1818

1919
import org.reflections.Reflections;
2020

driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/crypt/CollectionInfoRetriever.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import com.mongodb.lang.Nullable;
2121
import com.mongodb.reactivestreams.client.MongoClient;
2222
import org.bson.BsonDocument;
23-
import reactor.core.publisher.Mono;
23+
import reactor.core.publisher.Flux;
2424

2525
import static com.mongodb.assertions.Assertions.notNull;
2626
import static com.mongodb.reactivestreams.client.internal.TimeoutHelper.databaseWithTimeoutDeferred;
@@ -35,8 +35,8 @@ class CollectionInfoRetriever {
3535
this.client = notNull("client", client);
3636
}
3737

38-
public Mono<BsonDocument> filter(final String databaseName, final BsonDocument filter, @Nullable final Timeout operationTimeout) {
38+
public Flux<BsonDocument> filter(final String databaseName, final BsonDocument filter, @Nullable final Timeout operationTimeout) {
3939
return databaseWithTimeoutDeferred(client.getDatabase(databaseName), TIMEOUT_ERROR_MESSAGE, operationTimeout)
40-
.flatMap(database -> Mono.from(database.listCollections(BsonDocument.class).filter(filter).first()));
40+
.flatMapMany(database -> Flux.from(database.listCollections(BsonDocument.class).filter(filter)));
4141
}
4242
}

driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/crypt/Crypt.java

+2-4
Original file line numberDiff line numberDiff line change
@@ -304,10 +304,8 @@ private void collInfo(final MongoCryptContext cryptContext,
304304
} else {
305305
collectionInfoRetriever.filter(databaseName, cryptContext.getMongoOperation(), operationTimeout)
306306
.contextWrite(sink.contextView())
307-
.doOnSuccess(result -> {
308-
if (result != null) {
309-
cryptContext.addMongoOperationResult(result);
310-
}
307+
.doOnNext(result -> cryptContext.addMongoOperationResult(result))
308+
.doOnComplete(() -> {
311309
cryptContext.completeMongoOperation();
312310
executeStateMachineWithSink(cryptContext, databaseName, sink, operationTimeout);
313311
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* Copyright 2008-present MongoDB, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.mongodb.reactivestreams.client;
18+
19+
import com.mongodb.ClientEncryptionSettings;
20+
import com.mongodb.MongoClientSettings;
21+
import com.mongodb.client.MongoClient;
22+
import com.mongodb.client.vault.ClientEncryption;
23+
import com.mongodb.reactivestreams.client.syncadapter.SyncClientEncryption;
24+
import com.mongodb.reactivestreams.client.syncadapter.SyncMongoClient;
25+
import com.mongodb.reactivestreams.client.vault.ClientEncryptions;
26+
27+
public class ClientSideEncryption25LookupProseTests extends com.mongodb.client.ClientSideEncryption25LookupProseTests {
28+
29+
@Override
30+
protected MongoClient createMongoClient(final MongoClientSettings settings) {
31+
return new SyncMongoClient(MongoClients.create(settings));
32+
}
33+
34+
@Override
35+
protected ClientEncryption createClientEncryption(final ClientEncryptionSettings settings) {
36+
return new SyncClientEncryption(ClientEncryptions.create(settings));
37+
}
38+
39+
}

driver-sync/src/main/com/mongodb/client/internal/CollectionInfoRetriever.java

+8-4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
import com.mongodb.lang.Nullable;
2222
import org.bson.BsonDocument;
2323

24+
import java.util.ArrayList;
25+
import java.util.List;
26+
2427
import static com.mongodb.assertions.Assertions.notNull;
2528
import static com.mongodb.client.internal.TimeoutHelper.databaseWithTimeout;
2629

@@ -33,9 +36,10 @@ class CollectionInfoRetriever {
3336
this.client = notNull("client", client);
3437
}
3538

36-
@Nullable
37-
public BsonDocument filter(final String databaseName, final BsonDocument filter, @Nullable final Timeout operationTimeout) {
38-
return databaseWithTimeout(client.getDatabase(databaseName), TIMEOUT_ERROR_MESSAGE,
39-
operationTimeout).listCollections(BsonDocument.class).filter(filter).first();
39+
public List<BsonDocument> filter(final String databaseName, final BsonDocument filter, @Nullable final Timeout operationTimeout) {
40+
return databaseWithTimeout(client.getDatabase(databaseName), TIMEOUT_ERROR_MESSAGE, operationTimeout)
41+
.listCollections(BsonDocument.class)
42+
.filter(filter)
43+
.into(new ArrayList<>());
4044
}
4145
}

driver-sync/src/main/com/mongodb/client/internal/Crypt.java

+5-3
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import java.io.IOException;
4242
import java.io.InputStream;
4343
import java.nio.ByteBuffer;
44+
import java.util.List;
4445
import java.util.Map;
4546
import java.util.function.Supplier;
4647

@@ -308,9 +309,10 @@ private void fetchCredentials(final MongoCryptContext cryptContext) {
308309

309310
private void collInfo(final MongoCryptContext cryptContext, final String databaseName, @Nullable final Timeout operationTimeout) {
310311
try {
311-
BsonDocument collectionInfo = assertNotNull(collectionInfoRetriever).filter(databaseName, cryptContext.getMongoOperation(), operationTimeout);
312-
if (collectionInfo != null) {
313-
cryptContext.addMongoOperationResult(collectionInfo);
312+
List<BsonDocument> results = assertNotNull(collectionInfoRetriever)
313+
.filter(databaseName, cryptContext.getMongoOperation(), operationTimeout);
314+
for (BsonDocument result : results) {
315+
cryptContext.addMongoOperationResult(result);
314316
}
315317
cryptContext.completeMongoOperation();
316318
} catch (Throwable t) {

0 commit comments

Comments
 (0)