diff --git a/src/libmongoc/doc/mongoc_auto_encryption_opts_set_key_expiration.rst b/src/libmongoc/doc/mongoc_auto_encryption_opts_set_key_expiration.rst new file mode 100644 index 0000000000..a2bdfa812f --- /dev/null +++ b/src/libmongoc/doc/mongoc_auto_encryption_opts_set_key_expiration.rst @@ -0,0 +1,27 @@ +:man_page: mongoc_auto_encryption_opts_set_key_expiration + +mongoc_auto_encryption_opts_set_key_expiration() +======================================================== + +Synopsis +-------- + +.. code-block:: c + + void + mongoc_auto_encryption_opts_set_key_expiration ( + mongoc_auto_encryption_opts_t *opts, uint64_t cache_expiration_ms); + + +Parameters +---------- + +* ``opts``: The :symbol:`mongoc_auto_encryption_opts_t` +* ``cache_expiration_ms``: The data encryption key cache expiration time in milliseconds. + +.. seealso:: + + | :symbol:`mongoc_client_enable_auto_encryption()` + + | `In-Use Encryption `_ + diff --git a/src/libmongoc/doc/mongoc_auto_encryption_opts_t.rst b/src/libmongoc/doc/mongoc_auto_encryption_opts_t.rst index 8281ebf68b..99db637fbe 100644 --- a/src/libmongoc/doc/mongoc_auto_encryption_opts_t.rst +++ b/src/libmongoc/doc/mongoc_auto_encryption_opts_t.rst @@ -38,4 +38,5 @@ Synopsis mongoc_auto_encryption_opts_set_tls_opts mongoc_auto_encryption_opts_set_encrypted_fields_map mongoc_auto_encryption_opts_set_bypass_query_analysis + mongoc_auto_encryption_opts_set_key_expiration diff --git a/src/libmongoc/doc/mongoc_client_encryption_opts_set_key_expiration.rst b/src/libmongoc/doc/mongoc_client_encryption_opts_set_key_expiration.rst new file mode 100644 index 0000000000..c3e2148302 --- /dev/null +++ b/src/libmongoc/doc/mongoc_client_encryption_opts_set_key_expiration.rst @@ -0,0 +1,27 @@ +:man_page: mongoc_client_encryption_opts_set_key_expiration + +mongoc_client_encryption_opts_set_key_expiration() +======================================================== + +Synopsis +-------- + +.. code-block:: c + + void + mongoc_client_encryption_opts_set_key_expiration ( + mongoc_client_encryption_opts_t *opts, uint64_t cache_expiration_ms); + + +Parameters +---------- + +* ``opts``: The :symbol:`mongoc_client_encryption_opts_t` +* ``cache_expiration_ms``: The data encryption key cache expiration time in milliseconds. + +.. seealso:: + + | :symbol:`mongoc_client_encryption_new()` + + | `In-Use Encryption `_ + diff --git a/src/libmongoc/doc/mongoc_client_encryption_opts_t.rst b/src/libmongoc/doc/mongoc_client_encryption_opts_t.rst index 476b732eb7..88c4affd25 100644 --- a/src/libmongoc/doc/mongoc_client_encryption_opts_t.rst +++ b/src/libmongoc/doc/mongoc_client_encryption_opts_t.rst @@ -28,6 +28,7 @@ Used to set options for :symbol:`mongoc_client_encryption_new()`. mongoc_client_encryption_opts_set_kms_credential_provider_callback mongoc_client_encryption_opts_set_kms_providers mongoc_client_encryption_opts_set_tls_opts + mongoc_client_encryption_opts_set_key_expiration .. seealso:: diff --git a/src/libmongoc/src/mongoc/mongoc-client-side-encryption.c b/src/libmongoc/src/mongoc/mongoc-client-side-encryption.c index eb7ddd9413..0b13b7cd7c 100644 --- a/src/libmongoc/src/mongoc/mongoc-client-side-encryption.c +++ b/src/libmongoc/src/mongoc/mongoc-client-side-encryption.c @@ -52,6 +52,7 @@ struct _mongoc_auto_encryption_opts_t { bool bypass_query_analysis; mc_kms_credentials_callback creds_cb; bson_t *extra; + mcd_optional_u64_t cache_expiration_ms; }; static void @@ -134,6 +135,17 @@ mongoc_auto_encryption_opts_set_kms_providers (mongoc_auto_encryption_opts_t *op } } +void +mongoc_auto_encryption_opts_set_key_expiration (mongoc_auto_encryption_opts_t *opts, uint64_t expiration) +{ + if (!opts) { + return; + } + + opts->cache_expiration_ms.set = true; + opts->cache_expiration_ms.value = expiration; +} + /* _bson_copy_or_null returns a copy of @bson or NULL if @bson is NULL */ static bson_t * _bson_copy_or_null (const bson_t *bson) @@ -233,6 +245,7 @@ struct _mongoc_client_encryption_opts_t { bson_t *kms_providers; bson_t *tls_opts; mc_kms_credentials_callback creds_cb; + mcd_optional_u64_t cache_expiration_ms; }; mongoc_client_encryption_opts_t * @@ -314,6 +327,14 @@ mongoc_client_encryption_opts_set_kms_credential_provider_callback (mongoc_clien opts->creds_cb.userdata = userdata; } +void +mongoc_client_encryption_opts_set_key_expiration (mongoc_client_encryption_opts_t *opts, uint64_t cache_expiration_ms) +{ + BSON_ASSERT_PARAM (opts); + opts->cache_expiration_ms.set = true; + opts->cache_expiration_ms.value = cache_expiration_ms; +} + /*-------------------------------------------------------------------------- * Data key options. *-------------------------------------------------------------------------- @@ -1794,6 +1815,7 @@ _mongoc_cse_client_enable_auto_encryption (mongoc_client_t *client, opts->bypass_auto_encryption, opts->bypass_query_analysis, opts->creds_cb, + opts->cache_expiration_ms, error); if (!client->topology->crypt) { GOTO (fail); @@ -1933,6 +1955,7 @@ _mongoc_cse_client_pool_enable_auto_encryption (mongoc_topology_t *topology, opts->bypass_auto_encryption, opts->bypass_query_analysis, opts->creds_cb, + opts->cache_expiration_ms, error); if (!topology->crypt) { GOTO (fail); @@ -2031,6 +2054,7 @@ mongoc_client_encryption_new (mongoc_client_encryption_opts_t *opts, bson_error_ false, /* bypass_query_analysis. Not applicable. */ opts->creds_cb, + opts->cache_expiration_ms, error); if (!client_encryption->crypt) { goto fail; diff --git a/src/libmongoc/src/mongoc/mongoc-client-side-encryption.h b/src/libmongoc/src/mongoc/mongoc-client-side-encryption.h index ef22f7a05f..22e6b11f9a 100644 --- a/src/libmongoc/src/mongoc/mongoc-client-side-encryption.h +++ b/src/libmongoc/src/mongoc/mongoc-client-side-encryption.h @@ -71,6 +71,9 @@ mongoc_auto_encryption_opts_set_keyvault_namespace (mongoc_auto_encryption_opts_ MONGOC_EXPORT (void) mongoc_auto_encryption_opts_set_kms_providers (mongoc_auto_encryption_opts_t *opts, const bson_t *kms_providers); +MONGOC_EXPORT (void) +mongoc_auto_encryption_opts_set_key_expiration (mongoc_auto_encryption_opts_t *opts, uint64_t expiration); + MONGOC_EXPORT (void) mongoc_auto_encryption_opts_set_tls_opts (mongoc_auto_encryption_opts_t *opts, const bson_t *tls_opts); @@ -130,6 +133,9 @@ mongoc_client_encryption_opts_set_kms_credential_provider_callback (mongoc_clien mongoc_kms_credentials_provider_callback_fn fn, void *userdata); +MONGOC_EXPORT (void) +mongoc_client_encryption_opts_set_key_expiration (mongoc_client_encryption_opts_t *opts, uint64_t cache_expiration_ms); + MONGOC_EXPORT (mongoc_client_encryption_rewrap_many_datakey_result_t *) mongoc_client_encryption_rewrap_many_datakey_result_new (void) BSON_GNUC_WARN_UNUSED_RESULT; diff --git a/src/libmongoc/src/mongoc/mongoc-crypt-private.h b/src/libmongoc/src/mongoc/mongoc-crypt-private.h index f7647d32f1..d18e2f4b1c 100644 --- a/src/libmongoc/src/mongoc/mongoc-crypt-private.h +++ b/src/libmongoc/src/mongoc/mongoc-crypt-private.h @@ -20,6 +20,7 @@ #define MONGOC_CRYPT_PRIVATE_H #include "mongoc-config.h" +#include "mongoc-util-private.h" #include "mongoc.h" @@ -48,6 +49,7 @@ _mongoc_crypt_new (const bson_t *kms_providers, bool bypass_auto_encryption, bool bypass_query_analysis, mc_kms_credentials_callback creds_cb, + mcd_optional_u64_t cache_expiration_ms, bson_error_t *error); void diff --git a/src/libmongoc/src/mongoc/mongoc-crypt.c b/src/libmongoc/src/mongoc/mongoc-crypt.c index bc960fcfd7..024ea5a5b6 100644 --- a/src/libmongoc/src/mongoc/mongoc-crypt.c +++ b/src/libmongoc/src/mongoc/mongoc-crypt.c @@ -1380,6 +1380,7 @@ _mongoc_crypt_new (const bson_t *kms_providers, bool bypass_auto_encryption, bool bypass_query_analysis, mc_kms_credentials_callback creds_cb, + mcd_optional_u64_t cache_expiration_ms, bson_error_t *error) { _mongoc_crypt_t *crypt; @@ -1457,6 +1458,13 @@ _mongoc_crypt_new (const bson_t *kms_providers, goto fail; } + if (cache_expiration_ms.set) { + mongocrypt_setopt_key_expiration (crypt->handle, cache_expiration_ms.value); + if (!_crypt_check_error (crypt->handle, error, false)) { + goto fail; + } + } + if (!mongocrypt_init (crypt->handle)) { _crypt_check_error (crypt->handle, error, true); goto fail; diff --git a/src/libmongoc/src/mongoc/mongoc-util-private.h b/src/libmongoc/src/mongoc/mongoc-util-private.h index 95b751de53..8ef99f6191 100644 --- a/src/libmongoc/src/mongoc/mongoc-util-private.h +++ b/src/libmongoc/src/mongoc/mongoc-util-private.h @@ -245,6 +245,11 @@ hex_to_bin (const char *hex, uint32_t *len); char * bin_to_hex (const uint8_t *bin, uint32_t len); +typedef struct { + bool set; + uint64_t value; +} mcd_optional_u64_t; + BSON_END_DECLS #endif /* MONGOC_UTIL_PRIVATE_H */ diff --git a/src/libmongoc/tests/json-test-monitoring.c b/src/libmongoc/tests/json-test-monitoring.c index ddfcfb72c6..1389e4e61b 100644 --- a/src/libmongoc/tests/json-test-monitoring.c +++ b/src/libmongoc/tests/json-test-monitoring.c @@ -590,13 +590,16 @@ check_json_apm_events (json_test_ctx_t *ctx, const bson_t *expectations) /* If we do not allow matching against a subset of actual events, check if * there are extra "actual" events */ - if (!allow_subset && bson_iter_next (&actual_iter)) { + if (!allow_subset) { bson_t extra; - - bson_iter_bson (&actual_iter, &extra); - _apm_match_error_context (&ctx->events, expectations); - test_error ("extra actual event was not found in expectations: %s\n", - bson_as_canonical_extended_json (&extra, NULL)); + while (bson_iter_next (&actual_iter)) { + bson_iter_bson (&actual_iter, &extra); + if (!skip_cse_list_collections (&extra)) { + _apm_match_error_context (&ctx->events, expectations); + test_error ("extra actual event was not found in expectations: %s\n", + bson_as_canonical_extended_json (&extra, NULL)); + } + } } for (i = 0; i < 2; i++) { diff --git a/src/libmongoc/tests/json-test.c b/src/libmongoc/tests/json-test.c index ce06bf3a41..efc769ec47 100644 --- a/src/libmongoc/tests/json-test.c +++ b/src/libmongoc/tests/json-test.c @@ -1599,6 +1599,13 @@ set_auto_encryption_opts (mongoc_client_t *client, bson_t *test) bson_free (env_cryptSharedLibPath); } + if (bson_iter_init_find (&iter, &opts, "keyExpirationMS")) { + BSON_ASSERT (BSON_ITER_HOLDS_INT (&iter)); + const int expiration = bson_iter_as_int64 (&iter); + BSON_ASSERT (expiration > 0); + mongoc_auto_encryption_opts_set_key_expiration (auto_encryption_opts, (uint64_t) expiration); + } + mongoc_auto_encryption_opts_set_extra (auto_encryption_opts, &extra); bson_destroy (&extra); diff --git a/src/libmongoc/tests/json/client_side_encryption/legacy/keyCache.json b/src/libmongoc/tests/json/client_side_encryption/legacy/keyCache.json new file mode 100644 index 0000000000..49a6ca32bd --- /dev/null +++ b/src/libmongoc/tests/json/client_side_encryption/legacy/keyCache.json @@ -0,0 +1,270 @@ +{ + "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": {} + }, + "keyExpirationMS": 1 + } + }, + "operations": [ + { + "name": "insertOne", + "arguments": { + "document": { + "_id": 1, + "encrypted_string": "string0" + } + } + }, + { + "name": "wait", + "object": "testRunner", + "arguments": { + "ms": 2 + } + }, + { + "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": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "keyvault", + "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" + } + }, + { + "command_started_event": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "AAAAAAAAAAAAAAAAAAAAAA==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "keyvault", + "readConcern": { + "level": "majority" + } + }, + "command_name": "find" + } + } + ], + "outcome": { + "collection": { + "data": [ + { + "_id": 1, + "encrypted_string": { + "$binary": { + "base64": "AQAAAAAAAAAAAAAAAAAAAAACwj+3zkv2VM+aTfk60RqhXq6a/77WlLwu/BxXFkL7EppGsju/m8f0x5kBDD3EZTtGALGXlym5jnpZAoSIkswHoA==", + "subType": "06" + } + } + } + ] + } + } + } + ] +} diff --git a/src/libmongoc/tests/json/client_side_encryption/unified/keyCache.json b/src/libmongoc/tests/json/client_side_encryption/unified/keyCache.json new file mode 100644 index 0000000000..36d5957a83 --- /dev/null +++ b/src/libmongoc/tests/json/client_side_encryption/unified/keyCache.json @@ -0,0 +1,198 @@ +{ + "description": "keyCache-explicit", + "schemaVersion": "1.22", + "runOnRequirements": [ + { + "csfle": true + } + ], + "createEntities": [ + { + "client": { + "id": "client0", + "observeEvents": [ + "commandStartedEvent" + ] + } + }, + { + "clientEncryption": { + "id": "clientEncryption0", + "clientEncryptionOpts": { + "keyVaultClient": "client0", + "keyVaultNamespace": "keyvault.datakeys", + "kmsProviders": { + "local": { + "key": "OCTP9uKPPmvuqpHlqq83gPk4U6rUPxKVRRyVtrjFmVjdoa4Xzm1SzUbr7aIhNI42czkUBmrCtZKF31eaaJnxEBkqf0RFukA9Mo3NEHQWgAQ2cn9duOcRbaFUQo2z0/rB" + } + }, + "keyExpirationMS": 1 + } + } + }, + { + "database": { + "id": "database0", + "client": "client0", + "databaseName": "keyvault" + } + }, + { + "collection": { + "id": "collection0", + "database": "database0", + "collectionName": "datakeys" + } + } + ], + "initialData": [ + { + "databaseName": "keyvault", + "collectionName": "datakeys", + "documents": [ + { + "_id": { + "$binary": { + "base64": "a+YWzdygTAG62/cNUkqZiQ==", + "subType": "04" + } + }, + "keyAltNames": [], + "keyMaterial": { + "$binary": { + "base64": "iocBkhO3YBokiJ+FtxDTS71/qKXQ7tSWhWbcnFTXBcMjarsepvALeJ5li+SdUd9ePuatjidxAdMo7vh1V2ZESLMkQWdpPJ9PaJjA67gKQKbbbB4Ik5F2uKjULvrMBnFNVRMup4JNUwWFQJpqbfMveXnUVcD06+pUpAkml/f+DSXrV3e5rxciiNVtz03dAG8wJrsKsFXWj6vTjFhsfknyBA==", + "subType": "00" + } + }, + "creationDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "updateDate": { + "$date": { + "$numberLong": "1552949630483" + } + }, + "status": { + "$numberInt": "0" + }, + "masterKey": { + "provider": "local" + } + } + ] + } + ], + "tests": [ + { + "description": "decrypt, wait, and decrypt again", + "operations": [ + { + "name": "decrypt", + "object": "clientEncryption0", + "arguments": { + "value": { + "$binary": { + "base64": "AWvmFs3coEwButv3DVJKmYkCJ6lUzRX9R28WNlw5uyndb+8gurA+p8q14s7GZ04K2ZvghieRlAr5UwZbow3PMq27u5EIhDDczwBFcbdP1amllw==", + "subType": "06" + } + } + }, + "expectResult": "foobar" + }, + { + "name": "wait", + "object": "testRunner", + "arguments": { + "ms": 2 + } + }, + { + "name": "decrypt", + "object": "clientEncryption0", + "arguments": { + "value": { + "$binary": { + "base64": "AWvmFs3coEwButv3DVJKmYkCJ6lUzRX9R28WNlw5uyndb+8gurA+p8q14s7GZ04K2ZvghieRlAr5UwZbow3PMq27u5EIhDDczwBFcbdP1amllw==", + "subType": "06" + } + } + }, + "expectResult": "foobar" + } + ], + "expectEvents": [ + { + "client": "client0", + "events": [ + { + "commandStartedEvent": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "a+YWzdygTAG62/cNUkqZiQ==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "keyvault", + "readConcern": { + "level": "majority" + } + } + } + }, + { + "commandStartedEvent": { + "command": { + "find": "datakeys", + "filter": { + "$or": [ + { + "_id": { + "$in": [ + { + "$binary": { + "base64": "a+YWzdygTAG62/cNUkqZiQ==", + "subType": "04" + } + } + ] + } + }, + { + "keyAltNames": { + "$in": [] + } + } + ] + }, + "$db": "keyvault", + "readConcern": { + "level": "majority" + } + } + } + } + ] + } + ] + } + ] +} diff --git a/src/libmongoc/tests/unified/entity-map.c b/src/libmongoc/tests/unified/entity-map.c index 446ae1220b..edf9fb1eb6 100644 --- a/src/libmongoc/tests/unified/entity-map.c +++ b/src/libmongoc/tests/unified/entity-map.c @@ -18,6 +18,7 @@ #include "bsonutil/bson-parser.h" #include "TestSuite.h" +#include "mongoc.h" #include "test-conveniences.h" #include "test-libmongoc.h" #include "utlist.h" @@ -1193,10 +1194,12 @@ entity_client_encryption_new (entity_map_t *entity_map, bson_t *bson, bson_error char *client_id = NULL; char *kv_ns = NULL; bson_t *kms = NULL; + int64_t *key_expiration; bson_parser_utf8 (ce_opts_parser, "keyVaultClient", &client_id); bson_parser_utf8 (ce_opts_parser, "keyVaultNamespace", &kv_ns); bson_parser_doc (ce_opts_parser, "kmsProviders", &kms); + bson_parser_int_optional (ce_opts_parser, "keyExpirationMS", &key_expiration); if (!bson_parser_parse (ce_opts_parser, ce_opts_bson, error)) { goto ce_opts_done; @@ -1237,6 +1240,11 @@ entity_client_encryption_new (entity_map_t *entity_map, bson_t *bson, bson_error mongoc_client_encryption_opts_set_keyvault_namespace (ce_opts, db, coll); } + if (key_expiration) { + BSON_ASSERT (*key_expiration >= 0); + mongoc_client_encryption_opts_set_key_expiration (ce_opts, (uint64_t) *key_expiration); + } + if (!_parse_and_set_kms_providers (ce_opts, kms, error)) { goto ce_opts_done; } diff --git a/src/libmongoc/tests/unified/operation.c b/src/libmongoc/tests/unified/operation.c index 1fbcdca770..f49af6feca 100644 --- a/src/libmongoc/tests/unified/operation.c +++ b/src/libmongoc/tests/unified/operation.c @@ -3546,6 +3546,22 @@ operation_assert_number_connections_checked_out (test_t *test, operation_t *op, return true; } +static bool +operation_wait (test_t *test, operation_t *op, result_t *result, bson_error_t *error) +{ + BSON_UNUSED (test); + BSON_UNUSED (error); + + bson_iter_t iter; + bson_iter_init_find (&iter, op->arguments, "ms"); + ASSERT (BSON_ITER_HOLDS_INT (&iter)); + const int64_t sleep_msec = bson_iter_as_int64 (&iter); + _mongoc_usleep (sleep_msec * 1000); + + result_from_ok (result); + return true; +} + static bool operation_rename (test_t *test, operation_t *op, result_t *result, bson_error_t *error) { @@ -3871,6 +3887,7 @@ operation_run (test_t *test, bson_t *op_bson, bson_error_t *error) {"assertSessionUnpinned", operation_assert_session_unpinned}, {"loop", operation_loop}, {"assertNumberConnectionsCheckedOut", operation_assert_number_connections_checked_out}, + {"wait", operation_wait}, /* GridFS operations */ {"delete", operation_delete}, diff --git a/src/libmongoc/tests/unified/runner.c b/src/libmongoc/tests/unified/runner.c index 78b9c777c1..b31ba8734d 100644 --- a/src/libmongoc/tests/unified/runner.c +++ b/src/libmongoc/tests/unified/runner.c @@ -576,9 +576,11 @@ check_schema_version (test_file_t *test_file) // 1.8 is fully supported. Later minor versions are partially supported. // 1.12 is partially supported (expectedError.errorResponse assertions) // 1.18 is partially supported (additional properties in kmsProviders) + // 1.20 is partially supported (expectedError.writeErrors and expectedError.writeConcernErrors) // 1.21 is partially supported (expectedError.writeErrors and expectedError.writeConcernErrors) + // 1.22 is partially supported (keyExpirationMS in client encryption options) semver_t schema_version; - semver_parse ("1.21", &schema_version); + semver_parse ("1.22", &schema_version); if (schema_version.major != test_file->schema_version.major) { goto fail;