summaryrefslogtreecommitdiff
path: root/jstests
diff options
context:
space:
mode:
authorLucas de Castro Borges <lucas@gnuabordo.com.br>2025-02-18 17:02:53 -0300
committerLucas de Castro Borges <lucas@gnuabordo.com.br>2025-02-18 17:02:53 -0300
commit959575a5ca598bf5f37fb5cebe7ed1d80d3d71f7 (patch)
treeacc8d60aedb12b70048e676e8a7349deb0010db8 /jstests
parent76588293975fc059cf076779e4283e6ffaf8afff (diff)
New upstream version 6.0.20upstream
Diffstat (limited to 'jstests')
-rw-r--r--jstests/aggregation/accumulators/top_bottom_top_n_bottom_n.js13
-rw-r--r--jstests/aggregation/bugs/hash_lookup_spill_large_and_small_documents_correctly.js3
-rw-r--r--jstests/aggregation/bugs/server95350.js34
-rw-r--r--jstests/aggregation/documents_merge.js112
-rw-r--r--jstests/aggregation/expressions/expression_set_field_null_chars.js96
-rw-r--r--jstests/aggregation/expressions/log_pow_exp.js (renamed from jstests/aggregation/bugs/server18427.js)205
-rw-r--r--jstests/aggregation/extras/utils.js13
-rw-r--r--jstests/aggregation/group_by_objectid.js36
-rw-r--r--jstests/aggregation/ifnull.js12
-rw-r--r--jstests/aggregation/sources/documents/basics.js (renamed from jstests/aggregation/sources/documents.js)0
-rw-r--r--jstests/aggregation/sources/documents/subpipeline_validation.js215
-rw-r--r--jstests/aggregation/sources/lookup/lookup_absorb_match.js104
-rw-r--r--jstests/aggregation/sources/lookup/lookup_collation.js45
-rw-r--r--jstests/aggregation/sources/lookup/lookup_foreign_collation.js121
-rw-r--r--jstests/aggregation/sources/redact/root_redact.js28
-rw-r--r--jstests/aggregation/sources/setWindowFields/comprehensive_parse.js51
-rw-r--r--jstests/aggregation/sources/setWindowFields/time.js92
-rw-r--r--jstests/aggregation/sources/unionWith/unionWith_explain.js30
-rw-r--r--jstests/aggregation/unwind.js53
-rw-r--r--jstests/aggregation/unwind_sort.js27
-rw-r--r--jstests/audit/log_query_stats.js109
-rw-r--r--jstests/auth/authz_cache_on_system_modification.js30
-rw-r--r--jstests/auth/lsid_auth_checks.js133
-rw-r--r--jstests/auth/renameRestrictedCollections.js5
-rw-r--r--jstests/auth/rename_encrypted_collection.js4
-rw-r--r--jstests/auth/speculative-auth-replset.js5
-rw-r--r--jstests/change_streams/oplog_rewrite/change_stream_basic_match_pushdown_rewrite.js35
-rw-r--r--jstests/change_streams/report_post_batch_resume_token.js11
-rw-r--r--jstests/change_streams/reshard_collection_event.js1
-rw-r--r--jstests/change_streams/split_large_event.js36
-rw-r--r--jstests/concurrency/fsm_libs/fsm.js5
-rw-r--r--jstests/concurrency/fsm_workload_helpers/set_parameter.js33
-rw-r--r--jstests/concurrency/fsm_workloads/agg_out.js75
-rw-r--r--jstests/concurrency/fsm_workloads/collection_uuid_sharded.js6
-rw-r--r--jstests/concurrency/fsm_workloads/insert_with_data_size_aware_balancing.js131
-rw-r--r--jstests/concurrency/fsm_workloads/query_stats_concurrent.js155
-rw-r--r--jstests/concurrency/fsm_workloads/query_stats_enable_disable.js133
-rw-r--r--jstests/concurrency/fsm_workloads/random_moveChunk_refine_collection_shard_key.js12
-rw-r--r--jstests/concurrency/fsm_workloads/random_moveChunk_timeseries_insert_many.js1
-rw-r--r--jstests/core/aggregation_accepts_write_concern.js6
-rw-r--r--jstests/core/api_version_pipeline_stages.js1
-rw-r--r--jstests/core/api_version_test_expression.js1
-rw-r--r--jstests/core/arrayfind8.js1
-rw-r--r--jstests/core/bypass_doc_validation.js1
-rw-r--r--jstests/core/bypass_empty_ts_replacement.js202
-rw-r--r--jstests/core/bypass_empty_ts_replacement_timeseries.js73
-rw-r--r--jstests/core/check_shard_index.js58
-rw-r--r--jstests/core/collmod.js14
-rw-r--r--jstests/core/command_let_variables_expressions.js208
-rw-r--r--jstests/core/currentop_shell.js177
-rw-r--r--jstests/core/elemmatch_index.js6
-rw-r--r--jstests/core/empty_ts.js134
-rw-r--r--jstests/core/explain_agg_write_concern.js1
-rw-r--r--jstests/core/explain_skip.js28
-rw-r--r--jstests/core/fts_mix.js1
-rw-r--r--jstests/core/index_filter_commands.js3
-rw-r--r--jstests/core/index_stats.js1
-rw-r--r--jstests/core/json_schema/json_schema.js2
-rw-r--r--jstests/core/json_schema/misc_validation.js1
-rw-r--r--jstests/core/negated_geo_queries.js93
-rw-r--r--jstests/core/opcounters_write_cmd.js1
-rw-r--r--jstests/core/plan_cache_list_plans.js1
-rw-r--r--jstests/core/profile_agg.js1
-rw-r--r--jstests/core/query/find_all_values_at_path_expression.js33
-rw-r--r--jstests/core/query/internal_strip_invalid_assignment.js5
-rw-r--r--jstests/core/rename_collection_system_db.js7
-rw-r--r--jstests/core/timeseries/libs/timeseries.js14
-rw-r--r--jstests/core/timeseries/timeseries_collmod.js13
-rw-r--r--jstests/core/timeseries/timeseries_computed_field.js856
-rw-r--r--jstests/core/timeseries/timeseries_filter_extended_range.js427
-rw-r--r--jstests/core/timeseries/timeseries_geonear_lookup.js40
-rw-r--r--jstests/core/timeseries/timeseries_graph_lookup.js1
-rw-r--r--jstests/core/timeseries/timeseries_insert_mixed_schema_bucket.js75
-rw-r--r--jstests/core/timeseries/timeseries_lookup.js90
-rw-r--r--jstests/core/timeseries/timeseries_merge.js1
-rw-r--r--jstests/core/timeseries/timeseries_project.js167
-rw-r--r--jstests/core/timeseries/timeseries_union_with.js1
-rw-r--r--jstests/core/timeseries/timeseries_update_mixed_schema_bucket.js79
-rw-r--r--jstests/core/txns/abort_expired_transaction.js13
-rw-r--r--jstests/core/txns/aggregation_in_transaction.js2
-rw-r--r--jstests/core/txns/prepare_conflict_aggregation_behavior.js7
-rw-r--r--jstests/core/views/invalid_system_views.js1
-rw-r--r--jstests/core/views/views_aggregation.js1
-rw-r--r--jstests/core/views/views_collation.js1
-rw-r--r--jstests/core/views/views_creation.js1
-rw-r--r--jstests/core/views/views_validation.js1
-rw-r--r--jstests/core/wildcard_index_validindex.js17
-rw-r--r--jstests/disk/libs/wt_file_helper.js13
-rw-r--r--jstests/disk/repair_index_format_version.js47
-rw-r--r--jstests/hooks/run_aggregate_metrics_background.js112
-rw-r--r--jstests/libs/backup_utils.js69
-rw-r--r--jstests/libs/badSAN.pem86
-rw-r--r--jstests/libs/badSAN.pem.digest.sha12
-rw-r--r--jstests/libs/badSAN.pem.digest.sha2562
-rw-r--r--jstests/libs/ca.pem82
-rw-r--r--jstests/libs/ca.pem.digest.sha12
-rw-r--r--jstests/libs/ca.pem.digest.sha2562
-rw-r--r--jstests/libs/client-all-the-oids.pem80
-rw-r--r--jstests/libs/client-all-the-oids.pem.digest.sha12
-rw-r--r--jstests/libs/client-all-the-oids.pem.digest.sha2562
-rw-r--r--jstests/libs/client-multivalue-rdn.pem80
-rw-r--r--jstests/libs/client-multivalue-rdn.pem.digest.sha12
-rw-r--r--jstests/libs/client-multivalue-rdn.pem.digest.sha2562
-rw-r--r--jstests/libs/client-self-signed.pem86
-rw-r--r--jstests/libs/client-self-signed.pem.digest.sha12
-rw-r--r--jstests/libs/client-self-signed.pem.digest.sha2562
-rw-r--r--jstests/libs/client.pem84
-rw-r--r--jstests/libs/client.pem.digest.sha12
-rw-r--r--jstests/libs/client.pem.digest.sha2562
-rw-r--r--jstests/libs/client_email.pem82
-rw-r--r--jstests/libs/client_email.pem.digest.sha12
-rw-r--r--jstests/libs/client_email.pem.digest.sha2562
-rw-r--r--jstests/libs/client_escape.pem80
-rw-r--r--jstests/libs/client_escape.pem.digest.sha12
-rw-r--r--jstests/libs/client_escape.pem.digest.sha2562
-rw-r--r--jstests/libs/client_privatekey.pem80
-rw-r--r--jstests/libs/client_privatekey.pem.digest.sha12
-rw-r--r--jstests/libs/client_privatekey.pem.digest.sha2562
-rw-r--r--jstests/libs/client_revoked.pem82
-rw-r--r--jstests/libs/client_revoked.pem.digest.sha12
-rw-r--r--jstests/libs/client_revoked.pem.digest.sha2562
-rw-r--r--jstests/libs/client_roles.pem80
-rw-r--r--jstests/libs/client_roles.pem.digest.sha12
-rw-r--r--jstests/libs/client_roles.pem.digest.sha2562
-rw-r--r--jstests/libs/client_title.pem80
-rw-r--r--jstests/libs/client_title.pem.digest.sha12
-rw-r--r--jstests/libs/client_title.pem.digest.sha2562
-rw-r--r--jstests/libs/client_utf8.pem80
-rw-r--r--jstests/libs/client_utf8.pem.digest.sha12
-rw-r--r--jstests/libs/client_utf8.pem.digest.sha2562
-rw-r--r--jstests/libs/cluster_cert.pem82
-rw-r--r--jstests/libs/cluster_cert.pem.digest.sha12
-rw-r--r--jstests/libs/cluster_cert.pem.digest.sha2562
-rw-r--r--jstests/libs/clustered_collections/clustered_collection_bounded_scan_common.js140
-rw-r--r--jstests/libs/crl.pem14
-rw-r--r--jstests/libs/crl.pem.digest.sha12
-rw-r--r--jstests/libs/crl.pem.digest.sha2562
-rw-r--r--jstests/libs/crl_client_revoked.pem14
-rw-r--r--jstests/libs/crl_client_revoked.pem.digest.sha12
-rw-r--r--jstests/libs/crl_client_revoked.pem.digest.sha2562
-rw-r--r--jstests/libs/crl_expired.pem14
-rw-r--r--jstests/libs/crl_expired.pem.digest.sha12
-rw-r--r--jstests/libs/crl_expired.pem.digest.sha2562
-rw-r--r--jstests/libs/crl_from_intermediate_ca_B.pem12
-rw-r--r--jstests/libs/crl_from_intermediate_ca_B.pem.digest.sha11
-rw-r--r--jstests/libs/crl_from_intermediate_ca_B.pem.digest.sha2561
-rw-r--r--jstests/libs/crl_from_trusted_ca.pem12
-rw-r--r--jstests/libs/crl_from_trusted_ca.pem.digest.sha11
-rw-r--r--jstests/libs/crl_from_trusted_ca.pem.digest.sha2561
-rw-r--r--jstests/libs/crl_intermediate_ca_B_revoked.pem12
-rw-r--r--jstests/libs/crl_intermediate_ca_B_revoked.pem.digest.sha11
-rw-r--r--jstests/libs/crl_intermediate_ca_B_revoked.pem.digest.sha2561
-rw-r--r--jstests/libs/ecdsa-ca-ocsp.crt14
-rw-r--r--jstests/libs/ecdsa-ca-ocsp.key6
-rw-r--r--jstests/libs/ecdsa-ca-ocsp.pem20
-rw-r--r--jstests/libs/ecdsa-ca-ocsp.pem.digest.sha12
-rw-r--r--jstests/libs/ecdsa-ca-ocsp.pem.digest.sha2562
-rw-r--r--jstests/libs/ecdsa-ca.pem20
-rw-r--r--jstests/libs/ecdsa-ca.pem.digest.sha12
-rw-r--r--jstests/libs/ecdsa-ca.pem.digest.sha2562
-rw-r--r--jstests/libs/ecdsa-client.pem18
-rw-r--r--jstests/libs/ecdsa-client.pem.digest.sha12
-rw-r--r--jstests/libs/ecdsa-client.pem.digest.sha2562
-rw-r--r--jstests/libs/ecdsa-ocsp-responder.crt18
-rw-r--r--jstests/libs/ecdsa-ocsp-responder.crt.digest.sha12
-rw-r--r--jstests/libs/ecdsa-ocsp-responder.crt.digest.sha2562
-rw-r--r--jstests/libs/ecdsa-ocsp-responder.key6
-rw-r--r--jstests/libs/ecdsa-server-ocsp-mustStaple.pem24
-rw-r--r--jstests/libs/ecdsa-server-ocsp-mustStaple.pem.digest.sha12
-rw-r--r--jstests/libs/ecdsa-server-ocsp-mustStaple.pem.digest.sha2562
-rw-r--r--jstests/libs/ecdsa-server-ocsp.pem24
-rw-r--r--jstests/libs/ecdsa-server-ocsp.pem.digest.sha12
-rw-r--r--jstests/libs/ecdsa-server-ocsp.pem.digest.sha2562
-rw-r--r--jstests/libs/ecdsa-server.pem26
-rw-r--r--jstests/libs/ecdsa-server.pem.digest.sha12
-rw-r--r--jstests/libs/ecdsa-server.pem.digest.sha2562
-rw-r--r--jstests/libs/expired.pem84
-rw-r--r--jstests/libs/expired.pem.digest.sha12
-rw-r--r--jstests/libs/expired.pem.digest.sha2562
-rw-r--r--jstests/libs/intermediate-ca-B-leaf.pem55
-rw-r--r--jstests/libs/intermediate-ca-B-leaf.pem.digest.sha11
-rw-r--r--jstests/libs/intermediate-ca-B-leaf.pem.digest.sha2561
-rw-r--r--jstests/libs/intermediate-ca-B.pem53
-rw-r--r--jstests/libs/intermediate-ca-B.pem.digest.sha11
-rw-r--r--jstests/libs/intermediate-ca-B.pem.digest.sha2561
-rw-r--r--jstests/libs/intermediate-ca-chain.pem58
-rw-r--r--jstests/libs/intermediate-ca-chain.pem.digest.sha12
-rw-r--r--jstests/libs/intermediate-ca-chain.pem.digest.sha2562
-rw-r--r--jstests/libs/intermediate-ca.pem80
-rw-r--r--jstests/libs/intermediate-ca.pem.digest.sha12
-rw-r--r--jstests/libs/intermediate-ca.pem.digest.sha2562
-rw-r--r--jstests/libs/legacyThreadSupport.js0
-rw-r--r--jstests/libs/localhostnameCN.pem86
-rw-r--r--jstests/libs/localhostnameCN.pem.digest.sha12
-rw-r--r--jstests/libs/localhostnameCN.pem.digest.sha2562
-rw-r--r--jstests/libs/localhostnameSAN.pem86
-rw-r--r--jstests/libs/localhostnameSAN.pem.digest.sha12
-rw-r--r--jstests/libs/localhostnameSAN.pem.digest.sha2562
-rw-r--r--jstests/libs/not_yet_valid.pem82
-rw-r--r--jstests/libs/not_yet_valid.pem.digest.sha12
-rw-r--r--jstests/libs/not_yet_valid.pem.digest.sha2562
-rw-r--r--jstests/libs/ocsp/ca_ocsp.crt30
-rw-r--r--jstests/libs/ocsp/ca_ocsp.key52
-rw-r--r--jstests/libs/ocsp/ca_ocsp.pem82
-rw-r--r--jstests/libs/ocsp/ca_ocsp.pem.digest.sha12
-rw-r--r--jstests/libs/ocsp/ca_ocsp.pem.digest.sha2562
-rw-r--r--jstests/libs/ocsp/client_ocsp.pem84
-rw-r--r--jstests/libs/ocsp/client_ocsp.pem.digest.sha12
-rw-r--r--jstests/libs/ocsp/client_ocsp.pem.digest.sha2562
-rw-r--r--jstests/libs/ocsp/intermediate_ca_only_ocsp.crt30
-rw-r--r--jstests/libs/ocsp/intermediate_ca_only_ocsp.key52
-rw-r--r--jstests/libs/ocsp/intermediate_ca_only_ocsp.pem82
-rw-r--r--jstests/libs/ocsp/intermediate_ca_only_ocsp.pem.digest.sha12
-rw-r--r--jstests/libs/ocsp/intermediate_ca_only_ocsp.pem.digest.sha2562
-rw-r--r--jstests/libs/ocsp/intermediate_ca_with_root_ocsp.pem60
-rw-r--r--jstests/libs/ocsp/intermediate_ca_with_root_ocsp.pem.digest.sha12
-rw-r--r--jstests/libs/ocsp/intermediate_ca_with_root_ocsp.pem.digest.sha2562
-rw-r--r--jstests/libs/ocsp/ocsp_responder.crt28
-rw-r--r--jstests/libs/ocsp/ocsp_responder.key52
-rw-r--r--jstests/libs/ocsp/ocsp_responder.pem80
-rw-r--r--jstests/libs/ocsp/ocsp_responder.pem.digest.sha12
-rw-r--r--jstests/libs/ocsp/ocsp_responder.pem.digest.sha2562
-rw-r--r--jstests/libs/ocsp/server_and_intermediate_ca_appended_ocsp.pem114
-rw-r--r--jstests/libs/ocsp/server_and_intermediate_ca_appended_ocsp.pem.digest.sha12
-rw-r--r--jstests/libs/ocsp/server_and_intermediate_ca_appended_ocsp.pem.digest.sha2562
-rw-r--r--jstests/libs/ocsp/server_ocsp.pem82
-rw-r--r--jstests/libs/ocsp/server_ocsp.pem.digest.sha12
-rw-r--r--jstests/libs/ocsp/server_ocsp.pem.digest.sha2562
-rw-r--r--jstests/libs/ocsp/server_ocsp_invalid.pem84
-rw-r--r--jstests/libs/ocsp/server_ocsp_invalid.pem.digest.sha12
-rw-r--r--jstests/libs/ocsp/server_ocsp_invalid.pem.digest.sha2562
-rw-r--r--jstests/libs/ocsp/server_ocsp_mustStaple.pem82
-rw-r--r--jstests/libs/ocsp/server_ocsp_mustStaple.pem.digest.sha12
-rw-r--r--jstests/libs/ocsp/server_ocsp_mustStaple.pem.digest.sha2562
-rw-r--r--jstests/libs/ocsp/server_ocsp_revoked.pem82
-rw-r--r--jstests/libs/ocsp/server_ocsp_revoked.pem.digest.sha12
-rw-r--r--jstests/libs/ocsp/server_ocsp_revoked.pem.digest.sha2562
-rw-r--r--jstests/libs/ocsp/server_signed_by_intermediate_ca_ocsp.pem84
-rw-r--r--jstests/libs/ocsp/server_signed_by_intermediate_ca_ocsp.pem.digest.sha12
-rw-r--r--jstests/libs/ocsp/server_signed_by_intermediate_ca_ocsp.pem.digest.sha2562
-rw-r--r--jstests/libs/override_methods/validate_collections_on_shutdown.js1
-rw-r--r--jstests/libs/parallelTester.js242
-rw-r--r--jstests/libs/password_protected.pem92
-rw-r--r--jstests/libs/password_protected.pem.digest.sha12
-rw-r--r--jstests/libs/password_protected.pem.digest.sha2562
-rw-r--r--jstests/libs/query_stats_utils.js490
-rw-r--r--jstests/libs/rollover_ca.pem86
-rw-r--r--jstests/libs/rollover_ca.pem.digest.sha12
-rw-r--r--jstests/libs/rollover_ca.pem.digest.sha2562
-rw-r--r--jstests/libs/rollover_ca_merged.pem64
-rw-r--r--jstests/libs/rollover_ca_merged.pem.digest.sha12
-rw-r--r--jstests/libs/rollover_ca_merged.pem.digest.sha2562
-rw-r--r--jstests/libs/rollover_server.pem82
-rw-r--r--jstests/libs/rollover_server.pem.digest.sha12
-rw-r--r--jstests/libs/rollover_server.pem.digest.sha2562
-rw-r--r--jstests/libs/rs0.pem84
-rw-r--r--jstests/libs/rs0.pem.digest.sha12
-rw-r--r--jstests/libs/rs0.pem.digest.sha2562
-rw-r--r--jstests/libs/rs1.pem84
-rw-r--r--jstests/libs/rs1.pem.digest.sha12
-rw-r--r--jstests/libs/rs1.pem.digest.sha2562
-rw-r--r--jstests/libs/rs2.pem84
-rw-r--r--jstests/libs/rs2.pem.digest.sha12
-rw-r--r--jstests/libs/rs2.pem.digest.sha2562
-rw-r--r--jstests/libs/server-intermediate-ca.pem108
-rw-r--r--jstests/libs/server-intermediate-ca.pem.digest.sha12
-rw-r--r--jstests/libs/server-intermediate-ca.pem.digest.sha2562
-rw-r--r--jstests/libs/server-intermediate-leaf.pem80
-rw-r--r--jstests/libs/server-intermediate-leaf.pem.digest.sha12
-rw-r--r--jstests/libs/server-intermediate-leaf.pem.digest.sha2562
-rw-r--r--jstests/libs/server.pem88
-rw-r--r--jstests/libs/server.pem.digest.sha12
-rw-r--r--jstests/libs/server.pem.digest.sha2562
-rw-r--r--jstests/libs/server_SAN.pem82
-rw-r--r--jstests/libs/server_SAN.pem.digest.sha12
-rw-r--r--jstests/libs/server_SAN.pem.digest.sha2562
-rw-r--r--jstests/libs/server_SAN2.pem80
-rw-r--r--jstests/libs/server_SAN2.pem.digest.sha12
-rw-r--r--jstests/libs/server_SAN2.pem.digest.sha2562
-rw-r--r--jstests/libs/server_no_SAN.pem82
-rw-r--r--jstests/libs/server_no_SAN.pem.digest.sha12
-rw-r--r--jstests/libs/server_no_SAN.pem.digest.sha2562
-rw-r--r--jstests/libs/server_no_subject.pem84
-rw-r--r--jstests/libs/server_no_subject.pem.digest.sha12
-rw-r--r--jstests/libs/server_no_subject.pem.digest.sha2562
-rw-r--r--jstests/libs/server_no_subject_no_SAN.pem84
-rw-r--r--jstests/libs/server_no_subject_no_SAN.pem.digest.sha12
-rw-r--r--jstests/libs/server_no_subject_no_SAN.pem.digest.sha2562
-rw-r--r--jstests/libs/smoke.pem82
-rw-r--r--jstests/libs/smoke.pem.digest.sha12
-rw-r--r--jstests/libs/smoke.pem.digest.sha2562
-rw-r--r--jstests/libs/splithorizon-server.pem80
-rw-r--r--jstests/libs/splithorizon-server.pem.digest.sha12
-rw-r--r--jstests/libs/splithorizon-server.pem.digest.sha2562
-rw-r--r--jstests/libs/tenant_migration_donor.pem84
-rw-r--r--jstests/libs/tenant_migration_donor.pem.digest.sha12
-rw-r--r--jstests/libs/tenant_migration_donor.pem.digest.sha2562
-rw-r--r--jstests/libs/tenant_migration_donor_expired.pem84
-rw-r--r--jstests/libs/tenant_migration_donor_expired.pem.digest.sha12
-rw-r--r--jstests/libs/tenant_migration_donor_expired.pem.digest.sha2562
-rw-r--r--jstests/libs/tenant_migration_donor_insufficient_privileges.pem84
-rw-r--r--jstests/libs/tenant_migration_donor_insufficient_privileges.pem.digest.sha12
-rw-r--r--jstests/libs/tenant_migration_donor_insufficient_privileges.pem.digest.sha2562
-rw-r--r--jstests/libs/tenant_migration_recipient.pem86
-rw-r--r--jstests/libs/tenant_migration_recipient.pem.digest.sha12
-rw-r--r--jstests/libs/tenant_migration_recipient.pem.digest.sha2562
-rw-r--r--jstests/libs/tenant_migration_recipient_expired.pem86
-rw-r--r--jstests/libs/tenant_migration_recipient_expired.pem.digest.sha12
-rw-r--r--jstests/libs/tenant_migration_recipient_expired.pem.digest.sha2562
-rw-r--r--jstests/libs/tenant_migration_recipient_insufficient_privileges.pem84
-rw-r--r--jstests/libs/tenant_migration_recipient_insufficient_privileges.pem.digest.sha12
-rw-r--r--jstests/libs/tenant_migration_recipient_insufficient_privileges.pem.digest.sha2562
-rw-r--r--jstests/libs/trusted-ca.pem80
-rw-r--r--jstests/libs/trusted-ca.pem.digest.sha12
-rw-r--r--jstests/libs/trusted-ca.pem.digest.sha2562
-rw-r--r--jstests/libs/trusted-client.pem80
-rw-r--r--jstests/libs/trusted-client.pem.digest.sha12
-rw-r--r--jstests/libs/trusted-client.pem.digest.sha2562
-rw-r--r--jstests/libs/trusted-client.pfxbin3667 -> 3525 bytes
-rw-r--r--jstests/libs/trusted-server.pem80
-rw-r--r--jstests/libs/trusted-server.pem.digest.sha12
-rw-r--r--jstests/libs/trusted-server.pem.digest.sha2562
-rw-r--r--jstests/libs/trusted-server.pfxbin3667 -> 3525 bytes
-rw-r--r--jstests/multiVersion/genericBinVersion/query_stats_key_hash_version_consistency.js56
-rw-r--r--jstests/multiVersion/genericBinVersion/remove_invalid_index_options.js13
-rw-r--r--jstests/multiVersion/genericBinVersion/timeseries_collection_mixed_type.js4
-rw-r--r--jstests/multiVersion/prepare_unique_fcv_check.js48
-rw-r--r--jstests/multiVersion/targetedTestsLastLtsFeatures/change_streams_split_event_v1_v2_tokens.js31
-rw-r--r--jstests/multiVersion/targetedTestsLastLtsFeatures/fix_invalid_index_options.js12
-rw-r--r--jstests/multiVersion/targetedTestsLastLtsFeatures/invalid_index_options.js16
-rw-r--r--jstests/multiVersion/targetedTestsLastLtsFeatures/query_stats_upgrade_downgrade.js272
-rw-r--r--jstests/multiVersion/targetedTestsLastLtsFeatures/timeseries_collection_mixed_schema_index_build_stepdown.js4
-rw-r--r--jstests/multiVersion/targetedTestsLastLtsFeatures/upgrade_downgrade_timeseries_collection_from_last_lts.js4
-rw-r--r--jstests/noPassthrough/change_streams_per_shard_cursor.js6
-rw-r--r--jstests/noPassthrough/change_streams_split_event_v1_v2_tokens.js43
-rw-r--r--jstests/noPassthrough/collmod_removes_invalid_index_options.js16
-rw-r--r--jstests/noPassthrough/comment_field_passthrough.js9
-rw-r--r--jstests/noPassthrough/compound_2dsphere_max_index_keys.js6
-rw-r--r--jstests/noPassthrough/deep_merge_server_parameters.js98
-rw-r--r--jstests/noPassthrough/disable_test_parameters_when_no_set_parameters.js48
-rw-r--r--jstests/noPassthrough/dispatch_pipeline_to_all_shardservers.js90
-rw-r--r--jstests/noPassthrough/durable_history_index_usage.js8
-rw-r--r--jstests/noPassthrough/index_build_external_and_internal_abort_do_not_deadlock_single_phase.js58
-rw-r--r--jstests/noPassthrough/index_build_external_and_internal_abort_do_not_deadlock_two_phase.js92
-rw-r--r--jstests/noPassthrough/index_startup_prepareunique.js24
-rw-r--r--jstests/noPassthrough/initial_sync_same_index_spec.js98
-rw-r--r--jstests/noPassthrough/libs/index_build.js10
-rw-r--r--jstests/noPassthrough/libs/missing_index_ident.js10
-rw-r--r--jstests/noPassthrough/notablescan.js (renamed from jstests/core/notablescan.js)6
-rw-r--r--jstests/noPassthrough/oplog_application_while_recovering_must_succeed.js1
-rw-r--r--jstests/noPassthrough/or_pushdown_disable_optimization.js39
-rw-r--r--jstests/noPassthrough/profile_query_planning_time_metric.js70
-rw-r--r--jstests/noPassthrough/queryStats/agg_cmd_one_way_tokenization.js187
-rw-r--r--jstests/noPassthrough/queryStats/application_name_find.js37
-rw-r--r--jstests/noPassthrough/queryStats/clear_query_stats_store.js46
-rw-r--r--jstests/noPassthrough/queryStats/documentSourceQueryStats_redaction_parameters.js126
-rw-r--r--jstests/noPassthrough/queryStats/feature_flag_off_sampling_rate_on.js44
-rw-r--r--jstests/noPassthrough/queryStats/find_cmd_one_way_tokenization.js66
-rw-r--r--jstests/noPassthrough/queryStats/geometry_without_coordinates.js22
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_agg_cmd_collect_on_mongos.js143
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_agg_key.js64
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_agg_key_change_stream.js182
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_agg_key_change_stream_passthrough_shard.js94
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_agg_key_explain.js84
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_change_stream.js227
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_change_stream_evict.js71
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_change_stream_per_shard_cursor.js222
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_collectionType.js208
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_disable_after_initial_request.js98
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_explain_cmd_agg.js37
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_expressions.js76
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_feature_flag.js31
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_find_cmd_collect_on_mongos.js126
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_find_key.js113
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_key_hash.js98
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_logging.js99
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_metrics_across_getMore_calls.js173
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_regex.js43
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_sampling_rate.js37
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_server_status_metrics.js272
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_sub_pipelines.js184
-rw-r--r--jstests/noPassthrough/queryStats/query_stats_upgrade.js45
-rw-r--r--jstests/noPassthrough/queryStats/redact_queries_with_nonobject_fields.js76
-rw-r--r--jstests/noPassthrough/queryStats/redact_sensitive_fields_in_log.js60
-rw-r--r--jstests/noPassthrough/queryStats/redact_sensitive_fields_in_profile.js63
-rw-r--r--jstests/noPassthrough/queryStats/repl_set_query_stats_key.js108
-rw-r--r--jstests/noPassthrough/queryStats/single_batch_on_mongod_agg_cmd.js61
-rw-r--r--jstests/noPassthrough/queryStats/single_batch_on_mongod_find_cmd.js59
-rw-r--r--jstests/noPassthrough/readConcern_atClusterTime_noop_write.js126
-rw-r--r--jstests/noPassthrough/read_preference_metrics.js39
-rw-r--r--jstests/noPassthrough/read_ticket_exhaustion_with_stepdown.js239
-rw-r--r--jstests/noPassthrough/sbe_plan_cache_with_const_let_var.js57
-rw-r--r--jstests/noPassthrough/server_status_metrics_retryable_writes.js155
-rw-r--r--jstests/noPassthrough/serverstatus_index_stats.js1
-rw-r--r--jstests/noPassthrough/shell_assertions.js23
-rw-r--r--jstests/noPassthrough/standalone_replication_recovery.js3
-rw-r--r--jstests/noPassthrough/timeseries_validate_mixed_schema_bucket.js94
-rw-r--r--jstests/noPassthrough/unfinished_index_builds_restart_using_same_ident.js80
-rw-r--r--jstests/noPassthrough/unindex_detects_data_corruption.js38
-rw-r--r--jstests/noPassthrough/update_now_clustertime_replset.js6
-rw-r--r--jstests/noPassthrough/validate_detects_invalid_index_options.js28
-rw-r--r--jstests/noPassthrough/validate_doc_schema.js23
-rw-r--r--jstests/noPassthrough/validate_out_of_order.js4
-rw-r--r--jstests/noPassthroughWithMongod/command_let_variables_merge_only.js2
-rw-r--r--jstests/noPassthroughWithMongod/cursor_server_status_metrics_lifespan_histogram.js27
-rw-r--r--jstests/noPassthroughWithMongod/projection_optimizations.js3
-rw-r--r--jstests/noPassthroughWithMongod/query_stats_configuration.js35
-rw-r--r--jstests/noPassthroughWithMongod/validate_timeseries.js64
-rw-r--r--jstests/noPassthroughWithMongod/validate_timeseries_minmax.js246
-rw-r--r--jstests/noPassthroughWithMongod/validate_timeseries_version.js106
-rw-r--r--jstests/parallel/basic.js22
-rw-r--r--jstests/parallel/basicPlus.js39
-rw-r--r--jstests/replsets/backwards_compatible_timeseries_catalog_options.js72
-rw-r--r--jstests/replsets/catchup_ignores_old_heartbeats.js70
-rw-r--r--jstests/replsets/change_stream_pit_pre_image_deletion_asymmetric.js7
-rw-r--r--jstests/replsets/dbcheck_fails_on_write_concern_error.js103
-rw-r--r--jstests/replsets/dbcheck_skip_applying_batch_on_secondary_parameter.js91
-rw-r--r--jstests/replsets/dbcheck_write_concern.js82
-rw-r--r--jstests/replsets/empty_ts_repl.js159
-rw-r--r--jstests/replsets/ignore_dbcheck_in_initial_sync.js7
-rw-r--r--jstests/replsets/ignore_dbcheck_in_rollback.js104
-rw-r--r--jstests/replsets/ignore_dbcheck_in_startup_recovery.js101
-rw-r--r--jstests/replsets/libs/dbcheck_utils.js16
-rw-r--r--jstests/replsets/libs/rollback_test.js4
-rw-r--r--jstests/replsets/log_wt_stats_during_secondary_oplog_application.js46
-rw-r--r--jstests/replsets/nodes_eventually_sync_from_closer_data_center.js8
-rw-r--r--jstests/replsets/reconstruct_prepared_transactions_initial_sync.js34
-rw-r--r--jstests/replsets/tenant_migration_abort_forget_retry.js119
-rw-r--r--jstests/replsets/timeseries_mixed_schema_bucket_initial_sync.js74
-rw-r--r--jstests/sharding/agg_union_with_lookup.js76
-rw-r--r--jstests/sharding/all_collection_stats.js98
-rw-r--r--jstests/sharding/balance_random_data_distribution.js117
-rw-r--r--jstests/sharding/balancer_defragmentation_merge_chunks.js3
-rw-r--r--jstests/sharding/balancer_warns_draining_shards_blocked.js68
-rw-r--r--jstests/sharding/cancel_coordinate_txn_commit_with_tickets_exhausted.js9
-rw-r--r--jstests/sharding/change_stream_lookup_single_shard_cluster.js2
-rw-r--r--jstests/sharding/change_streams_shards_start_in_sync.js2
-rw-r--r--jstests/sharding/cluster_time_across_add_shard.js11
-rw-r--r--jstests/sharding/collection_uuid_reshard_collection.js13
-rw-r--r--jstests/sharding/configsvr_remove_chunks.js4
-rw-r--r--jstests/sharding/documents_db_not_exist.js2
-rw-r--r--jstests/sharding/drop_database_before_write_is_targeted.js6
-rw-r--r--jstests/sharding/health_monitor/progress_monitor_doesnt_crash_on_not_critical.js6
-rw-r--r--jstests/sharding/hedged_reads.js13
-rw-r--r--jstests/sharding/index_operations_abort_concurrent_outgoing_migrations.js5
-rw-r--r--jstests/sharding/libs/mongos_api_params_util.js2
-rw-r--r--jstests/sharding/libs/remove_shard_util.js46
-rw-r--r--jstests/sharding/mongos_rs_shard_failure_tolerance.js24
-rw-r--r--jstests/sharding/query/aggregation_currentop.js5
-rw-r--r--jstests/sharding/query/collation_lookup.js124
-rw-r--r--jstests/sharding/query/merge_nondefault_read_concern.js1
-rw-r--r--jstests/sharding/range_deletions_has_index.js1
-rw-r--r--jstests/sharding/range_deletions_setFCV.js171
-rw-r--r--jstests/sharding/refresh_sessions.js11
-rw-r--r--jstests/sharding/reshard_collection_basic.js40
-rw-r--r--jstests/sharding/reshard_collection_joins_existing_operation.js8
-rw-r--r--jstests/sharding/resharding_change_stream_namespace_filtering.js4
-rw-r--r--jstests/sharding/resharding_coordinator_recovers_abort_decision.js8
-rw-r--r--jstests/sharding/resharding_disallow_drop.js6
-rw-r--r--jstests/sharding/retryable_write_error_labels.js8
-rw-r--r--jstests/sharding/run_restore.js6
-rw-r--r--jstests/sharding/run_restore_unsharded.js6
-rw-r--r--jstests/sharding/secondaries_clear_filtering_metadata.js73
-rw-r--r--jstests/sharding/shard_encrypted_collection.js4
-rw-r--r--jstests/sharding/shard_keys_with_dollar_sign.js3
-rw-r--r--jstests/sharding/swallow_unnecessary_uuid_mismatch_error.js58
-rw-r--r--jstests/sharding/timeseries_multiple_mongos.js50
-rw-r--r--jstests/sharding/ttl_deletes_not_targeting_orphaned_documents.js16
-rw-r--r--jstests/sharding/txn_recover_decision_using_recovery_router.js15
-rw-r--r--jstests/sharding/verify_sessions_expiration_sharded.js4
-rw-r--r--jstests/ssl/libs/localhost-cn-with-san.pem84
-rw-r--r--jstests/ssl/libs/localhost-cn-with-san.pem.digest.sha12
-rw-r--r--jstests/ssl/libs/localhost-cn-with-san.pem.digest.sha2562
-rw-r--r--jstests/ssl/ssl_ingress_conn_metrics.js60
-rw-r--r--jstests/ssl/x509/certs.yml17
-rwxr-xr-xjstests/ssl/x509/mkcert.py23
-rwxr-xr-xjstests/ssl/x509/mkcrl.sh38
-rw-r--r--jstests/ssl/x509/root-and-trusted-ca.pem58
-rw-r--r--jstests/ssl/x509/root-and-trusted-ca.pem.digest.sha12
-rw-r--r--jstests/ssl/x509/root-and-trusted-ca.pem.digest.sha2562
-rw-r--r--jstests/ssl/x509/trusted-client-testdb-roles.pem84
-rw-r--r--jstests/ssl/x509/trusted-client-testdb-roles.pem.digest.sha12
-rw-r--r--jstests/ssl/x509/trusted-client-testdb-roles.pem.digest.sha2562
-rw-r--r--jstests/ssl_linear/mongo_uri_secondaries.js4
-rw-r--r--jstests/ssl_linear/repl_ssl_noca.js4
-rw-r--r--jstests/ssl_linear/ssl_cert_selector.js4
-rw-r--r--jstests/ssl_linear/ssl_with_system_ca.js4
-rw-r--r--jstests/ssl_linear/windows_castore_cleanup.py41
488 files changed, 15854 insertions, 4925 deletions
diff --git a/jstests/aggregation/accumulators/top_bottom_top_n_bottom_n.js b/jstests/aggregation/accumulators/top_bottom_top_n_bottom_n.js
index d0844a4acac..2556850752a 100644
--- a/jstests/aggregation/accumulators/top_bottom_top_n_bottom_n.js
+++ b/jstests/aggregation/accumulators/top_bottom_top_n_bottom_n.js
@@ -392,4 +392,17 @@ const testOperatorText = (op) => {
// most relevant results first.
testOperatorText("$bottomN");
testOperatorText("$topN");
+
+// Test constant output and sortBy.
+assert(coll.drop());
+assert.commandWorked(coll.insertMany([{a: 1}, {a: 2}, {a: 3}]));
+const testConstantOutputAndSort = (op) => {
+ const results =
+ coll.aggregate([{$group: {_id: null, result: {[op]: {n: 3, output: "abc", sortBy: {}}}}}])
+ .toArray();
+ assert.eq(results.length, 1, results);
+ assert.docEq(results[0], {_id: null, result: ["abc", "abc", "abc"]}, results);
+};
+testConstantOutputAndSort("$topN");
+testConstantOutputAndSort("$bottomN");
})();
diff --git a/jstests/aggregation/bugs/hash_lookup_spill_large_and_small_documents_correctly.js b/jstests/aggregation/bugs/hash_lookup_spill_large_and_small_documents_correctly.js
index de8f79bbea7..9d10fd95997 100644
--- a/jstests/aggregation/bugs/hash_lookup_spill_large_and_small_documents_correctly.js
+++ b/jstests/aggregation/bugs/hash_lookup_spill_large_and_small_documents_correctly.js
@@ -1,7 +1,4 @@
// Regression test to check that different document sizes work correctly with $lookup.
-// @tags: [
-// requires_fcv_71,
-// ]
(function() {
'use strict';
diff --git a/jstests/aggregation/bugs/server95350.js b/jstests/aggregation/bugs/server95350.js
new file mode 100644
index 00000000000..b1f939cb483
--- /dev/null
+++ b/jstests/aggregation/bugs/server95350.js
@@ -0,0 +1,34 @@
+/**
+ * SERVER-95350: Fix jstests/aggregation/api_version_stage_allowance_checks.js.
+ */
+(function() {
+"use strict";
+
+load("jstests/libs/collection_drop_recreate.js"); // For assertDropAndRecreateCollection.
+
+const collName = 'test';
+assertDropAndRecreateCollection(db, collName);
+
+let docs = [];
+for (let i = 0; i < 10; ++i) {
+ docs.push({x: i, y: i, z: i});
+}
+db[collName].insertMany(docs);
+
+assert.commandWorked(db.runCommand({
+ explain: {
+ aggregate: collName,
+ pipeline: [{
+ $mergeCursors: {
+ sort: {y: 1, z: 1},
+ compareWholeSortKey: false,
+ remotes: [],
+ nss: "test.mergeCursors",
+ allowPartialResults: false,
+ }
+ }],
+ cursor: {},
+ readConcern: {},
+ },
+}));
+})();
diff --git a/jstests/aggregation/documents_merge.js b/jstests/aggregation/documents_merge.js
new file mode 100644
index 00000000000..85744f0191e
--- /dev/null
+++ b/jstests/aggregation/documents_merge.js
@@ -0,0 +1,112 @@
+/**
+ * This is the test for $documents stage along with $merge stage in an aggregation pipeline,
+ * including verifying the bug in SERVER-85892 is addressed when the spec 'whenMatched' is not
+ * empty.
+ *
+ * @tags: [
+ * assumes_against_mongod_not_mongos, # not yet supported until 7.2 with SERVER-65534
+ * ]
+ */
+
+load("jstests/aggregation/extras/merge_helpers.js"); // For withEachMergeMode and
+ // dropWithoutImplicitRecreate.
+
+const outColl = db[`${jsTest.name()}_out`];
+const outCollName = outColl.getName();
+const expectedTotalDocs = 100;
+
+function assertDocsInsertedCorrectly(docs, pipeline) {
+ const msg = `Failed with pipeline: ${JSON.stringify(pipeline, null, 2)}`;
+
+ assert.eq(expectedTotalDocs, docs.length, msg);
+ for (let i = 0; i < expectedTotalDocs; i++) {
+ assert.eq(docs[i].x, i, msg);
+ }
+}
+
+const documentsStage = {
+ $documents: {$map: {input: {$range: [0, expectedTotalDocs]}, in : {x: "$$this"}}}
+};
+
+function testFn(pipeline, assertFn) {
+ // Creates an index as $merge requires a unique index with the 'on' identifier field. Then
+ // inserts a document allowed to be matched.
+ dropWithoutImplicitRecreate(outCollName);
+ assert.commandWorked(outColl.createIndex({x: 1}, {unique: true}));
+ assert.commandWorked(outColl.insert({x: 10}));
+
+ assert.doesNotThrow(() => db.aggregate(pipeline));
+ let res = outColl.find({}, {_id: 0}).sort({x: 1}).toArray();
+ assertDocsInsertedCorrectly(res, pipeline);
+ assertFn(res);
+}
+
+{ // Tests $merge with non-empty pipeline along with let in whenMatched spec.
+ const pipeline = [
+ documentsStage,
+ {
+ $merge: {
+ into: outCollName,
+ let : {num: 123},
+ whenMatched: [{$set: {number: "$$num"}}],
+ on: "x"
+ }
+ }
+ ];
+
+ testFn(pipeline, res => {
+ assert.eq(res.filter(elem => elem.number === 123).length, 1);
+ });
+}
+
+{ // Tests $merge with non-empty pipeline in whenMatched spec.
+ const pipeline = [
+ documentsStage,
+ {$merge: {into: outCollName, whenMatched: [{$set: {new: true}}], on: "x"}}
+ ];
+
+ testFn(pipeline, res => {
+ assert.eq(res.filter(elem => elem.new === true).length, 1);
+ });
+}
+
+// Tests each combination of merge modes.
+withEachMergeMode(({whenMatchedMode, whenNotMatchedMode}) => {
+ const expectErrorCode = whenMatchedMode === "fail"
+ ? ErrorCodes.DuplicateKey
+ : whenNotMatchedMode === "fail" ? ErrorCodes.MergeStageNoMatchingDocument : null;
+
+ // Creates an index as $merge requires a unique index with the 'on' identifier field. Then
+ // inserts a document allowed to be matched.
+ dropWithoutImplicitRecreate(outCollName);
+ assert.commandWorked(outColl.createIndex({x: 1}, {unique: true}));
+ assert.commandWorked(outColl.insert({x: 10, old: true}));
+
+ const pipeline = [
+ documentsStage,
+ {
+ $merge: {
+ into: outCollName,
+ whenMatched: whenMatchedMode,
+ whenNotMatched: whenNotMatchedMode,
+ on: "x",
+ }
+ }
+ ];
+
+ if (expectErrorCode) {
+ assert.throwsWithCode(() => db.aggregate(pipeline), expectErrorCode);
+ return;
+ }
+
+ assert.doesNotThrow(() => db.aggregate(pipeline));
+ let res = outColl.find({}, {_id: 0}).sort({x: 1}).toArray();
+ if (whenNotMatchedMode == "discard") {
+ assert.eq(outColl.count(), 1);
+ } else {
+ assertDocsInsertedCorrectly(res, pipeline);
+ }
+
+ // Asserts if the old document is replaced when 'whenMatchedMode' is "replace".
+ assert.eq(res.filter(elem => elem.old === true).length, whenMatchedMode == "replace" ? 0 : 1);
+});
diff --git a/jstests/aggregation/expressions/expression_set_field_null_chars.js b/jstests/aggregation/expressions/expression_set_field_null_chars.js
new file mode 100644
index 00000000000..4232bc033ef
--- /dev/null
+++ b/jstests/aggregation/expressions/expression_set_field_null_chars.js
@@ -0,0 +1,96 @@
+/**
+ * Tests that $setField handles null chars in the 'field' argument correctly.
+ */
+(function() {
+"use strict";
+
+const coll = db[jsTestName()];
+coll.drop();
+
+assert.commandWorked(coll.insert({_id: 1, foo: "bar"}));
+
+// Asserts $setField and $unsetField with the given 'field' argument fail with one of the given
+// 'codes' when used in various commands.
+function assertSetFieldFailsWithCode({field, codes}) {
+ const setFieldExpressions = [
+ {$setField: {field, input: {}, value: true}},
+ {$unsetField: {field, input: {}}},
+ ];
+
+ for (const setFieldExpression of setFieldExpressions) {
+ const errorMsg = tojson(setFieldExpression);
+
+ assert.commandFailedWithCode(
+ db.runCommand({find: coll.getName(), projection: {field: setFieldExpression}}),
+ codes,
+ errorMsg);
+ assert.commandFailedWithCode(db.runCommand({
+ aggregate: coll.getName(),
+ pipeline: [{$project: {field: setFieldExpression}}, {$out: coll.getName() + "-2"}],
+ cursor: {}
+ }),
+ codes,
+ errorMsg);
+ assert.commandFailedWithCode(db.runCommand({
+ aggregate: coll.getName(),
+ pipeline: [{
+ $merge: {
+ into: coll.getName(),
+ whenMatched: [{$replaceWith: setFieldExpression}],
+ whenNotMatched: "discard"
+ }
+ }],
+ cursor: {}
+ }),
+ codes,
+ errorMsg);
+ assert.commandFailedWithCode(db.runCommand({
+ update: coll.getName(),
+ updates: [{q: {_id: 1}, u: [{$replaceWith: setFieldExpression}], multi: false}]
+ }),
+ codes,
+ errorMsg);
+ assert.commandFailedWithCode(db.runCommand({
+ findAndModify: coll.getName(),
+ query: {_id: 1},
+ update: [{$replaceWith: setFieldExpression}]
+ }),
+ codes,
+ errorMsg);
+ }
+}
+
+const invalidFieldNames = [
+ // Starts with null chars.
+ "\x00a",
+ // Ends with null chars.
+ "a\x00",
+ // All null chars.
+ "\x00",
+ "\x00\x00\x00",
+ // Null chars somewhere in the middle.
+ "a\x00\x01\x08a",
+ "a\x00\x02\x08b",
+ "a\x00\x01\x18b",
+ "a\x00\x01\x28c",
+ "a\x00\x01\x03d\x00\xff\xff\xff\xff\x00\x08b",
+];
+
+// Test each field name directly, as part of a field reference, wrapped in $const/$literal,
+// wrapped in a const-foldable expression as well as some combinations of these.
+for (const field of invalidFieldNames) {
+ assertSetFieldFailsWithCode({field, codes: [9534700, 9423101]});
+ assertSetFieldFailsWithCode({field: {$const: field}, codes: [9534700, 9423101]});
+ assertSetFieldFailsWithCode({field: {$literal: field}, codes: [9534700, 9423101]});
+ assertSetFieldFailsWithCode({field: "$" + field, codes: [16411, 9423101]});
+ assertSetFieldFailsWithCode({field: "$foo." + field, codes: [16411, 9423101]});
+ assertSetFieldFailsWithCode({field: "foo." + field, codes: [9534700, 9423101]});
+ assertSetFieldFailsWithCode({field: {$const: "$" + field}, codes: [9534700, 9423101]});
+ assertSetFieldFailsWithCode({field: {$const: "$foo." + field}, codes: [9534700, 9423101]});
+ // Sanity check: non-literal expressions are not allowed even when they could be const
+ // folded.
+ assertSetFieldFailsWithCode({field: {$concat: [field]}, codes: [4161106, 9423101]});
+ assertSetFieldFailsWithCode({field: {$toUpper: field}, codes: [4161106, 9423101]});
+ assertSetFieldFailsWithCode({field: {$toLower: field}, codes: [4161106, 9423101]});
+}
+})();
diff --git a/jstests/aggregation/bugs/server18427.js b/jstests/aggregation/expressions/log_pow_exp.js
index a633632ab3d..b74cf4fed93 100644
--- a/jstests/aggregation/bugs/server18427.js
+++ b/jstests/aggregation/expressions/log_pow_exp.js
@@ -10,13 +10,29 @@ var coll = db.log_exponential_expressions;
coll.drop();
assert.commandWorked(coll.insert({_id: 0, a: 8, b: 2}));
-var decimalE = NumberDecimal("2.718281828459045235360287471352662");
-var decimal1overE = NumberDecimal("0.3678794411714423215955237701614609");
+const doubleE = 2.7182818284590452;
+const decimalE = NumberDecimal("2.718281828459045235360287471352662");
+const decimal1overE = NumberDecimal("0.3678794411714423215955237701614609");
+
+// Given a double, is it an integer?
+function isInteger(n) {
+ return !n.toString().includes('.');
+}
+
+function isNumberDecimal(n) {
+ return n.toString().includes('NumberDecimal');
+}
// Helper for testing that op returns expResult.
-function testOp(op, expResult) {
- var pipeline = [{$project: {_id: 0, result: op}}];
- assert.eq(coll.aggregate(pipeline).toArray(), [{result: expResult}]);
+function testOp(op, expResult, failMsg) {
+ const pipeline = [{$project: {_id: 0, result: op}}];
+ const result = coll.aggregate(pipeline).toArray();
+ assert.eq(result.length, 1);
+ if (expResult === null || isNaN(expResult) || isNumberDecimal(expResult)) {
+ assert.eq(result[0].result, expResult, failMsg);
+ } else {
+ assert.close(result[0].result, expResult, failMsg, 12 /*places*/);
+ }
}
// $log, $log10, $ln.
@@ -26,11 +42,180 @@ function testOp(op, expResult) {
testOp({$log: [10, 10]}, 1);
testOp({$log10: [10]}, 1);
testOp({$ln: [Math.E]}, 1);
-// - NumberDecimal
-testOp({$log: [NumberDecimal("10"), NumberDecimal("10")]}, NumberDecimal("1"));
-testOp({$log10: [NumberDecimal("10")]}, NumberDecimal("1"));
-// The below answer is actually correct: the input is an approximation of E
-testOp({$ln: [decimalE]}, NumberDecimal("0.9999999999999999999999999999999998"));
+
+// Different double and NumberDecimal inputs, verified manually.
+const logTestCases = [
+ // Base 8
+ {input: 1, base: 8, doubleResult: 0, decResult: NumberDecimal("0E+33")},
+ {
+ input: 2.5,
+ base: 8,
+ doubleResult: 0.4406426982957875,
+ decResult: NumberDecimal("0.4406426982957874492901064764964633")
+ },
+ {
+ input: 7,
+ base: 8,
+ doubleResult: 0.9357849740192015,
+ decResult: NumberDecimal("0.9357849740192013691473231057439436")
+ },
+ {input: 8, base: 8, doubleResult: 1, decResult: NumberDecimal("1")},
+ {
+ input: 64,
+ base: 8,
+ doubleResult: 2,
+ decResult: NumberDecimal("2.000000000000000000000000000000000")
+ },
+ {
+ input: 65,
+ base: 8,
+ doubleResult: 2.0074559376761516,
+ decResult: NumberDecimal("2.007455937676151502755710694582028")
+ },
+
+ // Base 9, a more unusual base.
+ {input: 1, base: 9, doubleResult: 0, decResult: NumberDecimal("0E+33")},
+ {
+ input: 2.5,
+ base: 9,
+ doubleResult: 0.41702188357323483,
+ decResult: NumberDecimal("0.4170218835732348650487566466679398")
+ },
+ {
+ input: 4,
+ base: 9,
+ doubleResult: 0.6309297535714574,
+ decResult: NumberDecimal("0.6309297535714574370995271143427609")
+ },
+ {input: 9, base: 9, doubleResult: 1, decResult: NumberDecimal("1")},
+ {
+ input: 10,
+ base: 9,
+ doubleResult: 1.0479516371446924,
+ decResult: NumberDecimal("1.047951637144692302148283761010701")
+ },
+ {input: 81, base: 9, doubleResult: 2, decResult: NumberDecimal("2")},
+ {
+ input: 82,
+ base: 9,
+ doubleResult: 2.0055843597957064,
+ decResult: NumberDecimal("2.005584359795706389324272570756155")
+ },
+
+ // Base 12.77, an even MORE unusual base.
+ {input: 1, base: 12.77, doubleResult: 0, decResult: NumberDecimal("0E+33")},
+ {
+ input: 2.5,
+ base: 12.77,
+ doubleResult: 0.3597390013391846,
+ decResult: NumberDecimal("0.3597390013391846393309152124110717")
+ },
+ {input: 12.77, base: 12.77, doubleResult: 1, decResult: NumberDecimal("1")},
+ {
+ input: 13,
+ base: 12.77,
+ doubleResult: 1.0070082433896357,
+ decResult: NumberDecimal("1.007008243389635671677137269228113")
+ },
+ {
+ input: 163.0729,
+ base: 12.77,
+ doubleResult: 2,
+ decResult: NumberDecimal("2.000000000000000000000000000000000")
+ },
+ {
+ input: 170,
+ base: 12.77,
+ doubleResult: 2.016332738676606,
+ decResult: NumberDecimal("2.016332738676605709114981994718173")
+ },
+];
+for (const test of logTestCases) {
+ // If we can cast our input, base (or both) to integer types, test them as well.
+ const inputs = [test.input, NumberDecimal(test.input.toString())];
+ if (isInteger(test.input)) {
+ inputs.push(NumberInt(test.input), NumberLong(test.input));
+ }
+ const bases = [test.base, NumberDecimal(test.base.toString())];
+ if (isInteger(test.base)) {
+ bases.push(NumberInt(test.base), NumberLong(test.base));
+ }
+ for (const input of inputs) {
+ for (const base of bases) {
+ const hasDecimalInput = isNumberDecimal(input) || isNumberDecimal(base);
+ testOp(
+ {$log: [input, base]}, hasDecimalInput ? test.decResult : test.doubleResult, test);
+ }
+ }
+}
+
+// Base 10, using $log10
+const log10TestCases = [
+ {input: 1, doubleResult: 0, decResult: NumberDecimal("0")},
+ {
+ input: 2.5,
+ doubleResult: 0.3979400086720376,
+ decResult: NumberDecimal("0.3979400086720376095725222105510140")
+ },
+ {input: 10, doubleResult: 1, decResult: NumberDecimal("1")},
+ {
+ input: 11,
+ doubleResult: 1.041392685158225,
+ decResult: NumberDecimal("1.041392685158225040750199971243024")
+ },
+ {input: 100, doubleResult: 2, decResult: NumberDecimal("2")},
+ {
+ input: 101,
+ doubleResult: 2.0043213737826426,
+ decResult: NumberDecimal("2.004321373782642574275188178222938")
+ },
+];
+for (const test of log10TestCases) {
+ // If the input is an integer anyway, test with our integer types as well.
+ if (isInteger(test.input)) {
+ testOp({$log10: NumberInt(test.input)}, test.doubleResult, test);
+ testOp({$log10: NumberLong(test.input)}, test.doubleResult, test);
+ }
+ testOp({$log10: test.input}, test.doubleResult, test);
+ testOp({$log10: NumberDecimal(test.input.toString())}, test.decResult, test);
+}
+
+// Base `e`, using $ln.
+const lnTestCases = [
+ {input: 1, doubleResult: 0, decResult: NumberDecimal("0")},
+ // `e` is about 2.7, so this should be close to 1.
+ {
+ input: 2.5,
+ doubleResult: 0.9162907318741551,
+ decResult: NumberDecimal("0.9162907318741550651835272117680110")
+ },
+ {
+ input: 7,
+ doubleResult: 1.9459101490553132,
+ decResult: NumberDecimal("1.945910149055313305105352743443180")
+ },
+ {
+ input: 10,
+ doubleResult: 2.302585092994046,
+ decResult: NumberDecimal("2.302585092994045684017991454684364")
+ },
+];
+for (const test of lnTestCases) {
+ if (isInteger(test.input)) {
+ testOp({$ln: NumberInt(test.input)}, test.doubleResult, test);
+ testOp({$ln: NumberLong(test.input)}, test.doubleResult, test);
+ }
+ testOp({$ln: test.input}, test.doubleResult, test);
+ testOp({$ln: NumberDecimal(test.input.toString())}, test.decResult, test);
+}
+
+// We represent `e` differently with double and NumberDecimal, so test that here.
+testOp({$ln: doubleE}, 1);
+testOp({$ln: 1 / doubleE}, -1);
+// The below answer is actually correct: the input is an approximation of E.
+testOp({$ln: decimalE}, NumberDecimal("0.9999999999999999999999999999999998"));
+testOp({$ln: decimal1overE}, NumberDecimal("-0.9999999999999999999999999999999998"));
+
// All types converted to doubles.
testOp({$log: [NumberLong("10"), NumberLong("10")]}, 1);
testOp({$log10: [NumberLong("10")]}, 1);
diff --git a/jstests/aggregation/extras/utils.js b/jstests/aggregation/extras/utils.js
index 6face031533..febd852c253 100644
--- a/jstests/aggregation/extras/utils.js
+++ b/jstests/aggregation/extras/utils.js
@@ -342,6 +342,19 @@ function assertErrCodeAndErrMsgContains(coll, pipe, code, expectedMessage) {
}
/**
+ * Assert that an aggregation ran on admin DB fails with a specific code and the error message
+ * contains the given string. Note that 'code' can be an array of possible codes.
+ */
+function assertAdminDBErrCodeAndErrMsgContains(coll, pipe, code, expectedMessage) {
+ const response = assert.commandFailedWithCode(
+ coll.getDB().adminCommand({aggregate: 1, pipeline: pipe, cursor: {}}), code);
+ assert.neq(
+ -1,
+ response.errmsg.indexOf(expectedMessage),
+ "Error message did not contain '" + expectedMessage + "', found:\n" + tojson(response));
+}
+
+/**
* Assert that an aggregation fails with any code and the error message contains the given
* string.
*/
diff --git a/jstests/aggregation/group_by_objectid.js b/jstests/aggregation/group_by_objectid.js
new file mode 100644
index 00000000000..4d7b638b6e5
--- /dev/null
+++ b/jstests/aggregation/group_by_objectid.js
@@ -0,0 +1,36 @@
+// Tests that $group aggregation works with group key of type ObjectId.
+// @tags: [
+// # Some in memory variants will error because this test uses too much memory. As such, we do not
+// # run this test on in-memory variants.
+// requires_persistence,
+// ]
+const collName = jsTestName();
+const coll = db[collName];
+coll.drop();
+
+const bigStr = Array(100 * 1000).toString(); // ~ 100KB of ','
+const bigStr2 = bigStr + "2";
+const nDocs = 1000;
+const nGroups = 10;
+
+let objectIds = [];
+for (let i = 0; i < nGroups; i++) {
+ objectIds.push(new ObjectId());
+}
+
+const bulk = coll.initializeUnorderedBulkOp();
+for (let i = 1; i <= nDocs; i++) {
+ bulk.insert({b: objectIds[i % nGroups], bigStr: bigStr, b2: bigStr2, c: i});
+}
+assert.commandWorked(bulk.execute());
+
+const pipeline = [
+ {
+ $sort: {
+ "c": NumberInt(-1),
+ }
+ },
+ {$group: {"_id": "$b", "doc": {"$first": "$$ROOT"}}},
+];
+
+assert.commandWorked(db.runCommand({aggregate: collName, pipeline: pipeline, cursor: {}}));
diff --git a/jstests/aggregation/ifnull.js b/jstests/aggregation/ifnull.js
index f147111a259..86d4ad2f85d 100644
--- a/jstests/aggregation/ifnull.js
+++ b/jstests/aggregation/ifnull.js
@@ -15,7 +15,8 @@ assert.commandWorked(t.insertOne({
my_null: null,
my_undefined: undefined,
my_obj: {},
- my_list: []
+ my_list: [],
+ my_nested: {zero: 0, null: null, undefined: undefined}
}));
function assertError(expectedErrorCode, ifNullSpec) {
@@ -23,8 +24,12 @@ function assertError(expectedErrorCode, ifNullSpec) {
}
function assertResult(expectedResult, ifNullSpec) {
- const res = t.aggregate({$project: {_id: 0, a: {$ifNull: ifNullSpec}}}).toArray()[0];
+ let res = t.aggregate({$project: {_id: 0, a: {$ifNull: ifNullSpec}}}).toArray()[0];
assert.docEq({a: expectedResult}, res);
+ res = t.aggregate({
+ $group: {_id: 0, a: {$push: {$let: {vars: {x: {$ifNull: ifNullSpec}}, in : "$$x"}}}}
+ }).toArray()[0];
+ assert.docEq({_id: 0, a: [expectedResult]}, res);
}
// Wrong number of args.
@@ -33,6 +38,7 @@ assertError(1257300, ['$one']);
assertError(1257300, ['$my_null']);
// First arg non null.
+assertResult(0, ['$my_nested.zero', '$one']);
assertResult(1, ['$one', '$two']);
assertResult(2, ['$two', '$one']);
assertResult(false, ['$my_false', '$one']);
@@ -48,6 +54,7 @@ assertResult(1, ['$one', '$two', null]);
assertResult(2, ['$two', '$my_undefined', null]);
// First arg null.
+assertResult(0, ['$my_nested.null', '$my_nested.zero']);
assertResult(2, ['$my_null', '$two']);
assertResult(1, ['$my_null', '$one']);
assertResult(null, ['$my_null', '$my_null']);
@@ -59,6 +66,7 @@ assertResult(null, ['$my_null', '$my_null', null]);
assertResult(undefined, ['$my_null', '$my_null', undefined]);
// First arg undefined.
+assertResult(0, ['$my_nested.undefined', '$my_nested.zero']);
assertResult(2, ['$my_undefined', '$two']);
assertResult(1, ['$my_undefined', '$one']);
assertResult(null, ['$my_undefined', '$my_null']);
diff --git a/jstests/aggregation/sources/documents.js b/jstests/aggregation/sources/documents/basics.js
index ed90e9ac7aa..ed90e9ac7aa 100644
--- a/jstests/aggregation/sources/documents.js
+++ b/jstests/aggregation/sources/documents/basics.js
diff --git a/jstests/aggregation/sources/documents/subpipeline_validation.js b/jstests/aggregation/sources/documents/subpipeline_validation.js
new file mode 100644
index 00000000000..7d4ae87584f
--- /dev/null
+++ b/jstests/aggregation/sources/documents/subpipeline_validation.js
@@ -0,0 +1,215 @@
+// Tests the validation logic for combinations of "collectionless" stages like $documents with or
+// around sub-pipelines. For the cases that should be legal, we mostly just care the the command
+// succeeds. However, we will use 'resultsEq' to test correct semantics while we are here, gaining
+// more coverage.
+// TODO SERVER-94226 consider extending this test to cases like $currentOp and $queryStats as well.
+// This test uses stages like $documents which are not permitted inside a $facet stage.
+// @tags: [do_not_wrap_aggregations_in_facets]
+(function() {
+"use strict";
+load("jstests/aggregation/extras/utils.js"); // For 'resultsEq.'
+load("jstests/libs/fixture_helpers.js"); // For 'isMongos.'
+
+const coll = db[jsTestName()];
+coll.drop();
+
+const targetCollForMerge = db["target_coll"];
+targetCollForMerge.drop();
+assert.commandWorked(coll.insert({_id: 0, arr: [{}, {}]}));
+
+{
+ // Tests for an aggregation over a collection (i.e. {aggregate: "collName"} commands) with a
+ // $documents stage used in a sub-pipeline. Each of these cases should be legal, which is most
+ // of the value of the assertion. We will use 'resultsEq' to test correct semantics while we are
+ // here.
+
+ // $lookup.
+ assert(resultsEq(coll.aggregate([
+ {$lookup: {
+ let: {documents: "$arr"},
+ pipeline: [
+ {$documents: "$$documents"},
+ ],
+ as: "duplicated"
+ }},
+ ]).toArray(), [{_id: 0, arr: [{}, {}], duplicated: [{}, {}]}]));
+
+ // $unionWith.
+ assert(resultsEq(coll.aggregate([
+ {
+ $unionWith: {
+ pipeline: [
+ {$documents: [{_id: "gen"}]},
+ ],
+ }
+ },
+ ])
+ .toArray(),
+ [{_id: 0, arr: [{}, {}]}, {_id: "gen"}]));
+
+ // Both, and more nesting.
+ assert(resultsEq(coll.aggregate([{
+ $unionWith: {
+ coll: coll.getName(),
+ pipeline: [{
+ $lookup: {
+ pipeline: [
+ {$documents: []},
+ {$unionWith: {coll: coll.getName(), pipeline: []}}
+ ],
+ as: "nest"
+ }
+ }]
+ }
+ }])
+ .toArray(),
+ [
+ {_id: 0, arr: [{}, {}]},
+ {_id: 0, arr: [{}, {}], nest: [{_id: 0, arr: [{}, {}]}]}
+ ]));
+}
+
+{
+ // Tests for a db-level aggregate (i.e. {aggregate: 1} commands) with sub-pipelines on regular
+ // collections.
+
+ // $facet
+ assert(resultsEq(db.aggregate([
+ {
+ $documents: [
+ {x: 1, y: 1, val: 1},
+ {x: 2, y: 2, val: 1},
+ {x: 3, y: 1, val: 2},
+ {x: 2, y: 2, val: 1}
+ ]
+ },
+ {
+ $facet: {
+ sumByX: [{$group: {_id: "$x", sum: {$sum: "$val"}}}],
+ sumByY: [{$group: {_id: "$y", sum: {$sum: "$val"}}}]
+ }
+ }
+ ]).toArray(),
+ [{
+ sumByX: [{_id: 1, sum: 1}, {_id: 2, sum: 2}, {_id: 3, sum: 2}],
+ sumByY: [{_id: 1, sum: 3}, {_id: 2, sum: 2}]
+ }]));
+
+ if (!FixtureHelpers.isMongos(db)) {
+ // This doesn't work on mongos in v7.0 and earlier - waiting for SERVER-65534.
+
+ // $lookup.
+ assert(resultsEq(db.aggregate([
+ {$documents: [{x: 1, arr: [{x: 2}]}, {y: 1, arr: []}]},
+ {$lookup: {
+ let: {documents: "$arr"},
+ pipeline: [
+ {$documents: "$$documents"},
+ ],
+ as: "duplicated"
+ }},
+ ]).toArray(),
+ [
+ {x: 1, arr: [{x: 2}], duplicated: [{x: 2}]},
+ {y: 1, arr: [], duplicated: []}
+ ]));
+
+ // $merge.
+ assert.doesNotThrow(() => db.aggregate([
+ {
+ $documents: [
+ {_id: 2, x: "foo"},
+ {_id: 4, x: "bar"},
+ ]
+ },
+ {
+ $merge: {
+ into: targetCollForMerge.getName(),
+ on: "_id",
+ whenMatched: [{$set: {x: {$setUnion: ["$x", "$$new.x"]}}}]
+ }
+ }
+ ]));
+ assert(resultsEq(targetCollForMerge.find({}, {_id: 1}).toArray(), [{_id: 2}, {_id: 4}]));
+
+ // $unionWith
+ assert(resultsEq(db.aggregate([
+ {$documents: [{_id: 2}, {_id: 4}]},
+ {$unionWith: {coll: coll.getName(), pipeline: []}}
+ ]).toArray(),
+ [{_id: 2}, {_id: 4}, {_id: 0, arr: [{}, {}]}]));
+
+ // All of the above, plus nesting.
+ const results =
+ db.aggregate([
+ {$documents: [{_id: "first"}]},
+ {
+ $unionWith: {
+ pipeline: [
+ {$documents: [{_id: "uw"}]},
+ {$unionWith: {pipeline: [{$documents: [{_id: "uw_2"}]}]}},
+ {
+ $facet: {
+ allTogether:
+ [{$group: {_id: null, all: {$addToSet: "$_id"}}}],
+ countEach: [{$group: {_id: "$_id", count: {$sum: 1}}}],
+ }
+ },
+ {
+ $lookup:
+ {pipeline: [{$documents: [{x: "lu1"}, {x: "lu2"}]}], as: "xs"}
+ },
+ {$set: {xs: {$map: {input: "$xs", in : "$$this.x"}}}}
+ ]
+ },
+ },
+ ]).toArray();
+ assert(resultsEq(results,
+ [
+ {_id: "first"},
+ {
+ allTogether: [{_id: null, all: ["uw", "uw_2"]}],
+ countEach: [{_id: "uw", count: 1}, {_id: "uw_2", count: 1}],
+ xs: ["lu1", "lu2"]
+ }
+ ]),
+ results);
+ }
+}
+
+// Test for invalid combinations.
+
+// To use $documents inside a $lookup, there must not be a "from" argument.
+// As of SERVER-94144, this does not throw on 7.0 and older branches.
+assert.doesNotThrow(
+ () => coll.aggregate([{$lookup: {from: "foo", pipeline: [{$documents: []}], as: "lustuff"}}]));
+assert.doesNotThrow(
+ () => coll.aggregate([
+ {$lookup: {
+ from: "foo",
+ let: {docs: "$arr"},
+ pipeline: [
+ {$documents: "$$docs"},
+ {$lookup: {
+ from: "foo",
+ let: {x: "$x", y: "$y"},
+ pipeline: [
+ {$match: {$expr: {$and: [
+ {$eq: ["$x", "$$x"]},
+ {$eq: ["$y", "$$y"]}
+ ]}}}
+ ],
+ as: "doesnt_matter"
+ }}
+ ],
+ as: "lustuff"
+ }}]));
+
+// To use $documents inside a $unionWith, there must not be a "coll" argument.
+// As of SERVER-94144, this does not throw on 7.0 and older branches.
+assert.doesNotThrow(
+ () => coll.aggregate([{$unionWith: {coll: "foo", pipeline: [{$documents: []}]}}]));
+
+// Cannot use $documents inside of $facet.
+assert.throwsWithCode(() => coll.aggregate([{$facet: {test: [{$documents: []}]}}]), 40600);
+})();
diff --git a/jstests/aggregation/sources/lookup/lookup_absorb_match.js b/jstests/aggregation/sources/lookup/lookup_absorb_match.js
index be589615f5c..4220cbcb71a 100644
--- a/jstests/aggregation/sources/lookup/lookup_absorb_match.js
+++ b/jstests/aggregation/sources/lookup/lookup_absorb_match.js
@@ -136,7 +136,7 @@ expected =
[{_id: "dog", locationId: "doghouse", location: {_id: "doghouse", coordinates: [25.0, 60.0]}}];
assert.eq(result, expected);
-// Test that a $match with $jsonSchema works as expected although ineligable for absorbtion by a
+// Test that a $match with $jsonSchema works as expected although ineligible for absorbtion by a
// $lookup.
result = testDB.animals
.aggregate([
@@ -167,7 +167,7 @@ expected =
[{_id: "bull", locationId: "bullpen", location: {_id: "bullpen", coordinates: [-25.0, -60.0]}}];
assert.eq(result, expected);
-// Test that a more complex $match with $jsonSchema works as expected although ineligable for
+// Test that a more complex $match with $jsonSchema works as expected although ineligible for
// absorbtion by a $lookup.
result = testDB.animals
.aggregate([
@@ -194,8 +194,100 @@ expected =
[{_id: "bull", locationId: "bullpen", location: {_id: "bullpen", coordinates: [-25.0, -60.0]}}];
assert.eq(result, expected);
-// Test that a $match with $alwaysTrue works as expected although ineligable for absorbtion by a
-// $lookup.
+// Test that $match with a $jsonSchema property that will internally translate to a match
+// expression node that has a path that is prefixed by the 'as' field in the lookup and that has
+// children that can operate on that path (in this case, $_internalSchemaAllElemMatchFromIndex)
+// works as expected although ineligible for absorbtion by a $lookup. Note that the jsonSchema below
+// ensures that all elements of 'location.coordinates' are above 0 since the 'items' field is an
+// object.
+result = testDB.animals
+ .aggregate([
+ {
+ $lookup: {
+ from: "locations",
+ localField: "locationId",
+ foreignField: "_id",
+ as: "location"
+ }
+ },
+ {$unwind: "$location"},
+ {
+ $match: {
+ $jsonSchema: {
+ properties: {"location.coordinates": {items: {minimum: 0}}}
+ }
+ }
+ },
+ {$project: {"location.extra": false, "colors": false}}
+ ])
+ .toArray();
+
+expected =
+ [{_id: "dog", locationId: "doghouse", location: {_id: "doghouse", coordinates: [25.0, 60.0]}}];
+assert.eq(result, expected);
+
+// Test that $match with a $jsonSchema property that will internally translate to a match
+// expression node that has a path that is prefixed by the 'as' field in the lookup and that has
+// children that can operate on that path (in this case, $_internalSchemaMatchArrayIndex) works as
+// expected although ineligible for absorbtion by a $lookup. Note that the jsonSchema below ensures
+// that the first element of 'location.coordinates' is above 0 since the 'items' field is an array.
+result = testDB.animals
+ .aggregate([
+ {
+ $lookup: {
+ from: "locations",
+ localField: "locationId",
+ foreignField: "_id",
+ as: "location"
+ }
+ },
+ {$unwind: "$location"},
+ {
+ $match: {
+ $jsonSchema: {
+ properties: {"location.coordinates": {items: [{minimum: 0}]}}
+ }
+ }
+ },
+ {$project: {"location.extra": false, "colors": false}}
+ ])
+ .toArray();
+
+expected =
+ [{_id: "dog", locationId: "doghouse", location: {_id: "doghouse", coordinates: [25.0, 60.0]}}];
+assert.eq(result, expected);
+
+// Test that $match with a $jsonSchema property that will internally translate to a match
+// expression node that has a path that is prefixed by the 'as' field in the lookup and that has
+// children that can operate that path (in this case, $_internalSchemaObjectMatch) works as expected
+// although ineligible for absorbtion by a $lookup.
+result = testDB.animals
+ .aggregate([
+ {
+ $lookup: {
+ from: "locations",
+ localField: "locationId",
+ foreignField: "_id",
+ as: "location"
+ }
+ },
+ {$unwind: "$location"},
+ {
+ $match: {
+ $jsonSchema: {
+ properties: {"location.extra": {type: 'object', properties: {"breeds": {type: 'string'}}}}
+ }
+ }
+ },
+ {$project: {"location.extra": false, "colors": false}}
+ ])
+ .toArray();
+expected =
+ [{_id: "bull", locationId: "bullpen", location: {_id: "bullpen", coordinates: [-25.0, -60.0]}}];
+assert.eq(result, expected);
+
+// Test that a $match with $alwaysTrue works as expected although ineligible for absorbtion
+// by a $lookup. The $sort is to guarantee records are returned in the expected order.
result = testDB.animals
.aggregate([
{
@@ -220,7 +312,7 @@ expected = [
];
assert.eq(result, expected);
-// Test that a $match with $alwaysFalse works as expected although ineligable for absorbtion by a
+// Test that a $match with $alwaysFalse works as expected although ineligible for absorbtion by a
// $lookup.
result = testDB.animals
.aggregate([
@@ -242,7 +334,7 @@ result = testDB.animals
expected = [];
assert.eq(result, expected);
-// Test that a $match with $expr works as expected although ineligable for absorbtion by a $lookup.
+// Test that a $match with $expr works as expected although ineligible for absorbtion by a $lookup.
result = testDB.animals
.aggregate([
{
diff --git a/jstests/aggregation/sources/lookup/lookup_collation.js b/jstests/aggregation/sources/lookup/lookup_collation.js
index 50ec057ae79..36f18b7e44c 100644
--- a/jstests/aggregation/sources/lookup/lookup_collation.js
+++ b/jstests/aggregation/sources/lookup/lookup_collation.js
@@ -3,14 +3,11 @@
* when performing comparisons on a foreign collection with a different default collation. Exercises
* the fix for SERVER-43350.
*
- * Collation can be set at three different levels for $lookup stage
+ * Collation can be set at two different levels for $lookup stage
* 1. on the local collection (collation on the foreign collection is always ignored)
- * 2. on the $lookup stage via '_internalCollation' property
- * 3. on the aggregation command via 'collation' property in options
+ * 2. on the aggregation command via 'collation' property in options
*
- * The three settings have the following precedence:
- * 1. '_internalCollation' overrides all others
- * 2. 'collation' option overrides local collection's collation
+ * The 'collation' command option overrides local collection's collation.
*/
load("jstests/aggregation/extras/utils.js"); // For anyEq.
load("jstests/libs/analyze_plan.js"); // For getAggPlanStages, getWinningPlan.
@@ -137,29 +134,6 @@ let explain;
}
})();
-// Collation set on $lookup stage with '_internalCollation' should override collation of the local
-// collection and on the command.
-(function testStageCollationPrecedence() {
- for (let lookupInto of [lookupWithPipeline, lookupNoPipeline]) {
- let lookupStage = lookupInto(collAa);
- lookupStage.$lookup._internalCollation = caseInsensitive;
- results = collAa.aggregate([lookupStage], {collation: caseSensitive}).toArray();
- assertArrayEq({
- actual: results,
- expected: resultCaseInsensitive,
- extraErrorMsg: " Case-insensitive collation on stage, running: " + tojson(lookupInto)
- });
-
- lookupStage.$lookup._internalCollation = caseSensitive;
- results = collAA.aggregate([lookupStage], {collation: caseInsensitive}).toArray();
- assertArrayEq({
- actual: results,
- expected: resultCaseSensistive,
- extraErrorMsg: " Case-sensitive collation on stage, running: " + tojson(lookupInto)
- });
- }
-})();
-
// In presense of indexes lookup might choose a different strategy for the join, that relies on the
// index (INLJ). It should respect the effective collation of $lookup.
(function testCollationWithIndexes() {
@@ -213,19 +187,6 @@ let explain;
explain = collAa.explain().aggregate([lookupInto(collAa_indexed)],
{collation: {locale: "fr"}, allowDiskUse: false});
assertNestedLoopJoinStrategy(explain);
-
- // Stage-level collation overrides collection-level and command-level collations.
- let lookupStage = lookupInto(collAa_indexed);
- lookupStage.$lookup._internalCollation = caseInsensitive;
- results = collAa.aggregate([lookupStage], {collation: caseSensitive}).toArray();
- assertArrayEq({
- actual: results,
- expected: resultCaseInsensitive,
- extraErrorMsg: " Case-insensitive collation on stage, foreign is indexed, running: " +
- tojson(lookupInto)
- });
- explain = collAa.explain().aggregate([lookupStage], {collation: caseSensitive});
- assertIndexJoinStrategy(explain);
}
})();
})();
diff --git a/jstests/aggregation/sources/lookup/lookup_foreign_collation.js b/jstests/aggregation/sources/lookup/lookup_foreign_collation.js
index 6937fe42854..7d6e9a4578e 100644
--- a/jstests/aggregation/sources/lookup/lookup_foreign_collation.js
+++ b/jstests/aggregation/sources/lookup/lookup_foreign_collation.js
@@ -96,12 +96,10 @@ function setup() {
// localColl: Local Collection
// foreignColl: Foreign Collection
// commandCollation: Collation set on the aggregate command. Pass null for default collation.
- // lookupCollation: Collation specified in the $lookup stage. Pass null for default
- // collation. expectedResults: Results expected from the aggregate invocation
+ // expectedResults: Results expected from the aggregate invocation
//
- function assertExpectedResultSet(
- localColl, foreignColl, commandCollation, lookupCollation, expectedResults) {
- const lookupWithPipeline = {$lookup: {from: foreignColl.getName(),
+ function assertExpectedResultSet(localColl, foreignColl, commandCollation, expectedResults) {
+ const lookupWithPipeline = {$lookup: {from: foreignColl.getName(),
as: "foreignMatch",
let: {l_id: "$_id"},
pipeline: [{$match: {$expr: {$eq: ["$_id", "$$l_id"]}}}]}};
@@ -111,11 +109,6 @@ function setup() {
foreignField: "_id",
as: "foreignMatch"}};
- if (lookupCollation) {
- lookupWithPipeline.$lookup._internalCollation = lookupCollation;
- lookupWithLocalForeignField.$lookup._internalCollation = lookupCollation;
- }
-
const aggOptions = {};
if (commandCollation) {
aggOptions.collation = commandCollation;
@@ -129,112 +122,20 @@ function setup() {
}
// Baseline test, confirming simple binary comparison when no collation has been specified on
- // the command, $lookup stage or collections.
- assertExpectedResultSet(localColl, foreignColl, null, null, resultSetCaseSensitive);
+ // the command or the collection.
+ assertExpectedResultSet(localColl, foreignColl, null, resultSetCaseSensitive);
// When a collation has been specified on the $lookup stage, it will always be used to join
// local and foreign collections.
for (const local of [localColl, localCaseInsensitiveColl]) {
for (const foreign of [foreignColl, foreignCaseInsensitiveColl]) {
- for (const command of [null, simpleCollation, caseInsensitiveCollation]) {
- // Case insensitive collation specified in the $lookup stage results in a case
- // insensitive join.
- assertExpectedResultSet(
- local, foreign, command, caseInsensitiveCollation, resultSetCaseInsensitive);
-
- // Simple collation specified in the $lookup stage results in a case sensitive join.
- assertExpectedResultSet(
- local, foreign, command, simpleCollation, resultSetCaseSensitive);
- }
+ // Case insensitive collation results in a case insensitive join.
+ assertExpectedResultSet(
+ local, foreign, caseInsensitiveCollation, resultSetCaseInsensitive);
+
+ // Simple collation results in a case sensitive join.
+ assertExpectedResultSet(local, foreign, simpleCollation, resultSetCaseSensitive);
}
}
})();
-
-(function testNestedLookupStagesWithDifferentCollations() {
- setup();
-
- const lookupWithPipeline = {$lookup: {from: foreignColl.getName(),
- as: "foreignMatch",
- let: {l_id: "$_id"},
- pipeline: [{$match: {$expr: {$eq: ["$_id", "$$l_id"]}}},
- {$lookup: {from: localColl.getName(),
- as: "foreignMatch2",
- let: {l_id: "$_id"},
- pipeline: [{$match: {$expr: {$eq: ["$_id", "$$l_id"]}}}],
- _internalCollation: simpleCollation}}],
- _internalCollation: caseInsensitiveCollation}};
-
- const resultSet = [
- {_id: "a", foreignMatch: [{_id: "a", "foreignMatch2": [{"_id": "a"}]}]},
- {_id: "b", foreignMatch: [{_id: "B", "foreignMatch2": []}]},
- {_id: "c", foreignMatch: [{_id: "c", "foreignMatch2": [{"_id": "c"}]}]},
- {_id: "d", foreignMatch: [{_id: "D", "foreignMatch2": []}]},
- {_id: "e", foreignMatch: [{_id: "e", "foreignMatch2": [{"_id": "e"}]}]}
- ];
-
- const results = localColl.aggregate([lookupWithPipeline]).toArray();
- assert(anyEq(results, resultSet), tojson(results));
-})();
-
-(function testMatchOnUnwoundAsFieldAbsorptionOptimization() {
- setup();
-
- // A $lookup stage with a collation that differs from the collection and command collation
- // will not absorb a $match on unwound results.
- let pipeline = [{$lookup: {from: foreignColl.getName(),
- as: "foreignMatch",
- let: {l_id: "$_id"},
- pipeline: [{$match: {$expr: {$eq: ["$_id", "$$l_id"]}}}],
- _internalCollation: caseInsensitiveCollation}},
- {$unwind: "$foreignMatch"},
- {$match: {"foreignMatch._id": "b"}}];
-
- let results = localColl.aggregate(pipeline).toArray();
- assert.eq(0, results.length);
-
- let explain = localColl.explain().aggregate(pipeline);
- let lastStage = explain.stages[explain.stages.length - 1];
- assert(lastStage.hasOwnProperty("$match"), tojson(explain));
- assert.eq({$match: {"foreignMatch._id": {$eq: "b"}}},
- lastStage,
- "The $match stage should not be optimized into the $lookup stage" + tojson(explain));
-
- // A $lookup stage with a collation that matches the command collation will absorb a $match
- // stage.
- pipeline = [{$lookup: {from: foreignColl.getName(),
- as: "foreignMatch",
- let: {l_id: "$_id"},
- pipeline: [{$match: {$expr: {$eq: ["$_id", "$$l_id"]}}}],
- _internalCollation: caseInsensitiveCollation}},
- {$unwind: "$foreignMatch"},
- {$match: {"foreignMatch._id": "b"}}];
-
- let expectedResults = [{"_id": "b", "foreignMatch": {"_id": "B"}}];
-
- results = localColl.aggregate(pipeline, {collation: caseInsensitiveCollation}).toArray();
- assert(anyEq(results, expectedResults), tojson(results));
-
- explain = localColl.explain().aggregate(pipeline, {collation: caseInsensitiveCollation});
- lastStage = explain.stages[explain.stages.length - 1];
- assert(lastStage.hasOwnProperty("$lookup"), tojson(explain));
-
- // A $lookup stage with a collation that matches the local collection collation will absorb
- // a $match stage.
- pipeline = [{$lookup: {from: foreignColl.getName(),
- as: "foreignMatch",
- let: {l_id: "$_id"},
- pipeline: [{$match: {$expr: {$eq: ["$_id", "$$l_id"]}}}],
- _internalCollation: caseInsensitiveCollation}},
- {$unwind: "$foreignMatch"},
- {$match: {"foreignMatch._id": "b"}}];
-
- expectedResults = [{"_id": "b", "foreignMatch": {"_id": "B"}}];
-
- results = localCaseInsensitiveColl.aggregate(pipeline).toArray();
- assert(anyEq(results, expectedResults), tojson(results));
-
- explain = localCaseInsensitiveColl.explain().aggregate(pipeline);
- lastStage = explain.stages[explain.stages.length - 1];
- assert(lastStage.hasOwnProperty("$lookup"), tojson(explain));
-})();
})();
diff --git a/jstests/aggregation/sources/redact/root_redact.js b/jstests/aggregation/sources/redact/root_redact.js
new file mode 100644
index 00000000000..a1851e54726
--- /dev/null
+++ b/jstests/aggregation/sources/redact/root_redact.js
@@ -0,0 +1,28 @@
+// Usage of $$ROOT variable can lead to Document cache reallocation and possible memory corruption.
+// Test is checking that this is not the case.
+(function() {
+"use strict";
+
+const bigStr = 'X'.repeat(1024);
+const doc = {
+ _id: 0,
+ d: true,
+ sub: {d: false, str: bigStr},
+ str: bigStr,
+};
+
+db.test.drop();
+assert.commandWorked(db.test.insertOne(doc));
+
+const pipeline = [{
+ $redact: {
+ $cond: {
+ if: "$d",
+ then: "$$DESCEND",
+ else: {$cond: {if: {$objectToArray: "$$ROOT"}, then: "$$KEEP", else: "$$PRUNE"}}
+ }
+ }
+}];
+
+assert.eq([doc], db.test.aggregate(pipeline).toArray());
+})();
diff --git a/jstests/aggregation/sources/setWindowFields/comprehensive_parse.js b/jstests/aggregation/sources/setWindowFields/comprehensive_parse.js
index dbe509e2c59..4dd4cc90565 100644
--- a/jstests/aggregation/sources/setWindowFields/comprehensive_parse.js
+++ b/jstests/aggregation/sources/setWindowFields/comprehensive_parse.js
@@ -65,6 +65,7 @@ const windows = {
// The list of sort definitions to test.
const sortBys = {
none: null,
+ expr: {partitionSeq: {$meta: "randVal"}},
asc: {partitionSeq: 1},
desc: {partitionSeq: -1},
asc_date: {date: 1},
@@ -104,18 +105,11 @@ function constructQuery(wf, window, sortBy, partitionBy) {
}
// Given an element of each of the lists above, what is the expected
-// result. The output should be 'SKIP', 'OK' or the expected integer
+// result. The output should be 'OK' or the expected integer
// error code.
function expectedResult(wfType, windowType, sortType, partitionType) {
// Static errors all come first.
- // Skip range windows over dates or that are over descending windows.
- if (windowType.endsWith('range')) {
- if (sortType.endsWith('date') || sortType.startsWith('desc')) {
- return 'SKIP';
- }
- }
-
// Derivative and integral require an ascending sort
// and an explicit window.
if (wfType.startsWith('derivative')) {
@@ -129,6 +123,11 @@ function expectedResult(wfType, windowType, sortType, partitionType) {
return ErrorCodes.FailedToParse;
}
+ // '$derivative requires a non-expression sortBy'.
+ if (sortType == "expr") {
+ return ErrorCodes.FailedToParse;
+ }
+
} else if (wfType.startsWith('integral')) {
// Integral requires a sort.
if (sortType == 'none') {
@@ -140,6 +139,11 @@ function expectedResult(wfType, windowType, sortType, partitionType) {
return ErrorCodes.FailedToParse;
}
+ // '$integral requires a non-expression sortBy'.
+ if (sortType == "expr") {
+ return ErrorCodes.FailedToParse;
+ }
+
} else if (wfType.startsWith('expMovingAvg')) {
// $expMovingAvg doesn't accept a window.
if (windowType != 'none') {
@@ -179,9 +183,23 @@ function expectedResult(wfType, windowType, sortType, partitionType) {
}
// Range based windows require a sort over a single field.
- if (windowType.endsWith('range') && (sortType == 'none' || sortType == 'multi')) {
- // 'Range-based window require sortBy a single field'.
- return 5339902;
+ if (windowType.endsWith('range')) {
+ if (sortType == 'none' || sortType == 'multi') {
+ // 'Range-based window require sortBy a single field'.
+ return 5339902;
+ }
+ if (sortType == 'expr') {
+ // 'Range-based bounds require a non-expression sortBy'
+ return 8947400;
+ }
+ if (sortType.startsWith('desc')) {
+ // 'Range-based bounds require an ascending sortBy'.
+ return 8947401;
+ }
+ if (sortType.endsWith('date') && !partitionType.endsWith('array')) {
+ // 'For windows that involve date or time ranges, a unit must be provided.'
+ return 5429413;
+ }
}
if (partitionType === 'static_array') {
@@ -238,10 +256,6 @@ function* makeTests() {
expectedResult: expectedResult(wfType, windowType, sortType, partitionType)
};
- if (test.expectedResult == 'SKIP') {
- continue;
- }
-
yield test;
}
}
@@ -251,13 +265,16 @@ function* makeTests() {
// Run all the combinations generated in makeTests.
for (const test of makeTests()) {
+ const errorMsg = "Command was: " + tojson(test.query);
if (test.expectedResult == ErrorCodes.OK) {
assert.commandWorked(
- coll.runCommand({aggregate: coll.getName(), pipeline: [test.query], cursor: {}}));
+ coll.runCommand({aggregate: coll.getName(), pipeline: [test.query], cursor: {}}),
+ errorMsg);
} else {
assert.commandFailedWithCode(
coll.runCommand({aggregate: coll.getName(), pipeline: [test.query], cursor: {}}),
- test.expectedResult);
+ test.expectedResult,
+ errorMsg);
}
}
})();
diff --git a/jstests/aggregation/sources/setWindowFields/time.js b/jstests/aggregation/sources/setWindowFields/time.js
index e4f7d7cfa6c..7ef72c7243b 100644
--- a/jstests/aggregation/sources/setWindowFields/time.js
+++ b/jstests/aggregation/sources/setWindowFields/time.js
@@ -196,4 +196,96 @@ error = assert.throws(() => {
run([range('unbounded', 'unbounded')]);
});
assert.commandFailedWithCode(error, 5429513);
+
+// Test with small bound over large data values
+coll.drop();
+assert.commandWorked(coll.insert([
+ {_id: 0, time: new Date("2023-07-01T20:53:50.932Z"), "str": "ric"},
+ {_id: 1, time: new Date("2023-07-02T20:57:42.383Z"), "str": "alc"},
+ {_id: 2, time: new Date("2023-07-04T01:39:14.265Z"), "str": ""},
+ {_id: 3, time: new Date("2023-07-04T04:01:29.983Z"), "str": "ric"},
+ {_id: 4, time: new Date("2023-07-05T15:08:22.541Z"), "str": ""},
+ {_id: 5, time: new Date("2023-07-05T22:56:30.949Z"), "str": ""},
+]));
+
+const res = coll.aggregate([
+ {
+ $setWindowFields: {
+ partitionBy: "$str",
+ sortBy: {"any": -1},
+ output: {"num": {$sum: {$pow: [9, 20]}}}
+ }
+ },
+ {
+ $setWindowFields: {
+ sortBy: {"num": 1},
+ output: {"res": {$max: "$num", window: {range: [-4, "current"]}}}
+ }
+ },
+ {$project: {res: 1, _id: 0}},
+ ])
+ .toArray();
+
+assert.sameMembers(res, [
+ {"res": 12157665459056929000},
+ {"res": 24315330918113858000},
+ {"res": 24315330918113858000},
+ {"res": 36472996377170790000},
+ {"res": 36472996377170790000},
+ {"res": 36472996377170790000}
+]);
+
+// Test with large bound over large data values
+const res2 =
+ coll.aggregate([
+ {
+ $setWindowFields: {
+ partitionBy: "$str",
+ sortBy: {"any": -1},
+ output: {"num": {$sum: {$pow: [8, 20]}}}
+ }
+ },
+ {
+ $setWindowFields: {
+ sortBy: {"num": 1},
+ output:
+ {"res": {$max: "$num", window: {range: [-{$pow: [9, 20]}, "current"]}}}
+ }
+ },
+ {$project: {res: 1, _id: 0}},
+ ])
+ .toArray();
+
+assert.sameMembers(res2, [
+ {"res": 1152921504606847000},
+ {"res": 2305843009213694000},
+ {"res": 2305843009213694000},
+ {"res": 3458764513820541000},
+ {"res": 3458764513820541000},
+ {"res": 3458764513820541000}
+]);
+
+// Test with large bound over small data values
+const res3 =
+ coll.aggregate([
+ {
+ $setWindowFields: {
+ partitionBy: "$str",
+ sortBy: {"any": -1},
+ output: {"num": {$sum: {$pow: [2, 2]}}}
+ }
+ },
+ {
+ $setWindowFields: {
+ sortBy: {"num": 1},
+ output:
+ {"res": {$max: "$num", window: {range: [-{$pow: [9, 20]}, "current"]}}}
+ }
+ },
+ {$project: {res: 1, _id: 0}},
+ ])
+ .toArray();
+
+assert.sameMembers(res3,
+ [{"res": 4}, {"res": 8}, {"res": 8}, {"res": 12}, {"res": 12}, {"res": 12}]);
})();
diff --git a/jstests/aggregation/sources/unionWith/unionWith_explain.js b/jstests/aggregation/sources/unionWith/unionWith_explain.js
index 60d6a7ae4a4..a600b7fbe0f 100644
--- a/jstests/aggregation/sources/unionWith/unionWith_explain.js
+++ b/jstests/aggregation/sources/unionWith/unionWith_explain.js
@@ -105,8 +105,18 @@ function assertExplainEq(union, regular) {
executionStatsIngoredFields),
buildErrorString(unionStats, regularStats, "executionStages"));
} else if ("stages" in regular) {
- assert(arrayEqWithIgnoredFields(union, regular.stages, stagesIgnoredFields),
- buildErrorString(union, regular, "stages"));
+ // For explains run with the runCommand({explain: ...}) format.
+ if (regular.stages.length > 1 && "$cursor" in regular.stages[0] &&
+ "executionStats" in regular.stages[0]["$cursor"]) {
+ assert(
+ arrayEqWithIgnoredFields(union,
+ regular.stages,
+ [...stagesIgnoredFields, ...executionStatsIngoredFields]),
+ buildErrorString(union, regular, "stages with executionStats"));
+ } else {
+ assert(arrayEqWithIgnoredFields(union, regular.stages, stagesIgnoredFields),
+ buildErrorString(union, regular, "stages"));
+ }
} else if ("queryPlanner" in regular) {
assert.eq(union.length, 1, "Expected single union stage");
const unionCursor = union[0].$cursor;
@@ -123,7 +133,7 @@ function assertExplainEq(union, regular) {
function assertExplainMatch(unionExplain, regularExplain) {
const unionStage = getUnionWithStage(unionExplain);
- assert(unionStage);
+ assert(unionStage, unionExplain);
const unionSubExplain = unionStage.$unionWith.pipeline;
assertExplainEq(unionSubExplain, regularExplain);
}
@@ -133,6 +143,20 @@ function testPipeline(pipeline) {
{explain: true});
let queryResult = collB.aggregate(pipeline, {explain: true});
assertExplainMatch(unionResult, queryResult);
+
+ // Alternative explain invocation. This is a regression test for SERVER-89344.
+ if (!FixtureHelpers.isMongos(db)) {
+ unionResult = db.runCommand({
+ explain: {
+ "aggregate": collA.getName(),
+ "pipeline": [{$unionWith: {coll: collB.getName(), pipeline: pipeline}}],
+ "cursor": {}
+ }
+ });
+ queryResult = db.runCommand(
+ {explain: {"aggregate": collB.getName(), "pipeline": pipeline, "cursor": {}}});
+ assertExplainMatch(unionResult, queryResult);
+ }
}
testPipeline([{$addFields: {bump: true}}]);
diff --git a/jstests/aggregation/unwind.js b/jstests/aggregation/unwind.js
index ffd2a3da9c6..cf01560cc0c 100644
--- a/jstests/aggregation/unwind.js
+++ b/jstests/aggregation/unwind.js
@@ -15,3 +15,56 @@ assert.eq(4, res.length);
assert.eq([1, 2, 3, 4], res.map(function(z) {
return z.x;
}));
+
+// Test unwinding an empty path
+coll = db.agg_unwind_empty_path;
+coll.drop();
+coll.insert({_id: 1});
+coll.insert({_id: 2, "": [1, 2]});
+coll.insert({_id: 3, "": {"": [3, 4, 5]}});
+
+assert.throwsWithCode(() => coll.aggregate([{$unwind: {path: "$"}}]).toArray(), 40352);
+assert.throwsWithCode(() => coll.aggregate([{$unwind: {path: "$."}}]).toArray(), 40353);
+
+// Test includeArrayIndex
+coll = db.agg_unwind_with_index;
+coll.drop();
+coll.insert({_id: 1});
+coll.insert({_id: 2, array: [1, 2]});
+coll.insert({_id: 3, obj: {array: [3, 4, 5]}});
+coll.insert({_id: 4, obj: {subObj: {array: [6, 7, 8, 9]}}});
+
+assert.eq(
+ coll.aggregate([{$unwind: {path: "$array", includeArrayIndex: "idx"}}]).toArray(),
+ [{"_id": 2, "array": 1, "idx": NumberLong(0)}, {"_id": 2, "array": 2, "idx": NumberLong(1)}]);
+
+assert.eq(coll.aggregate([{$unwind: {path: "$array", includeArrayIndex: "array"}}]).toArray(),
+ [{"_id": 2, "array": NumberLong(0)}, {"_id": 2, "array": NumberLong(1)}]);
+
+assert.eq(coll.aggregate([{$unwind: {path: "$obj.array", includeArrayIndex: "idx"}}]).toArray(), [
+ {"_id": 3, "obj": {"array": 3}, "idx": NumberLong(0)},
+ {"_id": 3, "obj": {"array": 4}, "idx": NumberLong(1)},
+ {"_id": 3, "obj": {"array": 5}, "idx": NumberLong(2)}
+]);
+
+assert.eq(coll.aggregate([{$unwind: {path: "$obj.array", includeArrayIndex: "obj"}}]).toArray(), [
+ {"_id": 3, "obj": NumberLong(0)},
+ {"_id": 3, "obj": NumberLong(1)},
+ {"_id": 3, "obj": NumberLong(2)}
+]);
+
+assert.eq(
+ coll.aggregate([{$unwind: {path: "$obj.array", includeArrayIndex: "obj.array"}}]).toArray(), [
+ {"_id": 3, "obj": {"array": NumberLong(0)}},
+ {"_id": 3, "obj": {"array": NumberLong(1)}},
+ {"_id": 3, "obj": {"array": NumberLong(2)}}
+ ]);
+
+assert.eq(coll.aggregate([{$unwind: {path: "$obj.subObj.array", includeArrayIndex: "obj.subObj"}}])
+ .toArray(),
+ [
+ {"_id": 4, "obj": {"subObj": NumberLong(0)}},
+ {"_id": 4, "obj": {"subObj": NumberLong(1)}},
+ {"_id": 4, "obj": {"subObj": NumberLong(2)}},
+ {"_id": 4, "obj": {"subObj": NumberLong(3)}}
+ ]);
diff --git a/jstests/aggregation/unwind_sort.js b/jstests/aggregation/unwind_sort.js
new file mode 100644
index 00000000000..858320bec0d
--- /dev/null
+++ b/jstests/aggregation/unwind_sort.js
@@ -0,0 +1,27 @@
+// Test that we can sort on fields, produces by unwind
+
+const coll = db.agg_unwind_sort;
+coll.drop();
+assert.commandWorked(coll.insertOne({a: [3, 4, 5]}));
+assert.commandWorked(coll.insertOne({a: [1, 2]}));
+
+let result = coll.aggregate([{$unwind: "$a"}, {$sort: {a: 1}}]).toArray();
+assert.eq([1, 2, 3, 4, 5], result.map(function(z) {
+ return z.a;
+}));
+result = coll.aggregate([{$unwind: "$a"}, {$sort: {a: -1}}]).toArray();
+assert.eq([5, 4, 3, 2, 1], result.map(function(z) {
+ return z.a;
+}));
+result =
+ coll.aggregate([{$unwind: {path: "$a", includeArrayIndex: "i"}}, {$sort: {i: 1}}]).toArray();
+assert.eq([NumberLong(0), NumberLong(0), NumberLong(1), NumberLong(1), NumberLong(2)],
+ result.map(function(z) {
+ return z.i;
+ }));
+result =
+ coll.aggregate([{$unwind: {path: "$a", includeArrayIndex: "i"}}, {$sort: {i: -1}}]).toArray();
+assert.eq([NumberLong(2), NumberLong(1), NumberLong(1), NumberLong(0), NumberLong(0)],
+ result.map(function(z) {
+ return z.i;
+ }));
diff --git a/jstests/audit/log_query_stats.js b/jstests/audit/log_query_stats.js
new file mode 100644
index 00000000000..f52d0219b59
--- /dev/null
+++ b/jstests/audit/log_query_stats.js
@@ -0,0 +1,109 @@
+// Verify usage of $queryStats agg stage can be sent to audit log.
+// @tags: [requires_fcv_60]
+
+(function() {
+'use strict';
+
+load('src/mongo/db/modules/enterprise/jstests/audit/lib/audit.js');
+
+const runTest = function(audit, db, admin) {
+ assert.commandWorked(
+ admin.runCommand({createUser: "user1", pwd: "pwd", roles: [{role: "root", db: "admin"}]}));
+ audit.fastForward();
+
+ // Authentication does not match the audit filter.
+ assert(admin.auth({user: "user1", pwd: "pwd"}));
+ audit.assertNoNewEntries();
+
+ audit.fastForward();
+
+ // "$queryStats" command with no transform identifiers matches the audit filter.
+ assert.commandWorked(
+ db.adminCommand({aggregate: 1, pipeline: [{$queryStats: {}}], cursor: {}}));
+ audit.assertCmd("authCheck", {
+ command: "aggregate",
+ ns: "admin.$cmd.aggregate",
+ args: {
+ aggregate: 1,
+ pipeline: [{$queryStats: {}}],
+ cursor: {},
+ lsid: db.getSession().getSessionId(),
+ $db: "admin",
+ }
+ });
+
+ audit.fastForward();
+
+ // "$queryStats" with both transform identifiers matches the audit filter.
+ const hmacKey = "MjM0NTY3ODkxMDExMTIxMzE0MTUxNjE3MTgxOTIwMjE=";
+ assert.commandWorked(db.adminCommand({
+ aggregate: 1,
+ pipeline: [{
+ $queryStats:
+ {transformIdentifiers: {algorithm: "hmac-sha-256", hmacKey: BinData(8, hmacKey)}}
+ }],
+ cursor: {}
+ }));
+
+ // Query stats adds extra timestamping fields that we don't want to bother with.
+ audit.assertEntryRelaxed("authCheck", {
+ command: "aggregate",
+ ns: "admin.$cmd.aggregate",
+ args: {
+ aggregate: 1,
+ pipeline: [{
+ $queryStats: {
+ transformIdentifiers: {
+ algorithm: "hmac-sha-256",
+ // HMAC key is Sensitive, so it should always be redacted.
+ hmacKey: "###"
+ }
+ }
+ }],
+ cursor: {},
+ lsid: db.getSession().getSessionId(),
+ $db: "admin"
+ }
+ });
+
+ // Collection drop does not match the audit filter, so no entry is produced.
+ db.coll.drop();
+ audit.assertNoNewEntries();
+ admin.logout();
+};
+
+const auditFilterStr = "{'param.args.pipeline.0.$queryStats':{$exists:true}}";
+const parameters = {
+ auditAuthorizationSuccess: true,
+ internalQueryStatsRateLimit: -1
+};
+
+{
+ const m = MongoRunner.runMongodAuditLogger(
+ {auth: "", auditFilter: auditFilterStr, setParameter: parameters});
+ const audit = m.auditSpooler();
+ const db = m.getDB("test");
+ const admin = m.getDB("admin");
+
+ audit.assertCmd = audit.assertEntry;
+ runTest(audit, db, admin);
+ MongoRunner.stopMongod(m);
+}
+
+{
+ const st = MongoRunner.runShardedClusterAuditLogger({}, {
+ auth: null,
+ auditFilter: auditFilterStr,
+ setParameter: parameters,
+ });
+ const auditMongos = st.s0.auditSpooler();
+ const db = st.s0.getDB("test");
+ const admin = st.s0.getDB("admin");
+
+ // On clusters, clusterTime shows up in the param field. We don't want to worry about that
+ // so we run assertEntryRelaxed instead.
+ auditMongos.assertCmd = auditMongos.assertEntryRelaxed;
+ runTest(auditMongos, db, admin);
+ st.stop();
+}
+})();
diff --git a/jstests/auth/authz_cache_on_system_modification.js b/jstests/auth/authz_cache_on_system_modification.js
index 23473cd0d01..65c49951853 100644
--- a/jstests/auth/authz_cache_on_system_modification.js
+++ b/jstests/auth/authz_cache_on_system_modification.js
@@ -7,7 +7,6 @@
const conn = MongoRunner.runMongod({auth: ''});
let db = conn.getDB('admin');
-const authzErrorCode = 13;
// creates a root user
assert.commandWorked(db.runCommand({createUser: 'root', pwd: 'pwd', roles: ['__system']}),
@@ -46,23 +45,32 @@ db.logout();
assert(db.auth('custom', 'pwd'));
assert.commandFailedWithCode(
db.runCommand({insert: "admin.test", documents: [{woo: "mar"}]}),
- authzErrorCode,
+ ErrorCodes.Unauthorized,
"Privileges retained after modification to system.roles collections");
db.logout();
})();
-// tests that a user does not retain their privileges after the system.users colleciton is modified
+// tests that a user cannot rename the system.users collection.
(function testModifySystemUsersCollection() {
- jsTestLog("Testing authz cache invalidation on system.users collection modification");
+ jsTestLog("Testing that a user cannot rename the system.users collection");
assert(db.auth('root', 'pwd'));
- assert.commandWorked(db.createCollection("scratch", {}),
- "Collection not created with root user");
- assert.commandWorked(db.runCommand({renameCollection: 'admin.system.users', to: 'admin.foo'}),
- "System collection could not be renamed with root user");
+
+ assert.commandFailedWithCode(
+ db.runCommand({renameCollection: 'admin.system.users', to: 'foo.system.users'}),
+ ErrorCodes.IllegalOperation,
+ "Renaming the system.users collection should not be allowed");
+ assert.commandFailedWithCode(
+ db.runCommand({renameCollection: 'foo.system.users', to: 'admin.system.users'}),
+ ErrorCodes.IllegalOperation,
+ "Renaming the system.users collection should not be allowed");
+ assert.commandFailedWithCode(
+ db.runCommand({renameCollection: 'admin.system.users', to: 'admin.system.foo'}),
+ ErrorCodes.IllegalOperation,
+ "Renaming the system.users collection should not be allowed");
assert.commandFailedWithCode(
- db.runCommand({renameCollection: 'admin.scratch', to: 'admin.system.users'}),
- authzErrorCode,
- "User cache not invalidated after modification to system collection");
+ db.runCommand({renameCollection: 'admin.system.foo', to: 'admin.system.users'}),
+ ErrorCodes.IllegalOperation,
+ "Renaming the system.users collection should not be allowed");
db.logout();
})();
diff --git a/jstests/auth/lsid_auth_checks.js b/jstests/auth/lsid_auth_checks.js
new file mode 100644
index 00000000000..39064931224
--- /dev/null
+++ b/jstests/auth/lsid_auth_checks.js
@@ -0,0 +1,133 @@
+/**
+ * Test that a sharded explain command with a value set for the lsid's uid field in the inner
+ * command invocation will ignore the lsid field and succeed so long as the user is authorized to
+ * run the command being explained. Also tests that a user can only set a lsid + uid in the the
+ * top-level explain command if they are authorized to do so.
+ *
+ * @tags: [requires_sharding]
+ */
+
+const st = new ShardingTest({keyFile: "jstests/libs/key1", shards: {rs0: {nodes: 2}}});
+const mongosConn = st.s;
+
+// Setup: create user roles.
+const adminDB = mongosConn.getDB("admin");
+adminDB.createUser({user: "admin", pwd: "admin", roles: ["root"]});
+adminDB.auth("admin", "admin");
+
+const testDB = mongosConn.getDB("test");
+testDB.test.insert({a: 1});
+
+testDB.createUser({user: "readOnlyUser", pwd: "user", roles: jsTest.readOnlyUserRoles});
+testDB.createUser({user: "readWriteUser", pwd: "user", roles: jsTest.basicUserRoles});
+adminDB.createRole({
+ role: "impersonateRole",
+ roles: [],
+ privileges: [
+ {resource: {db: "test", collection: "test"}, actions: ["find", "update"]},
+ {resource: {cluster: true}, actions: ["impersonate"]}
+ ]
+});
+adminDB.createUser({user: "impersonateUser", pwd: "user", roles: ["impersonateRole"]});
+adminDB.logout();
+
+// LSID helper functions.
+const cmdLsid = UUID();
+const invalidUid = computeSHA256Block("abc");
+const getUserUid = function() {
+ const user = adminDB.runCommand({connectionStatus: 1}).authInfo.authenticatedUsers[0];
+ return user ? computeSHA256Block(user.user + "@" + user.db) : computeSHA256Block("");
+};
+
+const createLsidObj = (uid) => ({lsid: {id: cmdLsid, uid}});
+const commandWithLsid = (cmd, lsidObj, isOuter = false) => {
+ return isOuter ? Object.assign({explain: cmd}, lsidObj)
+ : {explain: Object.assign({}, cmd, lsidObj)};
+};
+
+// Explain command helper and runners.
+const assertExplain = (cmd, uid, shouldFail = false, isOuter = false) => {
+ const lsidObj = createLsidObj(uid);
+ const command = commandWithLsid(cmd, lsidObj, isOuter);
+
+ if (shouldFail) {
+ assert.commandFailedWithCode(testDB.runCommand(command), ErrorCodes.Unauthorized);
+ } else {
+ assert.commandWorked(testDB.runCommand(command));
+ }
+};
+
+const assertInnerLsidExplainIsUnauthorized = (cmd, uid) => assertExplain(cmd, uid, true);
+const assertInnerLsidExplainWorked = (cmd, uid) => assertExplain(cmd, uid, false);
+const assertTopLevelLsidExplainIsUnauthorized = (cmd, uid) => assertExplain(cmd, uid, true, true);
+const assertTopLevelLsidExplainWorked = (cmd, uid) => assertExplain(cmd, uid, false, true);
+
+const runCommandWithLsidTest =
+ (isAuthZforInnerCmd, canSetTopLevelLsid, cmd, invalidUid, userUid) => {
+ // A user can put any arbitrary lsid/generic argument in the inner command invocation, as
+ // this will be pruned when the command is wrapped into an explain command. The explain will
+ // succeed so long as the user is authorized to run the command being explained. A user can
+ // only specify an lsid in the top-level explain command if they are authorized to do so, or
+ // if the uid in the lsid is the same as the user digest in the opCtx. The explain command
+ // will succeed if the user is authorized to run the command being explained.
+ if (isAuthZforInnerCmd) {
+ assertInnerLsidExplainWorked(cmd, invalidUid);
+ assertInnerLsidExplainWorked(cmd, userUid);
+ assertTopLevelLsidExplainWorked(cmd, userUid);
+ } else {
+ assertInnerLsidExplainIsUnauthorized(cmd, invalidUid);
+ assertInnerLsidExplainIsUnauthorized(cmd, userUid);
+ assertTopLevelLsidExplainIsUnauthorized(cmd, userUid);
+ }
+
+ if (canSetTopLevelLsid) {
+ assertTopLevelLsidExplainWorked(cmd, invalidUid);
+ } else {
+ assertTopLevelLsidExplainIsUnauthorized(cmd, invalidUid);
+ }
+ };
+
+// Commands to run explain on.
+const commands = [
+ {cmd: {distinct: "test", key: "_id"}, isWrite: false},
+ {cmd: {count: "test"}, isWrite: false},
+ {cmd: {find: "test", filter: {a: 1}}, isWrite: false},
+ {
+ cmd: {findAndModify: "test", query: {a: 1}, update: {$set: {b: 2}}, "new": true},
+ isWrite: true
+ },
+ {cmd: {update: "test", updates: [{q: {a: 1}, u: {c: "foo"}}]}, isWrite: true}
+];
+
+// A user is only authorized to run an explain on a command if they:
+// 1. Are authorized to run the command being explained on the associated resource.
+// 2. Are authorized to set any generic arguments attached to the top-level invocation of the
+// explain. In particular, a user can only set a different value in the uid field of an lsid if they
+// have the "impersonate" role. If a user specifies the same uid value as their user digest, the
+// command will succeed if (1) is true.
+const users = [
+ {user: "readOnlyUser", pwd: "user", authDB: testDB, canWrite: false, canSetTopLevelLsid: false},
+ {user: "readWriteUser", pwd: "user", authDB: testDB, canWrite: true, canSetTopLevelLsid: false},
+ {
+ user: "impersonateUser",
+ pwd: "user",
+ authDB: adminDB,
+ canWrite: true,
+ canSetTopLevelLsid: true
+ },
+ {user: "admin", pwd: "admin", authDB: adminDB, canWrite: true, canSetTopLevelLsid: false},
+];
+
+users.forEach(({user, pwd, authDB, canWrite, canSetTopLevelLsid}) => {
+ authDB.auth(user, pwd);
+ const userUid = getUserUid();
+
+ commands.forEach(({cmd, isWrite}) => {
+ const isAuthZforInnerCmd = canWrite || !isWrite;
+ runCommandWithLsidTest(isAuthZforInnerCmd, canSetTopLevelLsid, cmd, invalidUid, userUid);
+ });
+
+ authDB.logout();
+});
+
+st.stop();
diff --git a/jstests/auth/renameRestrictedCollections.js b/jstests/auth/renameRestrictedCollections.js
index 4d487d38d08..d54a0aec3eb 100644
--- a/jstests/auth/renameRestrictedCollections.js
+++ b/jstests/auth/renameRestrictedCollections.js
@@ -109,9 +109,10 @@ adminDB.logout();
// Test renaming system.users collection with __system
assert(adminDB.auth('rootier', 'password'));
-jsTestLog("Test that with __system you CAN rename to/from system.users");
+jsTestLog("Test that with __system you CANNOT rename to/from system.users");
res = adminDB.system.users.renameCollection("users", true);
-assert.eq(1, res.ok, tojson(res));
+assert.eq(0, res.ok, tojson(res));
+assert.eq(ErrorCodes.IllegalOperation, res.code);
// At this point, all the user documents are gone, so further activity may be unauthorized,
// depending on cluster configuration. So, this is the end of the test.
diff --git a/jstests/auth/rename_encrypted_collection.js b/jstests/auth/rename_encrypted_collection.js
index 76b01f9e62d..17f0326320f 100644
--- a/jstests/auth/rename_encrypted_collection.js
+++ b/jstests/auth/rename_encrypted_collection.js
@@ -1,10 +1,6 @@
/**
* Verify renaming to/from a collection with encrypted fields is disallowed depending on the users
* privileges
- *
- * @tags: [
- * requires_fcv_61,
- * ]
*/
load("jstests/fle2/libs/encrypted_client_util.js");
diff --git a/jstests/auth/speculative-auth-replset.js b/jstests/auth/speculative-auth-replset.js
index c0b8ef6c19a..fa6eabc61b1 100644
--- a/jstests/auth/speculative-auth-replset.js
+++ b/jstests/auth/speculative-auth-replset.js
@@ -27,8 +27,9 @@ function countAuthInLog(conn) {
}
} else if (entry.id === kAuthenticationFailedLogId) {
// Authentication can fail legitimately because the secondary abandons the connection
- // during shutdown.
- assert.eq(entry.attr.error.code, ErrorCodes.AuthenticationAbandoned);
+ // during shutdown - if we do encounter an authentication failure in the log, make sure
+ // that it is only of this type, fail anything else
+ assert.eq(entry.attr.result, ErrorCodes.AuthenticationAbandoned);
} else {
// Irrelevant.
return;
diff --git a/jstests/change_streams/oplog_rewrite/change_stream_basic_match_pushdown_rewrite.js b/jstests/change_streams/oplog_rewrite/change_stream_basic_match_pushdown_rewrite.js
index ec45e81871a..bd500d8c0fc 100644
--- a/jstests/change_streams/oplog_rewrite/change_stream_basic_match_pushdown_rewrite.js
+++ b/jstests/change_streams/oplog_rewrite/change_stream_basic_match_pushdown_rewrite.js
@@ -183,5 +183,40 @@ assert.eq(stringValues.slice(0, 2), ["Value", "vAlue"]);
// transaction, they effectively occur at exactly the same time.
assert.sameMembers(stringValues.slice(2, 4), ["vaLue", "valUe"]);
+const verifyOnChangeStream = (matchExpression, hasEntriesReturned) => {
+ const string = JSON.stringify(matchExpression);
+ const changeStream = coll.aggregate([{$changeStream: {}}, {$match: matchExpression}]);
+ assert.commandWorked(coll.insert({string}));
+ if (hasEntriesReturned) {
+ assert.soon(() => changeStream.hasNext());
+ const event = changeStream.next();
+ assert.eq(event.fullDocument.string, string, event);
+ } else {
+ assert(!changeStream.hasNext());
+ }
+ changeStream.close();
+};
+
+// Run a change stream with empty field path match expression to match null. Expect to return all
+// the oplog entries as the field "" is not set in oplogs.
+{
+ verifyOnChangeStream({"": null}, true);
+ verifyOnChangeStream({$or: [{"": null}]}, true);
+ verifyOnChangeStream({"": {$eq: null}}, true);
+ verifyOnChangeStream({"": {$in: [null]}}, true);
+ verifyOnChangeStream({"": {$nin: [0, "Non-Existing Value", 100, -1.23, true, false]}}, true);
+}
+
+// Run a change stream with empty field path match expression to match non-existing value(s).
+// Expect no oplog entries to be returned.
+{
+ verifyOnChangeStream({"": {$gte: 0}}, false);
+ verifyOnChangeStream({"": {$lte: 0}}, false);
+ verifyOnChangeStream({"": {$ne: null}}, false);
+ verifyOnChangeStream({"": "Non-Existing Value"}, false);
+ verifyOnChangeStream({"": {$in: [0, "", 100, -1.23, true, false]}}, false);
+ verifyOnChangeStream({"": {$nin: [null]}}, false);
+}
+
st.stop();
})();
diff --git a/jstests/change_streams/report_post_batch_resume_token.js b/jstests/change_streams/report_post_batch_resume_token.js
index 37f5f6cea3f..7d04b8e3ab5 100644
--- a/jstests/change_streams/report_post_batch_resume_token.js
+++ b/jstests/change_streams/report_post_batch_resume_token.js
@@ -224,4 +224,15 @@ assert.gt(bsonWoCompare(txnEvent3._id, previousGetMorePBRT), 0);
// appear in the batch. Confirm that the postBatchResumeToken has been set correctly.
getMorePBRT = csCursor.getResumeToken();
assert.gte(bsonWoCompare(getMorePBRT, txnEvent3._id), 0);
+
+// Test that a batch does not exceed the limit (and throw BSONObjectTooLarge) with a large
+// post-batch resume token.
+csCursor = testCollection.watch();
+const kSecondDocSize = 80 * 1024;
+// Here, 4.5 is some "unlucky" (non-unique) weight to provoke an error.
+const kFirstDocSize = (16 * 1024 * 1024) - (4.5 * kSecondDocSize);
+testCollection.insertMany([{a: "x".repeat(kFirstDocSize)}, {_id: "x".repeat(kSecondDocSize)}]);
+assert.doesNotThrow(() => {
+ csCursor.hasNext();
+}, [], "Unexpected exception on 'csCursor.hasNext()'.");
})();
diff --git a/jstests/change_streams/reshard_collection_event.js b/jstests/change_streams/reshard_collection_event.js
index d9dee39a182..52eada2b051 100644
--- a/jstests/change_streams/reshard_collection_event.js
+++ b/jstests/change_streams/reshard_collection_event.js
@@ -2,7 +2,6 @@
* Test that change streams returns reshardCollection events.
*
* @tags: [
- * requires_fcv_61,
* requires_sharding,
* uses_change_streams,
* change_stream_does_not_expect_txns,
diff --git a/jstests/change_streams/split_large_event.js b/jstests/change_streams/split_large_event.js
index a1c85564967..fc324d23b5a 100644
--- a/jstests/change_streams/split_large_event.js
+++ b/jstests/change_streams/split_large_event.js
@@ -287,4 +287,40 @@ for (const postImageMode of ["required", "updateLookup"]) {
() => testColl.watch([], {resumeAfter: resumeTokens[resumeTokens.length - 2]}),
ErrorCodes.ChangeStreamFatalError);
}
+
+{
+ // Get a resume token from a real event as opposed to a post-batch resume token.
+ const csCursor1 = testColl.watch([]);
+ assert.commandWorked(testColl.insertOne({_id: "ccc", a: 42, b: [42]}));
+ assert.soon(() => csCursor1.hasNext());
+ const eventResumeToken = csCursor1.next()._id;
+ csCursor1.close();
+
+ const expectedFullDocument = {_id: "ddd", a: 42, b: [42]};
+ assert.commandWorked(testColl.insertOne(expectedFullDocument));
+
+ // The following expressions will block its $match stage from moving ahead of other stages,
+ // unless those are the internal change stream stages allowed in the router (mongoS) pipeline.
+ // TODO SERVER-55492 Update these comments depending on the implementation progress.
+ const nonRenameableExpressions = [
+ // Array path match expressions are non-renameable.
+ {"fullDocument.b": {$size: 1}},
+ // Expressions of 'other' category, like $jsonSchema with nested properties, are
+ // non-renameable.
+ {$jsonSchema: {properties: {fullDocument: {properties: {a: {type: "number"}}}}}}
+ ];
+
+ // Test that $changeStreamSplitLargeEvent works correctly in the presence of a $match stage that
+ // cannot be pushed down (moved ahead of other stages).
+ for (const expr of nonRenameableExpressions) {
+ const csCursor2 = testColl.watch([{$match: expr}, {$changeStreamSplitLargeEvent: {}}],
+ {resumeAfter: eventResumeToken});
+
+ // Assert the change stream pipeline works and can produce events.
+ assert.soon(() => csCursor2.hasNext());
+ assert.docEq(expectedFullDocument, csCursor2.next().fullDocument);
+
+ csCursor2.close();
+ }
+}
}());
diff --git a/jstests/concurrency/fsm_libs/fsm.js b/jstests/concurrency/fsm_libs/fsm.js
index 29e4f5737eb..f252d70fd7a 100644
--- a/jstests/concurrency/fsm_libs/fsm.js
+++ b/jstests/concurrency/fsm_libs/fsm.js
@@ -132,7 +132,10 @@ var fsm = (function() {
fn.call(args.data, args.db, args.collName, connCache);
}
- var nextState = getWeightedRandomChoice(args.transitions[currentState], Random.rand());
+ assert(args.transitions.hasOwnProperty(currentState),
+ `No transitions defined for state: ${currentState}`);
+ const nextState =
+ getWeightedRandomChoice(args.transitions[currentState], Random.rand());
currentState = nextState;
}
diff --git a/jstests/concurrency/fsm_workload_helpers/set_parameter.js b/jstests/concurrency/fsm_workload_helpers/set_parameter.js
new file mode 100644
index 00000000000..f2422cedb9c
--- /dev/null
+++ b/jstests/concurrency/fsm_workload_helpers/set_parameter.js
@@ -0,0 +1,33 @@
+/**
+ * Changes the setParameter on each mongod and on each mongos (if any) for the given cluster.
+ *
+ * @returns the original value for the given parameter (which can be useful to reset the value after
+ * your workload is finshed).
+ *
+ * @param {Cluster} cluster - The FSM workload cluster - given in setup and teardown.
+ * @param {String} paramName - The name of the setParameter to change.
+ * @param {any} newValue - The new value to configure for the parameter.
+ * @param {Boolean} assertAllSettingsWereIdentical - whether to enforce that the settings were in
+ * sync across all nodes before this change is applied. All settings will be in sync after
+ * changes are applied.
+ */
+function setParameterOnAllNodes({cluster, paramName, newValue, assertAllSettingsWereIdentical}) {
+ let returnValue = null;
+ let lastSeenHost = null;
+ const setQueryStatsParams = (db) => {
+ const res = db.adminCommand({setParameter: 1, [paramName]: newValue});
+ assert.commandWorked(res);
+
+ if (returnValue != null && assertAllSettingsWereIdentical) {
+ assert.eq(
+ returnValue,
+ res.was,
+ `Expected all hosts to start with the same value for the parameter. Latest is: ${
+ db.getMongo().toString()}, last seen is: ${lastSeenHost}`);
+ }
+ returnValue = res.was;
+ };
+ cluster.executeOnMongodNodes(setQueryStatsParams);
+ cluster.executeOnMongosNodes(setQueryStatsParams);
+ return returnValue;
+}
diff --git a/jstests/concurrency/fsm_workloads/agg_out.js b/jstests/concurrency/fsm_workloads/agg_out.js
index d320676a167..86ebca8801a 100644
--- a/jstests/concurrency/fsm_workloads/agg_out.js
+++ b/jstests/concurrency/fsm_workloads/agg_out.js
@@ -37,11 +37,10 @@ var $config = extendWorkload($config, function($config, $super) {
$config.transitions = {
query: {
- query: 0.63,
+ query: 0.68,
createIndexes: 0.1,
dropIndex: 0.1,
collMod: 0.1,
- movePrimary: 0.05,
// Converting the target collection to a capped collection or a sharded collection will
// cause all subsequent aggregations to fail, so give these a low probability to make
// sure they don't happen too early in the test.
@@ -49,7 +48,6 @@ var $config = extendWorkload($config, function($config, $super) {
shardCollection: 0.01,
},
createIndexes: {query: 1},
- movePrimary: {query: 1},
dropIndex: {query: 1},
collMod: {query: 1},
convertToCapped: {query: 1},
@@ -60,7 +58,6 @@ var $config = extendWorkload($config, function($config, $super) {
* Runs an aggregate with a $out into '$config.data.outputCollName'.
*/
$config.states.query = function query(db, collName) {
- jsTestLog(`Running query: coll=${collName} out=${this.outputCollName}`);
const res = db[collName].runCommand({
aggregate: collName,
pipeline: [{$match: {flag: true}}, {$out: this.outputCollName}],
@@ -68,27 +65,15 @@ var $config = extendWorkload($config, function($config, $super) {
});
const allowedErrorCodes = [
- // Indexes of target collection changed during processing.
- ErrorCodes.CommandFailed,
- // $out is not supported to an existing *sharded* output collection.
- ErrorCodes.IllegalOperation,
- // Namespace is capped so it can't be used for $out.
- 17152,
- // $out collection cannot be sharded.
- 28769,
- // $out can't be executed while there is a move primary in progress.
- ErrorCodes.MovePrimaryInProgress,
- // (SERVER-78850) Move primary coordinator drops donor collections when it is done.
- // This invalidates non - snapshot cursors, which causes $out to fail.
- // Locally it fails with explicit collection dropped error. When doing remote reads,
- // it fails with cursor not found error.
- ErrorCodes.CursorNotFound,
+ ErrorCodes.CommandFailed, // indexes of target collection changed during processing.
+ ErrorCodes.IllegalOperation, // $out is not supported to an existing *sharded* output
+ // collection.
+ 17152, // namespace is capped so it can't be used for $out.
+ 28769, // $out collection cannot be sharded.
];
assertWhenOwnDB.commandWorkedOrFailedWithCode(res, allowedErrorCodes);
if (res.ok) {
- // No matter how many documents were in the original input stream, $out should never
- // return any results.
const cursor = new DBCommandCursor(db, res);
assertAlways.eq(0, cursor.itcount()); // No matter how many documents were in the
// original input stream, $out should never
@@ -102,10 +87,7 @@ var $config = extendWorkload($config, function($config, $super) {
*/
$config.states.createIndexes = function createIndexes(db, unusedCollName) {
for (var i = 0; i < this.indexSpecs; ++i) {
- const indexSpecs = this.indexSpecs[i];
- jsTestLog(`Running createIndex: coll=${this.outputCollName} indexSpec=${indexSpecs}`);
- assertWhenOwnDB.commandWorkedOrFailedWithCode(
- db[this.outputCollName].createIndex(indexSpecs), ErrorCodes.MovePrimaryInProgress);
+ assertWhenOwnDB.commandWorked(db[this.outputCollName].createIndex(this.indexSpecs[i]));
}
};
@@ -114,7 +96,6 @@ var $config = extendWorkload($config, function($config, $super) {
*/
$config.states.dropIndex = function dropIndex(db, unusedCollName) {
const indexSpec = this.indexSpecs[Random.randInt(this.indexSpecs.length)];
- jsTestLog(`Running dropIndex: coll=${this.outputCollName} indexSpec=${indexSpec}`);
db[this.outputCollName].dropIndex(indexSpec);
};
@@ -126,39 +107,20 @@ var $config = extendWorkload($config, function($config, $super) {
// Change the validation level.
const validationLevels = ['off', 'strict', 'moderate'];
const newValidationLevel = validationLevels[Random.randInt(validationLevels.length)];
- jsTestLog(`Running collMod: coll=${this.outputCollName} validationLevel=${
- newValidationLevel}`);
-
assertWhenOwnDB.commandWorkedOrFailedWithCode(
db.runCommand({collMod: this.outputCollName, validationLevel: newValidationLevel}),
- [ErrorCodes.ConflictingOperationInProgress, ErrorCodes.MovePrimaryInProgress]);
+ ErrorCodes.ConflictingOperationInProgress);
} else {
// Change the validation action.
- const validationAction = Random.rand() > 0.5 ? 'warn' : 'error';
- jsTestLog(`Running collMod: coll=${this.outputCollName} validationAction=${
- validationAction}`);
-
assertWhenOwnDB.commandWorkedOrFailedWithCode(
- db.runCommand({collMod: this.outputCollName, validationAction: validationAction}),
- [ErrorCodes.ConflictingOperationInProgress, ErrorCodes.MovePrimaryInProgress]);
+ db.runCommand({
+ collMod: this.outputCollName,
+ validationAction: Random.rand() > 0.5 ? 'warn' : 'error'
+ }),
+ ErrorCodes.ConflictingOperationInProgress);
}
};
- $config.states.movePrimary = function movePrimary(db, collName) {
- if (!isMongos(db)) {
- return;
- }
- const toShard = this.shards[Random.randInt(this.shards.length)];
- jsTestLog(`Running movePrimary: db=${db} to=${toShard}`);
-
- assert.commandWorkedOrFailedWithCode(
- db.adminCommand({movePrimary: db.getName(), to: toShard}), [
- // Caused by a concurrent movePrimary operation on the same database but a different
- // destination shard.
- ErrorCodes.ConflictingOperationInProgress,
- ]);
- };
-
/**
* Converts '$config.data.outputCollName' to a capped collection. This is never undone, and all
* subsequent $out's to this collection should fail.
@@ -168,10 +130,8 @@ var $config = extendWorkload($config, function($config, $super) {
return; // convertToCapped can't be run against a mongos.
}
- jsTestLog(`Running convertToCapped: coll=${this.outputCollName}`);
- assertWhenOwnDB.commandWorkedOrFailedWithCode(
- db.runCommand({convertToCapped: this.outputCollName, size: 100000}),
- ErrorCodes.MovePrimaryInProgress);
+ assertWhenOwnDB.commandWorked(
+ db.runCommand({convertToCapped: this.outputCollName, size: 100000}));
};
/**
@@ -182,7 +142,6 @@ var $config = extendWorkload($config, function($config, $super) {
*/
$config.states.shardCollection = function shardCollection(db, unusedCollName) {
if (isMongos(db) && this.tid === 0) {
- jsTestLog(`Running shardCollection: coll=${this.outputCollName} key=${this.shardKey}`);
assertWhenOwnDB.commandWorked(db.adminCommand({enableSharding: db.getName()}));
assertWhenOwnDB.commandWorked(db.adminCommand(
{shardCollection: db[this.outputCollName].getFullName(), key: {_id: 'hashed'}}));
@@ -198,10 +157,6 @@ var $config = extendWorkload($config, function($config, $super) {
// `shardCollection()` requires a shard key index to be in place on the output collection,
// as we may be sharding a non-empty collection.
assertWhenOwnDB.commandWorked(db[this.outputCollName].createIndex({_id: 'hashed'}));
-
- if (isMongos(db)) {
- this.shards = Object.keys(cluster.getSerializedCluster().shards);
- }
};
return $config;
diff --git a/jstests/concurrency/fsm_workloads/collection_uuid_sharded.js b/jstests/concurrency/fsm_workloads/collection_uuid_sharded.js
index 7fbaba0357f..40cc51e3219 100644
--- a/jstests/concurrency/fsm_workloads/collection_uuid_sharded.js
+++ b/jstests/concurrency/fsm_workloads/collection_uuid_sharded.js
@@ -34,7 +34,8 @@ var $config = extendWorkload($config, function($config, $super) {
let reshardCollectionCmd = {
reshardCollection: namespace,
key: {a: 1},
- collectionUUID: this.collUUID
+ collectionUUID: this.collUUID,
+ numInitialChunks: 1,
};
testCommand(db, namespace, "reshardCollection", reshardCollectionCmd, this);
@@ -56,7 +57,8 @@ var $config = extendWorkload($config, function($config, $super) {
reshardCollectionCmd = {
reshardCollection: namespace,
key: {_id: 1},
- collectionUUID: this.collUUID
+ collectionUUID: this.collUUID,
+ numInitialChunks: 1,
};
testCommand(db, namespace, "reshardCollection", reshardCollectionCmd, this);
}
diff --git a/jstests/concurrency/fsm_workloads/insert_with_data_size_aware_balancing.js b/jstests/concurrency/fsm_workloads/insert_with_data_size_aware_balancing.js
deleted file mode 100644
index 65315d99b36..00000000000
--- a/jstests/concurrency/fsm_workloads/insert_with_data_size_aware_balancing.js
+++ /dev/null
@@ -1,131 +0,0 @@
-'use strict';
-
-/**
- * - Shard several collections with different (random) configured maxChunkSize
- * - Perform continuous inserts of random amounts of data into the collections
- * - Verify that the balancer fairly redistributes data among available shards
- *
- * @tags: [
- * requires_sharding,
- * assumes_balancer_on,
- * featureFlagBalanceAccordingToDataSize,
- * requires_fcv_60,
- * ]
- */
-
-const bigString = 'X'.repeat(1024 * 1024 - 30); // Almost 1MB, to create documents of exactly 1MB
-const minChunkSizeMB = 1;
-const maxChunkSizeMB = 10;
-const dbNames = ['db0', 'db1'];
-const collNames = ['collA', 'collB', 'collC'];
-
-/*
- * Get a random db/coll name from the test lists.
- *
- * Using the thread id to introduce more randomness: it has been observed that concurrent calls to
- * Random.randInt(array.length) are returning too often the same number to different threads.
- */
-function getRandomDbName(tid) {
- return dbNames[Random.randInt(tid * tid) % dbNames.length];
-}
-function getRandomCollName(tid) {
- return collNames[Random.randInt(tid * tid) % collNames.length];
-}
-
-var $config = (function() {
- let states = {
- /*
- * Insert into a test collection a random amount of documents (up to 10MB per iteration)
- */
- insert: function(db, collName, connCache) {
- const dbName = getRandomDbName(this.tid);
- db = db.getSiblingDB(dbName);
- collName = getRandomCollName(this.tid);
- const coll = db[collName];
-
- const numDocs = Random.randInt(maxChunkSizeMB - 1) + 1;
- let insertBulkOp = coll.initializeUnorderedBulkOp();
- for (let i = 0; i < numDocs; ++i) {
- insertBulkOp.insert({s: bigString});
- }
-
- assertAlways.commandWorked(insertBulkOp.execute());
- },
- };
-
- /*
- * Create sharded collections with random maxChunkSizeMB (betwen 1MB and 10MB)
- */
- let setup = function(db, collName, cluster) {
- const mongos = cluster.getDB('config').getMongo();
- const shardNames = Object.keys(cluster.getSerializedCluster().shards);
- const numShards = shardNames.length;
-
- for (let i = 0; i < dbNames.length; i++) {
- // Initialize database
- const dbName = dbNames[i];
- const newDb = db.getSiblingDB(dbName);
- newDb.adminCommand({enablesharding: dbName, primaryShard: shardNames[i % numShards]});
-
- for (let j = 0; j < collNames.length; j++) {
- // Shard collection
- collName = collNames[j];
- const coll = newDb[collName];
- const ns = coll.getFullName();
- db.adminCommand({shardCollection: ns, key: {_id: 1}});
-
- // Configure random maxChunkSize
- const randomMaxChunkSizeMB = Random.randInt(maxChunkSizeMB - 1) + 1;
- assert.commandWorked(mongos.adminCommand({
- configureCollectionBalancing: ns,
- chunkSize: randomMaxChunkSizeMB,
- }));
- }
- }
- };
-
- /*
- * Verify that the balancer fairly redistributes data among available shards: the
- * collection size difference between two shards must be at most 2 * maxChunkSize
- */
- let teardown = function(db, collName, cluster) {
- const mongos = cluster.getDB('config').getMongo();
- // Sentinel variable to make sure not all collections have been skipped
- let testedAtLeastOneCollection = false;
- for (let i = 0; i < dbNames.length; i++) {
- const dbName = dbNames[i];
- for (let j = 0; j < collNames.length; j++) {
- collName = collNames[j];
- const ns = dbName + '.' + collName;
-
- const coll = mongos.getCollection(ns);
- if (coll.countDocuments({}) === 0) {
- // Skip empty collections
- continue;
- }
- testedAtLeastOneCollection = true;
-
- // Wait for collection to be considered balanced
- sh.awaitCollectionBalance(
- coll, 5 * 60000 /* 5min timeout */, 1000 /* 1s interval */);
- sh.verifyCollectionIsBalanced(coll);
- }
-
- assert(testedAtLeastOneCollection);
- }
- };
-
- let transitions = {insert: {insert: 1.0}};
-
- return {
- threadCount: 5,
- iterations: 8,
- startState: 'insert',
- states: states,
- transitions: transitions,
- data: {},
- setup: setup,
- teardown: teardown,
- passConnectionCache: true
- };
-})();
diff --git a/jstests/concurrency/fsm_workloads/query_stats_concurrent.js b/jstests/concurrency/fsm_workloads/query_stats_concurrent.js
new file mode 100644
index 00000000000..6d7b9456288
--- /dev/null
+++ b/jstests/concurrency/fsm_workloads/query_stats_concurrent.js
@@ -0,0 +1,155 @@
+'use strict';
+
+/**
+ * query_stats_concurrent.js
+ *
+ * Stresses $queryStats running concurrently with queries.
+ *
+ * @tags: [
+ * requires_fcv_60,
+ * does_not_support_causal_consistency,
+ * ]
+ *
+ *
+ */
+load("jstests/concurrency/fsm_workload_helpers/set_parameter.js");
+
+var $config = (function() {
+ var states = (function() {
+ function init(db, collName) {
+ }
+
+ function reInit(db, collName) {
+ }
+
+ // Runs one find query so that the queryStatsEntry is updated.
+ function findOneShape(db, collName) {
+ assertWhenOwnColl.gt(db[collName].find({i: {$lt: 50}}).itcount(), 0);
+ }
+
+ // Runs one agg query so that the queryStatsEntry is updated.
+ function aggOneShape(db, collName) {
+ assertWhenOwnColl.gt(db[collName].aggregate([{$match: {i: {$gt: 900}}}]).itcount(), 0);
+ }
+
+ // Runs many queries with different shapes to ensure eviction occurs in the queryStats
+ // store.
+ function multipleShapes(db, collName) {
+ for (var i = 0; i < 10000; i++) {
+ let query = {};
+ query["foo" + i] = "bar";
+ db[collName].aggregate([{$match: query}]).itcount();
+ }
+ const evictedAfter = db.serverStatus().metrics.queryStats.numEvicted;
+ assertAlways.gt(evictedAfter, 0);
+ }
+
+ // Runs queryStats with transformation.
+ function runQueryStatsWithHmac(db, collName) {
+ let response = db.adminCommand({
+ aggregate: 1,
+ pipeline: [{
+ $queryStats: {
+ transformIdentifiers: {
+ algorithm: "hmac-sha-256",
+ hmacKey: BinData(8, "MjM0NTY3ODkxMDExMTIxMzE0MTUxNjE3MTgxOTIwMjE=")
+ }
+ }
+ }],
+ // Use a small batch size to ensure these operations open up a cursor and use
+ // multiple getMores.
+ cursor: {batchSize: 1}
+ });
+ assertAlways.commandWorked(response);
+ const cursor = new DBCommandCursor(db.getSiblingDB("admin"), response);
+ assertAlways.gt(cursor.itcount(), 0);
+ }
+
+ // Runs queryStats without transformation.
+ function runQueryStatsWithoutHmac(db, collName) {
+ let response = db.adminCommand({
+ aggregate: 1,
+ pipeline: [{$queryStats: {}}],
+ // Use a small batch size to ensure these operations open up a cursor and use
+ // multiple getMores.
+ cursor: {batchSize: 1}
+ });
+ assertAlways.commandWorked(response);
+ const cursor = new DBCommandCursor(db.getSiblingDB("admin"), response);
+ assertAlways.gt(cursor.itcount(), 0);
+ }
+
+ return {
+ init: init,
+ reInit: reInit,
+ findOneShape: findOneShape,
+ multipleShapes: multipleShapes,
+ aggOneShape: aggOneShape,
+ runQueryStatsWithHmac: runQueryStatsWithHmac,
+ runQueryStatsWithoutHmac: runQueryStatsWithoutHmac
+ };
+ })();
+
+ var internalQueryStatsRateLimit;
+ var internalQueryStatsCacheSize;
+
+ let setup = function(db, collName, cluster) {
+ internalQueryStatsRateLimit = setParameterOnAllNodes(
+ {cluster: cluster, paramName: "internalQueryStatsRateLimit", newValue: -1});
+ internalQueryStatsCacheSize = setParameterOnAllNodes(
+ {cluster: cluster, paramName: "internalQueryStatsCacheSize", newValue: "1MB"});
+
+ assert.commandWorked(db[collName].createIndex({i: 1}));
+ const bulk = db[collName].initializeUnorderedBulkOp();
+ for (let i = 0; i < 1000; ++i) {
+ bulk.insert({i: i});
+ }
+ assert.commandWorked(bulk.execute());
+ };
+
+ let teardown = function(db, collName, cluster) {
+ setParameterOnAllNodes({
+ cluster: cluster,
+ paramName: "internalQueryStatsRateLimit",
+ newValue: internalQueryStatsRateLimit
+ });
+ setParameterOnAllNodes({
+ cluster: cluster,
+ paramName: "internalQueryStatsCacheSize",
+ newValue: internalQueryStatsCacheSize
+ });
+
+ db[collName].drop();
+ };
+
+ let transitions = {
+ // To start, add some $queryStats data so that it is never empty.
+ init: {
+ aggOneShape: 0.33,
+ findOneShape: 0.33,
+ multipleShapes: 0.34,
+ },
+ // From then on, choose evenly among all possibilities:
+ reInit: {
+ aggOneShape: 0.2,
+ findOneShape: 0.2,
+ multipleShapes: 0.2,
+ runQueryStatsWithHmac: 0.2,
+ runQueryStatsWithoutHmac: 0.2
+ },
+ findOneShape: {reInit: 1},
+ multipleShapes: {reInit: 1},
+ runQueryStatsWithHmac: {reInit: 1},
+ runQueryStatsWithoutHmac: {reInit: 1},
+ aggOneShape: {reInit: 1}
+ };
+
+ return {
+ threadCount: 10,
+ iterations: 10,
+ states: states,
+ setup: setup,
+ teardown: teardown,
+ transitions: transitions
+ };
+})();
diff --git a/jstests/concurrency/fsm_workloads/query_stats_enable_disable.js b/jstests/concurrency/fsm_workloads/query_stats_enable_disable.js
new file mode 100644
index 00000000000..ff22b26efb0
--- /dev/null
+++ b/jstests/concurrency/fsm_workloads/query_stats_enable_disable.js
@@ -0,0 +1,133 @@
+/**
+ * query_stats_enable_disable.js
+ *
+ * Stresses $queryStats being toggled on and off during execution.
+ *
+ * @tags: [
+ * requires_fcv_60,
+ * # Cannot read query stats entries from a different node than issued the query.
+ * does_not_support_causal_consistency,
+ * # setParameter is not persistent.
+ * does_not_support_stepdowns,
+ * # Changing the query stats parameters messes with the query stats test which expects to see
+ * # query stats results.
+ * incompatible_with_concurrency_simultaneous,
+ * ]
+ *
+ */
+
+load("jstests/concurrency/fsm_workload_helpers/set_parameter.js");
+
+var $config = (function() {
+ function setCacheSize(db, cacheSize) {
+ assert.commandWorked(
+ db.adminCommand({setParameter: 1, internalQueryStatsCacheSize: cacheSize}));
+ }
+
+ function setRateLimit(db, rateLimit) {
+ assert.commandWorked(
+ db.adminCommand({setParameter: 1, internalQueryStatsRateLimit: rateLimit}));
+ }
+
+ function runQueryStats({db, options}) {
+ try {
+ // Use a small batch size to ensure these operations open up a cursor and use
+ // multiple getMores - this will better stress odd concurrency states.
+ const cursor =
+ db.getSiblingDB("admin").aggregate([{$queryStats: options}], {batchSize: 1});
+ // Can't assert much in particular about the results.
+ assert.gte(cursor.itcount(), 0);
+ } catch (e) {
+ if (e.code === ErrorCodes.QueryFeatureNotAllowed) {
+ // This means query stats is disabled, which is expected to happen in this workload.
+ return;
+ }
+ throw e;
+ }
+ }
+
+ const hmacOptions = {
+ transformIdentifiers: {
+ algorithm: "hmac-sha-256",
+ hmacKey: BinData(8, "MjM0NTY3ODkxMDExMTIxMzE0MTUxNjE3MTgxOTIwMjE=")
+ }
+ };
+ const nDifferentShapes = 200;
+ const states = {
+ // The main operating states which toggle the feature on and off, since we've seen
+ // bugs like SERVER-84730 when this happens.
+ disableViaCacheSize: (db, collName) => setCacheSize(db, "0MB"),
+ enableViaCacheSize: (db, collName) => setCacheSize(db, "1MB"),
+ disableViaRateLimit: (db, collName) => setRateLimit(db, 0),
+ enableViaRateLimit: (db, collName) => setRateLimit(db, -1),
+
+ runOneQuery: function runOneQuery(db, collName) {
+ assert.eq(null,
+ db[collName].findOne({["field" + Random.randInt(nDifferentShapes)]: 42}));
+ },
+
+ runQueryStatsWithHmac: (db, collName) => runQueryStats({db: db, options: hmacOptions}),
+ runQueryStatsWithoutHmac: (db, collName) => runQueryStats({db: db, options: {}}),
+ init: (db, collName) => { /* no op */ },
+ };
+
+ const transitions = {
+ init: {
+ // Make the most common thing be running a query.
+ runOneQuery: 0.6,
+ // Followed by runing $queryStats, with half the probability.
+ runQueryStatsWithHmac: 0.15,
+ runQueryStatsWithoutHmac: 0.15,
+ // These sum up to 0.1:
+ disableViaCacheSize: 0.05,
+ disableViaRateLimit: 0.05,
+ },
+ runOneQuery: {init: 1},
+ runQueryStatsWithHmac: {init: 1},
+ runQueryStatsWithoutHmac: {init: 1},
+ // If you disable it, immediately re-enable it.
+ disableViaCacheSize: {enableViaCacheSize: 1},
+ enableViaCacheSize: {init: 1},
+ disableViaRateLimit: {enableViaRateLimit: 1},
+ enableViaRateLimit: {init: 1},
+ };
+
+ var internalQueryStatsRateLimit;
+ var internalQueryStatsCacheSize;
+
+ const setup = function(db, collName, cluster) {
+ // TODO SERVER-85405 Make this pattern easier and repeated throughout multiple workloads,
+ // not just the query stats ones.
+ internalQueryStatsRateLimit = setParameterOnAllNodes(
+ {cluster: cluster, paramName: "internalQueryStatsRateLimit", newValue: -1});
+ internalQueryStatsCacheSize = setParameterOnAllNodes(
+ {cluster: cluster, paramName: "internalQueryStatsCacheSize", newValue: "1MB"});
+ };
+
+ const teardown = function(db, collName, cluster) {
+ setParameterOnAllNodes({
+ cluster: cluster,
+ paramName: "internalQueryStatsRateLimit",
+ newValue: internalQueryStatsRateLimit,
+ // We were messing with the settings in this test by sending commands only to the
+ // primary. The secondaries are not expected to be involved and so cannot be expected to
+ // have the same settings.
+ assertAllSettingsWereIdentical: false,
+ });
+ setParameterOnAllNodes({
+ cluster: cluster,
+ paramName: "internalQueryStatsCacheSize",
+ newValue: internalQueryStatsCacheSize,
+ assertAllSettingsWereIdentical: false,
+ });
+ };
+
+ return {
+ threadCount: 10,
+ iterations: 10,
+ states: states,
+ setup: setup,
+ teardown: teardown,
+ transitions: transitions
+ };
+})();
diff --git a/jstests/concurrency/fsm_workloads/random_moveChunk_refine_collection_shard_key.js b/jstests/concurrency/fsm_workloads/random_moveChunk_refine_collection_shard_key.js
index d74d2454176..18fa771a945 100644
--- a/jstests/concurrency/fsm_workloads/random_moveChunk_refine_collection_shard_key.js
+++ b/jstests/concurrency/fsm_workloads/random_moveChunk_refine_collection_shard_key.js
@@ -57,7 +57,17 @@ var $config = extendWorkload($config, function($config, $super) {
// migrated back in. The particular error code is replaced with a more generic one, so this
// is identified by the failed migration's error message.
$config.data.isMoveChunkErrorAcceptable = (err) => {
- const codes = [ErrorCodes.LockBusy, ErrorCodes.ShardKeyNotFound, ErrorCodes.LockTimeout];
+ const codes = [
+ // TODO SERVER-68551: Remove lockbusy error since the balancer won't acquire anymore the
+ // DDL lock for migrations
+ ErrorCodes.LockBusy,
+ ErrorCodes.ShardKeyNotFound,
+ ErrorCodes.LockTimeout,
+ // The refienCollectionCoordinator interrupt all migrations by setting `allowMigration`
+ // to false
+ ErrorCodes.Interrupted,
+ ErrorCodes.OrphanedRangeCleanUpFailed,
+ ];
return (err.code && codes.includes(err.code)) ||
(err.message &&
(err.message.includes("CommandFailed") ||
diff --git a/jstests/concurrency/fsm_workloads/random_moveChunk_timeseries_insert_many.js b/jstests/concurrency/fsm_workloads/random_moveChunk_timeseries_insert_many.js
index 97b0cf8e5b4..80224a2725d 100644
--- a/jstests/concurrency/fsm_workloads/random_moveChunk_timeseries_insert_many.js
+++ b/jstests/concurrency/fsm_workloads/random_moveChunk_timeseries_insert_many.js
@@ -7,6 +7,7 @@
* assumes_balancer_off,
* requires_non_retryable_writes,
* does_not_support_transactions,
+ * requires_fcv_51,
* ]
*/
load('jstests/concurrency/fsm_workload_helpers/chunks.js'); // for chunk helpers
diff --git a/jstests/core/aggregation_accepts_write_concern.js b/jstests/core/aggregation_accepts_write_concern.js
index 2c764414a1d..8117c296e03 100644
--- a/jstests/core/aggregation_accepts_write_concern.js
+++ b/jstests/core/aggregation_accepts_write_concern.js
@@ -1,7 +1,11 @@
/**
* Confirms that the aggregate command accepts writeConcern regardless of whether the pipeline
* writes or is read-only.
- * @tags: [assumes_write_concern_unchanged, does_not_support_stepdowns]
+ * @tags: [
+ * assumes_write_concern_unchanged,
+ * does_not_support_stepdowns,
+ * references_foreign_collection
+ * ]
*/
(function() {
"use strict";
diff --git a/jstests/core/api_version_pipeline_stages.js b/jstests/core/api_version_pipeline_stages.js
index c9772e4fa0c..c9d092a9a06 100644
--- a/jstests/core/api_version_pipeline_stages.js
+++ b/jstests/core/api_version_pipeline_stages.js
@@ -27,7 +27,6 @@ const unstablePipelines = [
[{$planCacheStats: {}}],
[{$unionWith: {coll: "coll2", pipeline: [{$collStats: {latencyStats: {}}}]}}],
[{$lookup: {from: "coll2", pipeline: [{$indexStats: {}}]}}],
- [{$lookup: {from: "coll2", _internalCollation: {locale: "simple"}}}],
[{$facet: {field1: [], field2: [{$indexStats: {}}]}}],
];
diff --git a/jstests/core/api_version_test_expression.js b/jstests/core/api_version_test_expression.js
index 41bbd9c0402..3252ebda83e 100644
--- a/jstests/core/api_version_test_expression.js
+++ b/jstests/core/api_version_test_expression.js
@@ -8,6 +8,7 @@
* assumes_unsharded_collection,
* uses_api_parameters,
* no_selinux,
+ * references_foreign_collection,
* ]
*/
diff --git a/jstests/core/arrayfind8.js b/jstests/core/arrayfind8.js
index 87a3a8d701a..ee74aae33ef 100644
--- a/jstests/core/arrayfind8.js
+++ b/jstests/core/arrayfind8.js
@@ -81,7 +81,6 @@ function checkQuery(subQuery, bothMatch, elemMatch, nonElemMatch, additionalCons
insertValueIfNotNull(bothMatch);
insertValueIfNotNull(elemMatch);
insertValueIfNotNull(nonElemMatch);
-
checkMatch(bothMatch, elemMatch, nonElemMatch, standardQuery, elemMatchQuery, 'unindexed');
// Check matching and index bounds for a single key index.
diff --git a/jstests/core/bypass_doc_validation.js b/jstests/core/bypass_doc_validation.js
index d290508835a..1fd32db658b 100644
--- a/jstests/core/bypass_doc_validation.js
+++ b/jstests/core/bypass_doc_validation.js
@@ -6,6 +6,7 @@
// uses_map_reduce_with_temp_collections,
// # Tenant migrations don't support applyOps.
// tenant_migration_incompatible,
+// references_foreign_collection,
// ]
/**
diff --git a/jstests/core/bypass_empty_ts_replacement.js b/jstests/core/bypass_empty_ts_replacement.js
new file mode 100644
index 00000000000..9bd74f3f0ca
--- /dev/null
+++ b/jstests/core/bypass_empty_ts_replacement.js
@@ -0,0 +1,202 @@
+/**
+ * Tests the "bypassEmptyTsReplacement" option.
+ *
+ * @tags: [
+ * requires_fcv_60,
+ * ]
+ */
+(function() {
+"use strict";
+
+const coll = db.jstests_bypass_empty_ts_replacement;
+const collName = coll.getName();
+const emptyTs = Timestamp(0, 0);
+
+coll.drop();
+
+function doInsert(docs, bypassEmptyTsReplacement) {
+ let cmdRes = db.runCommand(
+ {insert: collName, documents: docs, bypassEmptyTsReplacement: bypassEmptyTsReplacement});
+ assert.commandWorked(cmdRes);
+}
+
+function doUpdate(filter, update, bypassEmptyTsReplacement) {
+ let cmdRes = db.runCommand({
+ update: collName,
+ updates: [{q: filter, u: update}],
+ bypassEmptyTsReplacement: bypassEmptyTsReplacement
+ });
+ assert.commandWorked(cmdRes);
+}
+
+function doUpdateWithUpsert(filter, update, bypassEmptyTsReplacement) {
+ let cmdRes = db.runCommand({
+ update: collName,
+ updates: [{q: filter, u: update, upsert: true}],
+ bypassEmptyTsReplacement: bypassEmptyTsReplacement
+ });
+ assert.commandWorked(cmdRes);
+}
+
+function doFindAndModify(filter, update, bypassEmptyTsReplacement) {
+ let cmdRes = db.runCommand({
+ findAndModify: collName,
+ query: filter,
+ update: update,
+ bypassEmptyTsReplacement: bypassEmptyTsReplacement
+ });
+ assert.commandWorked(cmdRes);
+}
+
+function doFindAndModifyWithUpsert(filter, update, bypassEmptyTsReplacement) {
+ let cmdRes = db.runCommand({
+ findAndModify: collName,
+ query: filter,
+ update: update,
+ upsert: true,
+ bypassEmptyTsReplacement: bypassEmptyTsReplacement
+ });
+ assert.commandWorked(cmdRes);
+}
+
+let numCallsToRunTests = 0;
+
+function runTests(bypassEmptyTsReplacement) {
+ ++numCallsToRunTests;
+
+ let first = (numCallsToRunTests == 1);
+ let startId = numCallsToRunTests * 100;
+
+ function getId(i) {
+ return startId + i;
+ }
+
+ // The insert/update/findAndModify commands below will be run with the bypassEmptyTsReplacement
+ // parameter set to true or false (depending whether the 'bypassEmptyTsReplacement' variable is
+ // true or false).
+
+ // Insert several documents.
+ doInsert([{_id: getId(1), a: emptyTs}], bypassEmptyTsReplacement);
+ doInsert([{_id: getId(2), a: 1}], bypassEmptyTsReplacement);
+ doInsert([{_id: getId(3), a: 2}], bypassEmptyTsReplacement);
+ doInsert([{_id: getId(6), a: 3}], bypassEmptyTsReplacement);
+ doInsert([{_id: getId(7), a: 4}], bypassEmptyTsReplacement);
+ doInsert([{_id: getId(8), a: 5}], bypassEmptyTsReplacement);
+ doInsert([{_id: getId(9), a: 6}], bypassEmptyTsReplacement);
+ doInsert([{_id: getId(10), a: 7}], bypassEmptyTsReplacement);
+ doInsert([{_id: getId(11), a: 8}], bypassEmptyTsReplacement);
+
+ // Use a replacement-style update to update the doc with _id=getId(2).
+ //
+ // When bypassEmptyTsReplacement=true, this is an example of how the special "empty timestamp"
+ // behavior can be suppressed when doing a replacement-style update.
+ doUpdate({_id: getId(2)}, {a: emptyTs}, bypassEmptyTsReplacement);
+
+ // Use a replacement-style findAndModify to update the doc with _id=getId(3).
+ doFindAndModify({_id: getId(3)}, {a: emptyTs}, bypassEmptyTsReplacement);
+
+ // Do a replacement-style update to add a new document with _id=getId(4).
+ doUpdateWithUpsert({_id: getId(4)}, {a: emptyTs}, bypassEmptyTsReplacement);
+
+ // Do a replacement-style findAndModify to add a new document with _id=getId(5).
+ doFindAndModifyWithUpsert({_id: getId(5)}, {a: emptyTs}, bypassEmptyTsReplacement);
+
+ // Do an update-operator-style update to update the doc with _id=getId(6).
+ doUpdate({_id: getId(6)}, {$set: {a: emptyTs}}, bypassEmptyTsReplacement);
+
+ // Do an update-operator-style findAndModify to update the doc with _id=getId(7).
+ doFindAndModify({_id: getId(7)}, {$set: {a: emptyTs}}, bypassEmptyTsReplacement);
+
+ // Do a pipeline-style update to update the doc with _id=getId(8).
+ doUpdate({_id: getId(8)}, [{$addFields: {a: emptyTs}}], bypassEmptyTsReplacement);
+
+ // Do a pipeline-style findAndModify to update the doc with _id=getId(9).
+ doFindAndModify({_id: getId(9)}, [{$addFields: {a: emptyTs}}], bypassEmptyTsReplacement);
+
+ // Do a pipeline-style update with $internalApplyOplogUpdate to update the doc with
+ // _id=getId(10).
+ doUpdate({_id: getId(10)},
+ [{$_internalApplyOplogUpdate: {oplogUpdate: {$v: 2, diff: {i: {a: emptyTs}}}}}],
+ bypassEmptyTsReplacement);
+
+ // Do a pipeline-style findAndModify with $internalApplyOplogUpdate to update the doc with
+ // _id=getId(11).
+ doFindAndModify({_id: getId(11)},
+ [{$_internalApplyOplogUpdate: {oplogUpdate: {$v: 2, diff: {i: {a: emptyTs}}}}}],
+ bypassEmptyTsReplacement);
+
+ // Do an update-operator-style update to add a new document with _id=getId(12).
+ doUpdateWithUpsert({_id: getId(12)}, {$set: {a: emptyTs}}, bypassEmptyTsReplacement);
+
+ // Do an update-operator-style findAndModify to add a new document with _id=getId(13).
+ doFindAndModifyWithUpsert({_id: getId(13)}, {$set: {a: emptyTs}}, bypassEmptyTsReplacement);
+
+ // Do a pipeline-style update to add a new document with _id=getId(14).
+ doUpdateWithUpsert({_id: getId(14)}, [{$addFields: {a: emptyTs}}], bypassEmptyTsReplacement);
+
+ // Do a pipeline-style findAndModify to add a new document with _id=getId(15).
+ doFindAndModifyWithUpsert(
+ {_id: getId(15)}, [{$addFields: {a: emptyTs}}], bypassEmptyTsReplacement);
+
+ // Do a pipline-style update with $internalApplyOplogUpdate to add a new document with
+ // _id=getId(16).
+ doUpdateWithUpsert(
+ {_id: getId(16)},
+ [{$_internalApplyOplogUpdate: {oplogUpdate: {$v: 2, diff: {i: {a: emptyTs}}}}}],
+ bypassEmptyTsReplacement);
+
+ // Do pipeline-style findAndModify with $internalApplyOplogUpdate to add a new document
+ // with _id=getId(17).
+ doFindAndModifyWithUpsert(
+ {_id: getId(17)},
+ [{$_internalApplyOplogUpdate: {oplogUpdate: {$v: 2, diff: {i: {a: emptyTs}}}}}],
+ bypassEmptyTsReplacement);
+
+ // Verify that all the insert, update, and findAndModify commands behaved the way we expected.
+ // If 'bypassEmptyTsReplacement' is true, then we expect field "a" will be equal to the empty
+ // timestamp for all 17 documents. If 'bypassEmptyTsReplacement' is false, then we expect
+ // field "a" will be equal to the current timestamp for the first 5 documents and it will
+ // be equal to the empty timestamp for the other 12 documents.
+ for (let i = 1; i <= 17; ++i) {
+ let result = coll.findOne({_id: getId(i)});
+
+ if (bypassEmptyTsReplacement || i >= 6) {
+ assert.eq(tojson(result.a), tojson(emptyTs), "_id=" + getId(i));
+ } else {
+ assert.neq(tojson(result.a), tojson(emptyTs), "_id=" + getId(i));
+ }
+ }
+
+ if (first) {
+ // If this is the first time that runTests() is invoked, insert a document with
+ // _id=Timestamp(0,0), and then verify that the document we just inserted can be
+ // retrieved using the filter "{_id: Timestamp(0,0)}".
+ doInsert([{_id: emptyTs, a: 9}], bypassEmptyTsReplacement);
+
+ let result = coll.findOne({_id: emptyTs});
+ assert.eq(tojson(result._id), tojson(emptyTs), "_id=" + tojson(emptyTs));
+ assert.eq(tojson(result.a), tojson(9), "_id=" + tojson(emptyTs));
+ }
+
+ // Do a replacement-style update on the document with _id=Timestamp(0,0).
+ doUpdate({_id: emptyTs}, {_id: emptyTs, a: emptyTs}, bypassEmptyTsReplacement);
+
+ // Verify the document we just updated can still be retrieved using "{_id: Timestamp(0,0)}".
+ let result = coll.findOne({_id: emptyTs});
+ assert.eq(tojson(result._id), tojson(emptyTs), "_id=" + tojson(emptyTs));
+
+ if (bypassEmptyTsReplacement) {
+ // Verify that an empty timestamp value was stored in field "a".
+ assert.eq(tojson(result.a), tojson(emptyTs), "_id=" + tojson(emptyTs));
+ } else {
+ // Verify that field "a" was set to the current timestamp.
+ assert.neq(tojson(result.a), tojson(emptyTs), "_id=" + tojson(emptyTs));
+ }
+}
+
+let bypassEmptyTsReplacement = true;
+runTests(bypassEmptyTsReplacement);
+
+bypassEmptyTsReplacement = false;
+runTests(bypassEmptyTsReplacement);
+}());
diff --git a/jstests/core/bypass_empty_ts_replacement_timeseries.js b/jstests/core/bypass_empty_ts_replacement_timeseries.js
new file mode 100644
index 00000000000..69a5bcf281c
--- /dev/null
+++ b/jstests/core/bypass_empty_ts_replacement_timeseries.js
@@ -0,0 +1,73 @@
+/**
+ * Tests inserts, updates, and upserts on a timeseries collection with "bypassEmptyTsReplacement"
+ * set to true.
+ *
+ * @tags: [
+ * assumes_no_implicit_collection_creation_after_drop,
+ * does_not_support_transactions,
+ * requires_fcv_60,
+ * requires_multi_updates,
+ * requires_non_retryable_writes,
+ * requires_timeseries,
+ * ]
+ */
+(function() {
+"use strict";
+
+const coll = db.jstests_bypass_empty_ts_replacement_timeseries;
+const collName = coll.getName();
+const emptyTs = Timestamp(0, 0);
+
+coll.drop();
+
+assert.commandWorked(db.createCollection(collName, {timeseries: {timeField: "t", metaField: "m"}}));
+
+function doInsert(docs, bypassEmptyTsReplacement) {
+ let cmdRes = db.runCommand(
+ {insert: collName, documents: docs, bypassEmptyTsReplacement: bypassEmptyTsReplacement});
+ assert.commandWorked(cmdRes);
+}
+
+function doUpdate(filter, update, bypassEmptyTsReplacement) {
+ let cmdRes = db.runCommand({
+ update: collName,
+ updates: [{q: filter, u: update, multi: true}],
+ bypassEmptyTsReplacement: bypassEmptyTsReplacement
+ });
+ assert.commandWorked(cmdRes);
+}
+
+let numCallsToRunTests = 0;
+
+function runTests(bypassEmptyTsReplacement) {
+ ++numCallsToRunTests;
+
+ let startId = numCallsToRunTests * 100;
+
+ function getId(i) {
+ return startId + i;
+ }
+
+ // Insert two documents.
+ doInsert([{_id: getId(1), t: new Date(100), m: emptyTs, a: emptyTs}], bypassEmptyTsReplacement);
+ doInsert([{_id: getId(2), t: new Date(200), m: getId(2), a: emptyTs}],
+ bypassEmptyTsReplacement);
+
+ // Do a replacement-style update containing an empty timestamp value.
+ doUpdate({m: getId(2)}, {$set: {m: emptyTs}}, bypassEmptyTsReplacement);
+
+ // Verify that the commands above didn't mutate any of the empty timestamp values in the
+ // collection.
+ for (let i = 1; i <= 2; ++i) {
+ let result = coll.findOne({_id: getId(i)});
+ assert.eq(tojson(result.m), tojson(emptyTs), "_id=" + getId(i));
+ assert.eq(tojson(result.a), tojson(emptyTs), "_id=" + getId(i));
+ }
+}
+
+let bypassEmptyTsReplacement = true;
+runTests(bypassEmptyTsReplacement);
+
+bypassEmptyTsReplacement = false;
+runTests(bypassEmptyTsReplacement);
+}());
diff --git a/jstests/core/check_shard_index.js b/jstests/core/check_shard_index.js
index 2beb3c12891..23f69c6b757 100644
--- a/jstests/core/check_shard_index.js
+++ b/jstests/core/check_shard_index.js
@@ -21,12 +21,12 @@ f.createIndex({x: 1, y: 1});
assert.eq(0, f.count(), "1. initial count should be zero");
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1}});
-assert.eq(true, res.ok, "1a");
+assert.commandWorked(res, "1a " + tojson(res));
f.save({x: 1, y: 1});
assert.eq(1, f.count(), "1. count after initial insert should be 1");
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1}});
-assert.eq(true, res.ok, "1b");
+assert.commandWorked(res, "1b " + tojson(res));
// -------------------------
// Case 2: entry with null values would make an index suitable
@@ -40,16 +40,16 @@ f.save({x: 1, y: 1});
f.save({x: null, y: 1});
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1}});
-assert.eq(true, res.ok, "2a " + tojson(res));
+assert.commandWorked(res, "2a " + tojson(res));
f.save({y: 2});
assert.eq(3, f.count(), "2. count after initial insert should be 3");
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1}});
-assert.eq(true, res.ok, "2b " + tojson(res));
+assert.commandWorked(res, "2b " + tojson(res));
// Check _id index
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {_id: 1}});
-assert.eq(true, res.ok, "2c " + tojson(res));
+assert.commandWorked(res, "2c " + tojson(res));
assert(res.idskip, "2d " + tojson(res));
// -------------------------
@@ -65,7 +65,7 @@ f.save({x: [1, 2], y: 2});
assert.eq(2, f.count(), "3. count after initial insert should be 2");
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1}});
-assert.eq(false, res.ok, "3a " + tojson(res));
+assert.commandFailed(res, "3a " + tojson(res));
f.remove({y: 2});
f.dropIndex({x: 1, y: 1});
@@ -73,13 +73,13 @@ f.createIndex({x: 1, y: 1});
assert.eq(1, f.count(), "3. count after removing array value should be 1");
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1}});
-assert.eq(true, res.ok, "3b " + tojson(res));
+assert.commandWorked(res, "3b " + tojson(res));
f.save({x: 2, y: [1, 2]});
assert.eq(2, f.count(), "3. count after adding array value should be 2");
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1}});
-assert.eq(false, res.ok, "3c " + tojson(res));
+assert.commandFailed(res, "3c " + tojson(res));
// -------------------------
// Case 4: Handles prefix shard key indexes.
@@ -93,21 +93,21 @@ f.save({x: 1, y: 1, z: 1});
assert.eq(1, f.count(), "4. count after initial insert should be 1");
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1}});
-assert.eq(true, res.ok, "4a " + tojson(res));
+assert.commandWorked(res, "4a " + tojson(res));
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1}});
-assert.eq(true, res.ok, "4b " + tojson(res));
+assert.commandWorked(res, "4b " + tojson(res));
f.save({x: [1, 2], y: 2, z: 2});
assert.eq(2, f.count(), "4. count after adding array value should be 2");
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1}});
-assert.eq(false, res.ok, "4c " + tojson(res));
+assert.commandFailed(res, "4c " + tojson(res));
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1}});
-assert.eq(false, res.ok, "4d " + tojson(res));
+assert.commandFailed(res, "4d " + tojson(res));
res = db.runCommand(
{checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1, z: 1}});
-assert.eq(false, res.ok, "4e " + tojson(res));
+assert.commandFailed(res, "4e " + tojson(res));
f.remove({y: 2});
f.dropIndex({x: 1, y: 1, z: 1});
@@ -116,18 +116,18 @@ f.createIndex({x: 1, y: 1, z: 1});
assert.eq(1, f.count(), "4. count after removing array value should be 1");
res = db.runCommand(
{checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1, z: 1}});
-assert.eq(true, res.ok, "4f " + tojson(res));
+assert.commandWorked(res, "4f " + tojson(res));
f.save({x: 3, y: [1, 2], z: 3});
assert.eq(2, f.count(), "4. count after adding array value on second key should be 2");
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1}});
-assert.eq(false, res.ok, "4g " + tojson(res));
+assert.commandFailed(res, "4g " + tojson(res));
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1}});
-assert.eq(false, res.ok, "4h " + tojson(res));
+assert.commandFailed(res, "4h " + tojson(res));
res = db.runCommand(
{checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1, z: 1}});
-assert.eq(false, res.ok, "4i " + tojson(res));
+assert.commandFailed(res, "4i " + tojson(res));
f.remove({x: 3});
// Necessary so that the index is no longer marked as multikey
@@ -137,18 +137,18 @@ f.createIndex({x: 1, y: 1, z: 1});
assert.eq(1, f.count(), "4. count after removing array value should be 1 again");
res = db.runCommand(
{checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1, z: 1}});
-assert.eq(true, res.ok, "4e " + tojson(res));
+assert.commandWorked(res, "4e " + tojson(res));
f.save({x: 4, y: 4, z: [1, 2]});
assert.eq(2, f.count(), "4. count after adding array value on third key should be 2");
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1}});
-assert.eq(false, res.ok, "4c " + tojson(res));
+assert.commandFailed(res, "4c " + tojson(res));
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1}});
-assert.eq(false, res.ok, "4d " + tojson(res));
+assert.commandFailed(res, "4d " + tojson(res));
res = db.runCommand(
{checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1, z: 1}});
-assert.eq(false, res.ok, "4e " + tojson(res));
+assert.commandFailed(res, "4e " + tojson(res));
// -------------------------
// Test error messages of checkShardingIndex failing:
@@ -157,21 +157,21 @@ assert.eq(false, res.ok, "4e " + tojson(res));
f.drop();
f.createIndex({x: 1});
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {y: 1}});
-assert.eq(false, res.ok);
+assert.commandFailed(res);
assert(res.errmsg.includes("Shard key is not a prefix of index key."));
// Index key is partial:
f.drop();
f.createIndex({x: 1, y: 1}, {partialFilterExpression: {y: {$gt: 0}}});
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1}});
-assert.eq(false, res.ok);
+assert.commandFailed(res);
assert(res.errmsg.includes("Index key is partial."));
// Index key is sparse:
f.drop();
f.createIndex({x: 1, y: 1}, {sparse: true});
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1}});
-assert.eq(false, res.ok);
+assert.commandFailed(res);
assert(res.errmsg.includes("Index key is sparse."));
// Index key is multikey:
@@ -179,21 +179,21 @@ f.drop();
f.createIndex({x: 1, y: 1});
f.save({y: [1, 2, 3, 4, 5]});
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1}});
-assert.eq(false, res.ok);
+assert.commandFailed(res);
assert(res.errmsg.includes("Index key is multikey."));
// Index key has a non-simple collation:
f.drop();
f.createIndex({x: 1, y: 1}, {collation: {locale: "en"}});
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1}});
-assert.eq(false, res.ok);
+assert.commandFailed(res);
assert(res.errmsg.includes("Index has a non-simple collation."));
// Index key is sparse and index has non-simple collation:
f.drop();
f.createIndex({x: 1, y: 1}, {sparse: true, collation: {locale: "en"}});
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1}});
-assert.eq(false, res.ok);
+assert.commandFailed(res);
assert(res.errmsg.includes("Index key is sparse.") &&
res.errmsg.includes("Index has a non-simple collation."));
@@ -203,7 +203,7 @@ f.createIndex({x: 1, y: 1}, {name: "index_1_part", partialFilterExpression: {x:
f.createIndex({x: 1, y: 1}, {name: "index_2"});
f.save({y: [1, 2, 3, 4, 5]});
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1}});
-assert.eq(false, res.ok);
+assert.commandFailed(res);
assert(res.errmsg.includes("Index key is multikey.") &&
res.errmsg.includes("Index key is partial."));
@@ -212,7 +212,7 @@ f.drop();
f.createIndex({x: 1, y: 1}, {name: "index_1_part", partialFilterExpression: {x: {$gt: 0}}});
f.createIndex({x: 1, y: 1}, {name: "index_2_sparse", sparse: true});
res = db.runCommand({checkShardingIndex: "test.jstests_shardingindex", keyPattern: {x: 1, y: 1}});
-assert.eq(false, res.ok);
+assert.commandFailed(res);
assert(res.errmsg.includes("Index key is partial.") && res.errmsg.includes("Index key is sparse."));
print("PASSED");
diff --git a/jstests/core/collmod.js b/jstests/core/collmod.js
index 4362fc110a4..3362650a77a 100644
--- a/jstests/core/collmod.js
+++ b/jstests/core/collmod.js
@@ -131,3 +131,17 @@ assert.commandFailed(
// Fails with an unknown key pattern.
assert.commandFailed(db.runCommand(
{collmod: coll, index: {keyPattern: {doesnotexist: 1}, expireAfterSeconds: 100}}));
+
+// Exclude from multiversion suites as SERVER-84531 will not be backported to older versions
+const isMultiversion = jsTestOptions().mixedBinVersions || jsTestOptions().shardMixedBinVersions ||
+ jsTestOptions().useRandomBinVersionsWithinReplicaSet;
+if (!isMultiversion) {
+ // The timeseriesBucketsMayHaveMixedSchemaData option can only be used on time-series
+ // collections.
+ assert.commandFailedWithCode(
+ db.runCommand({collMod: coll, timeseriesBucketsMayHaveMixedSchemaData: true}),
+ ErrorCodes.InvalidOptions);
+ assert.commandFailedWithCode(
+ db.runCommand({collMod: coll, timeseriesBucketsMayHaveMixedSchemaData: false}),
+ ErrorCodes.InvalidOptions);
+}
diff --git a/jstests/core/command_let_variables_expressions.js b/jstests/core/command_let_variables_expressions.js
new file mode 100644
index 00000000000..c551c30be48
--- /dev/null
+++ b/jstests/core/command_let_variables_expressions.js
@@ -0,0 +1,208 @@
+// Tests that commands like find, aggregate and update accept a 'let' parameter which defines
+// variables for use in expressions within the command. Specifically covers cases where the
+// parameter definitions contain expressions.
+// @tags: [
+// requires_non_retryable_writes,
+// does_not_support_transactions,
+// tenant_migration_incompatible
+// ]
+(function() {
+"use strict";
+
+load('jstests/aggregation/extras/utils.js'); // For assertArrayEq().
+
+const coll = db.getCollection('command_let_variables_expressions');
+
+function setupColl() {
+ coll.drop();
+ assert.commandWorked(coll.insert([
+ {_id: 2, a: {}},
+ {_id: 3, b: 1},
+ {_id: 4, a: "$notAFieldPath"},
+ ]));
+}
+setupColl();
+
+const missingLetParam = {
+ $getField: {field: "c", input: {a: 1}}
+};
+const literalLetParam = {
+ $literal: "$notAFieldPath"
+};
+
+// Run find commands with 'let' parameters containing expressions.
+{
+ // 'let' parameter expression that resolves to a missing value should not cause a query error.
+ let result = assert.commandWorked(db.runCommand({
+ find: coll.getName(),
+ filter: {$expr: {$eq: ["$a", "$$c"]}},
+ let : {c: missingLetParam},
+ }));
+ assertArrayEq({
+ actual: result.cursor.firstBatch,
+ expected: [{_id: 3, b: 1}],
+ });
+
+ // 'let' parameter expression that includes $literal and a $-prefixed string should not be
+ // misinterpreted as a field path.
+ result = assert.commandWorked(db.runCommand({
+ find: coll.getName(),
+ filter: {$expr: {$eq: ["$a", "$$c"]}},
+ let : {c: literalLetParam},
+ }));
+ assertArrayEq({
+ actual: result.cursor.firstBatch,
+ expected: [{_id: 4, a: "$notAFieldPath"}],
+ });
+}
+
+// Run aggregate commands with 'let' parameters containing expressions.
+{
+ let result =
+ coll.aggregate([{$match: {$expr: {$eq: ["$a", "$$c"]}}}], {let : {c: missingLetParam}})
+ .toArray();
+ assertArrayEq({
+ actual: result,
+ expected: [{_id: 3, b: 1}],
+ });
+
+ result = coll.aggregate([{$match: {$expr: {$eq: ["$a", "$$c"]}}}], {let : {c: literalLetParam}})
+ .toArray();
+ assertArrayEq({
+ actual: result,
+ expected: [{_id: 4, a: "$notAFieldPath"}],
+ });
+}
+
+// Same thing but for update.
+{
+ assert.commandWorked(db.runCommand({
+ update: coll.getName(),
+ updates: [{
+ q: {$expr: {$eq: ["$a", "$$c"]}},
+ u: [{$set: {c: "updated"}}],
+ multi: true,
+ }],
+ let : {c: missingLetParam}
+ }));
+ assertArrayEq({
+ actual: coll.find().toArray(),
+ expected: [{_id: 2, a: {}}, {_id: 3, b: 1, c: "updated"}, {_id: 4, a: "$notAFieldPath"}],
+ });
+
+ // Undo changes.
+ setupColl();
+
+ assert.commandWorked(db.runCommand({
+ update: coll.getName(),
+ updates: [{
+ q: {$expr: {$eq: ["$a", "$$c"]}},
+ u: [{$set: {c: "updated"}}],
+ multi: true,
+ }],
+ let : {c: literalLetParam}
+ }));
+ assertArrayEq({
+ actual: coll.find().toArray(),
+ expected: [
+ {_id: 2, a: {}},
+ {_id: 3, b: 1},
+ {_id: 4, a: "$notAFieldPath", c: "updated"},
+ ],
+ });
+}
+
+// Run findAndModify commands with 'let' parameters containing expressions.
+{
+ setupColl();
+
+ assert.commandWorked(db.runCommand({
+ findAndModify: coll.getName(),
+ query: {_id: 3, $expr: {$eq: ["$a", "$$c"]}},
+ update: [{$set: {c: "updated"}}],
+ let : {c: missingLetParam}
+ }));
+ assertArrayEq({
+ actual: coll.find().toArray(),
+ expected: [{_id: 2, a: {}}, {_id: 3, b: 1, c: "updated"}, {_id: 4, a: "$notAFieldPath"}],
+ });
+
+ // Undo changes.
+ setupColl();
+
+ assert.commandWorked(db.runCommand({
+ findAndModify: coll.getName(),
+ query: {_id: 4, $expr: {$eq: ["$a", "$$c"]}},
+ update: [{$set: {c: "updated"}}],
+ let : {c: literalLetParam}
+ }));
+ assertArrayEq({
+ actual: coll.find().toArray(),
+ expected: [
+ {_id: 2, a: {}},
+ {_id: 3, b: 1},
+ {_id: 4, a: "$notAFieldPath", c: "updated"},
+ ],
+ });
+}
+
+// Run delete commands with 'let' parameters containing expressions.
+{
+ setupColl();
+
+ assert.commandWorked(db.runCommand({
+ delete: coll.getName(),
+ deletes: [{
+ q: {$expr: {$eq: ["$a", "$$c"]}},
+ limit: 0, // multi
+ }],
+ let : {c: missingLetParam}
+ }));
+ assertArrayEq({
+ actual: coll.find().toArray(),
+ expected: [{_id: 2, a: {}}, {_id: 4, a: "$notAFieldPath"}],
+ });
+
+ // Undo changes.
+ setupColl();
+
+ assert.commandWorked(db.runCommand({
+ delete: coll.getName(),
+ deletes: [{
+ q: {$expr: {$eq: ["$a", "$$c"]}},
+ limit: 0, // multi
+ }],
+ let : {c: literalLetParam}
+ }));
+ assertArrayEq({
+ actual: coll.find().toArray(),
+ expected: [{_id: 2, a: {}}, {_id: 3, b: 1}],
+ });
+}
+
+// Run a $lookup with let/pipeline syntax. In sharded environments, this will require serializing
+// 'let' variables to send to the shards. One of the documents in the collection is missing the
+// local field ("$a"), which will cause a missing 'let' variable to be serialized.
+{
+ setupColl();
+
+ const result = coll.aggregate([
+ {
+ $lookup: {
+ from: coll.getName(),
+ as: "res",
+ let: {local_a: "$a"},
+ pipeline: [{$match: {$expr: {$eq: ["$$local_a", "$a"]},}}, {$project: {_id: 1}}]
+ }
+ }
+ ]).toArray();
+ assertArrayEq({
+ actual: result,
+ expected: [
+ {_id: 2, a: {}, res: [{_id: 2}]},
+ {_id: 3, b: 1, res: [{_id: 3}]},
+ {_id: 4, a: "$notAFieldPath", res: [{_id: 4}]},
+ ],
+ });
+}
+}());
diff --git a/jstests/core/currentop_shell.js b/jstests/core/currentop_shell.js
index c96ef2507f1..31b084bf132 100644
--- a/jstests/core/currentop_shell.js
+++ b/jstests/core/currentop_shell.js
@@ -2,7 +2,16 @@
* Tests that the shell helper db.currentOpCursor isn't constrained by the legacy currentOp server
* command - ie. the result set isn't limited to 16MB and long operations aren't truncated.
*
+ * Note: On newer branches, this test contains additional cases for the currentOp command (without a
+ * shell helper) and the $currentOp pipeline stage, which are not included here. Those cases would
+ * behave unreliably because of SERVER-92284.
+ *
* @tags: [
+ * # The collection may be completely moved to another shard, which results in currentOp not
+ * # returning the expected command.
+ * assumes_balancer_off,
+ * # The test runs commands that are not allowed with security token: getLog.
+ * not_allowed_with_signed_security_token,
* uses_parallel_shell,
* # This test uses currentOp to check whether an aggregate command is running. In replica set
* # environments, because currentOp is run against the admin database it is routed to the
@@ -11,6 +20,8 @@
* # currentOp results.
* assumes_read_preference_unchanged,
* no_selinux,
+ * # Uses $function operator.
+ * requires_scripting,
* ]
*/
@@ -18,31 +29,45 @@
"use strict";
load("jstests/libs/fixture_helpers.js"); // for FixtureHelpers
+load('jstests/libs/parallel_shell_helpers.js');
const coll = db.currentOp_cursor;
coll.drop();
-for (let i = 0; i < 3; i++) {
+for (let i = 0; i < 100; i++) {
assert.commandWorked(coll.insert({val: 1}));
}
+//
// Test that db.currentOpCursor() returns an iterable cursor.
-let res = db.currentOpCursor();
-assert(res.hasNext());
-assert(res.next());
-
-// Test that db.currentOp() interface does not change.
-res = db.currentOp();
-assert("inprog" in res, "Result contains 'inprog' field");
-assert("ok" in res, "Result contains 'ok' field");
-
-// Attempting to access the fsyncLock field from the results throws with an error message.
-let error = assert.throws(() => res.fsyncLock);
+//
+const cursorFromCurrentOp = db.currentOpCursor();
+assert(cursorFromCurrentOp.hasNext());
+assert(cursorFromCurrentOp.next());
+
+//
+// Test that db.currentOp() returns an object in the expected format.
+//
+const currentOpRes = db.currentOp();
+assert("inprog" in currentOpRes, "Result contains 'inprog' field");
+assert("ok" in currentOpRes, "Result contains 'ok' field");
+
+//
+// Test that attempting to access the fsyncLock field from the results throws with an error message.
+//
+const error = assert.throws(() => currentOpRes.fsyncLock);
assert(
/fsyncLock is no longer included in the currentOp shell helper, run db\.runCommand\({currentOp: 1}\) instead/
.test(error));
-function shellOp() {
+//
+// Start a pipeline with a large command object in a parallel shell and then test three different
+// methods of executing "currentOp" queries to ensure that they all observe the operation and that
+// they do or do not truncate its command object (according to each one's specification).
+//
+
+// Starts the query. Intended to b e called from a parallel shell.
+function startLongRunningAggregation(collName, comment) {
function createLargeDoc() {
let doc = {};
for (let i = 0; i < 100; i++) {
@@ -52,90 +77,96 @@ function shellOp() {
}
assert.commandFailedWithCode(db.runCommand({
- aggregate: "currentOp_cursor",
+ aggregate: collName,
pipeline: [{
$addFields: {
newVal: {$function: {args: [], body: "sleep(1000000)", lang: "js"}},
bigDoc: createLargeDoc()
}
}],
- comment: TestData.comment,
+ comment: comment,
cursor: {}
}),
ErrorCodes.Interrupted);
}
-function startShellWithOp(comment) {
- TestData.comment = comment;
- const awaitShell = startParallelShell(shellOp);
-
- // Confirm that the operation has started in the parallel shell.
+// Repeatedly executes 'getOperationsFunction()' until it returns exactly one operation for each
+// shard in a sharded collection or exactly one operation for an unsharded collection.
+function awaitOperations(getOperationsFunction) {
+ let operations;
assert.soon(
function() {
- let aggRes =
- db.getSiblingDB("admin")
- .aggregate([
- {$currentOp: {}},
- {$match: {ns: "test.currentOp_cursor", "command.comment": TestData.comment}}
- ])
- .toArray();
- return aggRes.length >= 1;
+ const numShards = FixtureHelpers.numberOfShardsForCollection(coll);
+ operations = getOperationsFunction();
+
+ // No shard should have more than one operation matching the query comment. First check
+ // that the total number of operations is no greater than the total number of shards.
+ assert.lte(operations.length, numShards, operations);
+
+ // Also explicitly check that each shard appears no more than once in the list of
+ // operations.
+ const distinctShardNames = new Set(operations.map(op => "shard" in op ? op.shard : ""));
+ assert.eq(operations.length, distinctShardNames.size, {operations, numShards});
+
+ if (operations.length < numShards) {
+ print(`Found ${operations.length} operation(s); waiting until there are ${
+ numShards} operation(s)`);
+ return false;
+ } else if (operations.some(op => op.op !== "getmore" && "cursor" in op &&
+ op.cursor.batchSize === 0)) {
+ print(`Found command with empty 'batchSize' value; waiting for getmore: ${
+ tojson(operations)}`);
+ return false;
+ }
+
+ return true;
},
function() {
return "Failed to find parallel shell operation in $currentOp output: " +
tojson(db.currentOp());
});
- return awaitShell;
-}
-// Test that the currentOp server command truncates long operations with a warning logged.
-const serverCommandTest = startShellWithOp("currentOp_server");
-res = db.adminCommand({
- currentOp: true,
- $and: [{"ns": "test.currentOp_cursor"}, {"command.comment": "currentOp_server"}]
-});
+ return operations;
+}
-if (FixtureHelpers.isMongos(db) && FixtureHelpers.isSharded(coll)) {
- // Assert currentOp truncation behavior for each shard in the cluster.
- assert(res.inprog.length >= 1, res);
- res.inprog.forEach((result) => {
- assert.eq(result.op, "getmore", result);
- assert(result.cursor.originatingCommand.hasOwnProperty("$truncated"), result);
- });
-} else {
- // Assert currentOp truncation behavior for unsharded collections.
- assert.eq(res.inprog.length, 1, res);
- assert.eq(res.inprog[0].op, "command", res);
- assert(res.inprog[0].command.hasOwnProperty("$truncated"), res);
+function getCommandFromCurrentOpEntry(entry) {
+ if (entry.op === "command" && "command" in entry) {
+ return entry.command;
+ } else if (entry.op === "getmore" && "cursor" in entry &&
+ "originatingCommand" in entry.cursor) {
+ return entry.cursor.originatingCommand;
+ } else {
+ assert(false, entry);
+ }
}
-const log = FixtureHelpers.getPrimaryForNodeHostingDatabase(db).adminCommand({getLog: "global"});
-assert(/will be truncated/.test(log.log));
+const comment = "long_running_aggregation";
+const awaitShell =
+ startParallelShell(funWithArgs(startLongRunningAggregation, coll.getName(), comment));
-res.inprog.forEach((op) => {
- assert.commandWorked(db.killOp(op.opid));
-});
+const filter = {
+ ns: coll.getFullName(),
+ "command.comment": comment,
-serverCommandTest();
-
-// Test that the db.currentOp() shell helper does not truncate ops.
-const shellHelperTest = startShellWithOp("currentOp_shell");
-res = db.currentOp({"ns": "test.currentOp_cursor", "command.comment": "currentOp_shell"});
-
-if (FixtureHelpers.isMongos(db) && FixtureHelpers.isSharded(coll)) {
- assert(res.inprog.length >= 1, res);
- res.inprog.forEach((result) => {
- assert.eq(result.op, "getmore", result);
- assert(!result.cursor.originatingCommand.hasOwnProperty("$truncated"), result);
- });
-} else {
- assert.eq(res.inprog.length, 1, res);
- assert(!res.inprog[0].command.hasOwnProperty("$truncated"), res);
-}
+ // On the replica set endpoint, currentOp reports both router and shard operations. So filter
+ // out one of them.
+ role: TestData.testingReplicaSetEndpoint ? "ClusterRole{router}" : {$exists: false}
+};
-res.inprog.forEach((op) => {
- assert.commandWorked(db.killOp(op.opid));
+// The 'currentOp' shell helper should _not_ truncate the command.
+const operationsViaCurrentOpShellHelper = awaitOperations(function() {
+ return db.currentOp(filter).inprog;
});
-
-shellHelperTest();
+assert(operationsViaCurrentOpShellHelper.every(op => {
+ const command = getCommandFromCurrentOpEntry(op);
+ return !("$truncated" in command) && command.aggregate == coll.getName();
+}),
+ operationsViaCurrentOpShellHelper);
+
+// Finish the test by killing the long-running aggregation pipeline and joining the parallel shell
+// that launched it.
+for (let op of operationsViaCurrentOpShellHelper) {
+ assert.commandWorked(db.killOp(op.opid));
+}
+awaitShell();
})();
diff --git a/jstests/core/elemmatch_index.js b/jstests/core/elemmatch_index.js
index a1941620a48..f0aaf35cdba 100644
--- a/jstests/core/elemmatch_index.js
+++ b/jstests/core/elemmatch_index.js
@@ -80,6 +80,12 @@ assertIndexResults(coll, {a: {$elemMatch: {"": {$elemMatch: {"b.c": "x"}}}}}, fa
// Tests $elemMatch with supporting index and no path components that are empty strings.
assertIndexResults(coll, {a: {$elemMatch: {"b.c": "x"}}}, true, 1);
assertIndexResults(coll, {a: {$all: [{$elemMatch: {"b.c": "x"}}]}}, true, 1);
+
+// Tests that $elemMatch with path components that are empty strings are correctly handled in the
+// plan enumerator in case if an index is used on another predicate of the query.
+assertIndexResults(coll, {$and: [{"a.b.c": "x"}, {"": {$elemMatch: {"a.b.c": "x"}}}]}, true, 0);
+
+assertIndexResults(coll, {$and: [{"a.b.c": "x"}, {"a.b.c": {$elemMatch: {"": "x"}}}]}, true, 0);
})();
(function() {
diff --git a/jstests/core/empty_ts.js b/jstests/core/empty_ts.js
new file mode 100644
index 00000000000..926de0fd790
--- /dev/null
+++ b/jstests/core/empty_ts.js
@@ -0,0 +1,134 @@
+/**
+ * Test how inserts and updates behave with "Timestamp(0,0)" values.
+ *
+ * @tags: [
+ * requires_fcv_60,
+ * ]
+ */
+(function() {
+"use strict";
+
+const coll = db.jstests_core_empty_ts;
+const emptyTs = Timestamp(0, 0);
+
+coll.drop();
+
+// Insert several documents. For the first document inserted (_id=101), the empty timestamp value
+// in field "a" should get replaced with the current timestamp.
+assert.commandWorked(coll.insert({_id: 101, a: emptyTs}));
+assert.commandWorked(coll.insert({_id: 102, a: 1}));
+assert.commandWorked(coll.insert({_id: 103, a: 2}));
+assert.commandWorked(coll.insert({_id: 106, a: 3}));
+assert.commandWorked(coll.insert({_id: 107, a: 4}));
+assert.commandWorked(coll.insert({_id: 108, a: 5}));
+assert.commandWorked(coll.insert({_id: 109, a: 6}));
+assert.commandWorked(coll.insert({_id: 110, a: 7}));
+assert.commandWorked(coll.insert({_id: 111, a: 8}));
+
+// Use a replacement-style update to update _id=102. This should result in field "a" being set to
+// the current timestamp.
+//
+// This is an example of how the special "empty timestamp" behavior works with a replacement-style
+// update.
+assert.commandWorked(coll.update({_id: 102}, {a: emptyTs}));
+
+// Use a replacement-style findAndModify to update _id=103. This should result in field "a" being
+// set to the current timestamp.
+let findAndModifyResult = coll.findAndModify({query: {_id: 103}, update: {a: emptyTs}});
+assert.eq(findAndModifyResult, {_id: 103, a: 2});
+
+// Do a replacement-style update to add a new document with _id=104. This should result in field "a"
+// being set to the current timestamp.
+assert.commandWorked(coll.update({_id: 104}, {a: emptyTs}, {upsert: true}));
+
+// Do a replacement-style findAndModify to add a new document with _id=105. This should result in
+// field "a" being set to the current timestamp.
+findAndModifyResult = coll.findAndModify({query: {_id: 105}, update: {a: emptyTs}, upsert: true});
+assert.eq(findAndModifyResult, null);
+
+// For the rest of the commands below, the empty timestamp values stored in field "a" should be
+// preserved as-is.
+
+// Do an update-operator-style update to update _id=106.
+assert.commandWorked(coll.update({_id: 106}, {$set: {a: emptyTs}}));
+
+// Do an update-operator-style findAndModify to update _id=107.
+findAndModifyResult = coll.findAndModify({query: {_id: 107}, update: {$set: {a: emptyTs}}});
+assert.eq(findAndModifyResult, {_id: 107, a: 4});
+
+// Do a pipeline-style update to update _id=108.
+assert.commandWorked(coll.update({_id: 108}, [{$addFields: {a: emptyTs}}]));
+
+// Do a pipeline-style findAndModify to update _id=109.
+findAndModifyResult = coll.findAndModify({query: {_id: 109}, update: [{$addFields: {a: emptyTs}}]});
+assert.eq(findAndModifyResult, {_id: 109, a: 6});
+
+// Do a pipeline-style update with $internalApplyOplogUpdate to update _id=110.
+assert.commandWorked(coll.update(
+ {_id: 110}, [{$_internalApplyOplogUpdate: {oplogUpdate: {$v: 2, diff: {i: {a: emptyTs}}}}}]));
+
+// Do a pipeline-style findAndModify with $internalApplyOplogUpdate to update _id=111.
+findAndModifyResult = coll.findAndModify({
+ query: {_id: 111},
+ update: [{$_internalApplyOplogUpdate: {oplogUpdate: {$v: 2, diff: {i: {a: emptyTs}}}}}]
+});
+assert.eq(findAndModifyResult, {_id: 111, a: 8});
+
+// Do an update-operator-style update to add a new document with _id=112.
+assert.commandWorked(coll.update({_id: 112}, {$set: {a: emptyTs}}, {upsert: true}));
+
+// Do an update-operator-style findAndModify to add a new document with _id=113.
+findAndModifyResult =
+ coll.findAndModify({query: {_id: 113}, update: {$set: {a: emptyTs}}, upsert: true});
+assert.eq(findAndModifyResult, null);
+
+// Do a pipeline-style update to add a new document with _id=114.
+assert.commandWorked(coll.update({_id: 114}, [{$addFields: {a: emptyTs}}], {upsert: true}));
+
+// Do a pipeline-style findAndModify to add a new document with _id=115.
+findAndModifyResult =
+ coll.findAndModify({query: {_id: 115}, update: [{$addFields: {a: emptyTs}}], upsert: true});
+assert.eq(findAndModifyResult, null);
+
+// Do a pipline-style update with $internalApplyOplogUpdate to add a new document _id=116.
+assert.commandWorked(
+ coll.update({_id: 116},
+ [{$_internalApplyOplogUpdate: {oplogUpdate: {$v: 2, diff: {i: {a: emptyTs}}}}}],
+ {upsert: true}));
+
+// Do pipeline-style findAndModify with $internalApplyOplogUpdate to add a new document _id=117.
+findAndModifyResult = coll.findAndModify({
+ query: {_id: 117},
+ update: [{$_internalApplyOplogUpdate: {oplogUpdate: {$v: 2, diff: {i: {a: emptyTs}}}}}],
+ upsert: true
+});
+assert.eq(findAndModifyResult, null);
+
+// Verify that all the insert, update, and findAndModify commands behaved the way we expected.
+for (let i = 101; i <= 117; ++i) {
+ let result = coll.findOne({_id: i});
+
+ if (i >= 106) {
+ assert.eq(tojson(result.a), tojson(emptyTs), "_id=" + i);
+ } else {
+ assert.neq(tojson(result.a), tojson(emptyTs), "_id=" + i);
+ }
+}
+
+// Insert a document with _id=Timestamp(0,0).
+assert.commandWorked(coll.insert({_id: emptyTs, a: 9}));
+
+// Verify the document we just inserted can be retrieved using the filter "{_id: Timestamp(0,0)}".
+let result = coll.findOne({_id: emptyTs});
+assert.eq(tojson(result._id), tojson(emptyTs), "_id=" + tojson(emptyTs));
+assert.eq(tojson(result.a), tojson(9), "_id=" + tojson(emptyTs));
+
+// Do a replacement-style update on the document.
+assert.commandWorked(coll.update({_id: emptyTs}, {_id: emptyTs, a: emptyTs}));
+
+// Verify the document we just updated can still be retrieved using "{_id: Timestamp(0,0)}", and
+// verify that field "a" was set to the current timestamp.
+result = coll.findOne({_id: emptyTs});
+assert.eq(tojson(result._id), tojson(emptyTs), "_id=" + tojson(emptyTs));
+assert.neq(tojson(result.a), tojson(emptyTs), "_id=" + tojson(emptyTs));
+}());
diff --git a/jstests/core/explain_agg_write_concern.js b/jstests/core/explain_agg_write_concern.js
index 9ff556489fa..ec246140abe 100644
--- a/jstests/core/explain_agg_write_concern.js
+++ b/jstests/core/explain_agg_write_concern.js
@@ -5,6 +5,7 @@
// assumes_unsharded_collection,
// assumes_write_concern_unchanged,
// does_not_support_stepdowns,
+// references_foreign_collection,
// requires_non_retryable_commands,
// ]
diff --git a/jstests/core/explain_skip.js b/jstests/core/explain_skip.js
new file mode 100644
index 00000000000..b6e01d6a436
--- /dev/null
+++ b/jstests/core/explain_skip.js
@@ -0,0 +1,28 @@
+/**
+ * Tests that explain reports the skip stage statistics correctly.
+ *
+ * @tags: [
+ * assumes_unsharded_collection,
+ * assumes_against_mongod_not_mongos,
+ * ]
+ */
+load("jstests/libs/analyze_plan.js"); // For getWinningPlan.
+
+var coll = db.explain_skip;
+coll.drop();
+
+assert.commandWorked(coll.insert({a: 1, b: 1}));
+assert.commandWorked(coll.insert({a: 1, b: 2}));
+assert.commandWorked(coll.insert({a: 1, b: 3}));
+assert.commandWorked(coll.insert({a: 2, b: 1}));
+assert.commandWorked(coll.insert({a: 2, b: 2}));
+assert.commandWorked(coll.insert({a: 2, b: 3}));
+
+assert.commandWorked(coll.createIndex({a: 1}));
+assert.commandWorked(coll.createIndex({b: 1}));
+
+var explain = coll.find({a: 1, b: 1}).sort({_id: 1}).skip(5).explain();
+var winningPlan = getWinningPlan(explain.queryPlanner);
+var skipStage = getPlanStage(winningPlan, "SKIP");
+assert.neq(null, skipStage, explain);
+assert.eq(5, skipStage.skipAmount, explain);
diff --git a/jstests/core/fts_mix.js b/jstests/core/fts_mix.js
index 5942a85ec2c..f8bf850fb29 100644
--- a/jstests/core/fts_mix.js
+++ b/jstests/core/fts_mix.js
@@ -1,4 +1,3 @@
-
(function() {
load("jstests/libs/fts.js");
load("jstests/aggregation/extras/utils.js"); // For resultsEq.
diff --git a/jstests/core/index_filter_commands.js b/jstests/core/index_filter_commands.js
index 6c5ff8920c8..6e5f5c5726a 100644
--- a/jstests/core/index_filter_commands.js
+++ b/jstests/core/index_filter_commands.js
@@ -30,7 +30,8 @@
* assumes_read_preference_unchanged,
* assumes_unsharded_collection,
* does_not_support_stepdowns,
- * requires_fcv_60
+ * requires_fcv_60,
+ * references_foreign_collection,
* ]
*/
diff --git a/jstests/core/index_stats.js b/jstests/core/index_stats.js
index ce5c9901e48..b0abd2e35a1 100644
--- a/jstests/core/index_stats.js
+++ b/jstests/core/index_stats.js
@@ -12,6 +12,7 @@
// # Tenant migrations passthrough suites automatically retry operations on TenantMigrationAborted
// # errors.
// tenant_migration_incompatible,
+// references_foreign_collection,
// ]
(function() {
diff --git a/jstests/core/json_schema/json_schema.js b/jstests/core/json_schema/json_schema.js
index c1e06344498..a69db77c60d 100644
--- a/jstests/core/json_schema/json_schema.js
+++ b/jstests/core/json_schema/json_schema.js
@@ -1,7 +1,7 @@
// listCollections tests expect that a collection is not implicitly created after a drop.
// @tags: [
// assumes_no_implicit_collection_creation_after_drop,
-// requires_non_retryable_commands,
+// requires_non_retryable_commands
// ]
/**
diff --git a/jstests/core/json_schema/misc_validation.js b/jstests/core/json_schema/misc_validation.js
index 58e76fc0d68..569d98be258 100644
--- a/jstests/core/json_schema/misc_validation.js
+++ b/jstests/core/json_schema/misc_validation.js
@@ -19,6 +19,7 @@
* requires_replication,
* # This test depends on hardcoded database name equality.
* tenant_migration_incompatible,
+ * references_foreign_collection,
* ]
*/
(function() {
diff --git a/jstests/core/negated_geo_queries.js b/jstests/core/negated_geo_queries.js
new file mode 100644
index 00000000000..e6c0cfbbf03
--- /dev/null
+++ b/jstests/core/negated_geo_queries.js
@@ -0,0 +1,93 @@
+/**
+ * With a normal ascending index on a geospatial field, {$not: {$geoWithin: <>}} and
+ * {$not: {$geoIntersects: <>}} queries should return proper results. Previously, those queries
+ * failed due to attempting to build geospatial index bounds on the non-geo index. See SERVER-92193
+ * for more details.
+ */
+(function() {
+"use strict";
+
+const coll = db.negated_geo_queries;
+coll.drop();
+
+assert.commandWorked(coll.insert(
+ {loc: {type: "Polygon", coordinates: [[[0, 0], [0, 1], [1, 1], [1, 0], [0, 0]]]}, a: 0}));
+assert.commandWorked(coll.insert(
+ {loc: {type: "Polygon", coordinates: [[[30, 0], [30, 1], [32, 1], [32, 0], [30, 0]]]}, a: 0}));
+assert.commandWorked(coll.insert(
+ {loc: {type: "Polygon", coordinates: [[[-55, 10], [-35, 15], [-45, 10], [-55, 10]]]}, a: 1}));
+
+const targetPolygonWithin = {
+ type: "Polygon",
+ coordinates: [[[-5, -5], [5, -5], [5, 5], [-5, 5], [-5, -5]]]
+};
+
+const targetLineIntersect = {
+ type: "LineString",
+ coordinates: [[29, -1], [31, 1]]
+};
+
+function runTest() {
+ // Tests $geoWithin.
+ let geoQuery = {loc: {$geoWithin: {$geometry: targetPolygonWithin}}};
+ let res = coll.find(geoQuery);
+ assert.eq(res.itcount(), 1);
+
+ // Tests $geoWithin under a $not.
+ geoQuery = {loc: {$not: {$geoWithin: {$geometry: targetPolygonWithin}}}};
+ res = coll.find(geoQuery);
+ assert.eq(res.itcount(), 2);
+
+ // Tests $geoIntersects.
+ geoQuery = {loc: {$geoIntersects: {$geometry: targetLineIntersect}}};
+ res = coll.find(geoQuery);
+ assert.eq(res.itcount(), 1);
+
+ // Tests $geoIntersects under a $not.
+ geoQuery = {loc: {$not: {$geoIntersects: {$geometry: targetLineIntersect}}}};
+ res = coll.find(geoQuery);
+ assert.eq(res.itcount(), 2);
+
+ // Tests an $and of the negated $geoWithin and negated $geoIntersects.
+ geoQuery = {
+ $and: [
+ {loc: {$not: {$geoWithin: {$geometry: targetPolygonWithin}}}},
+ {loc: {$not: {$geoIntersects: {$geometry: targetLineIntersect}}}}
+ ]
+ };
+ res = coll.find(geoQuery);
+ assert.eq(res.itcount(), 1);
+
+ // Tests the same logic as above written with a $nor.
+ geoQuery = {
+ $nor: [
+ {loc: {$geoWithin: {$geometry: targetPolygonWithin}}},
+ {loc: {$geoIntersects: {$geometry: targetLineIntersect}}}
+ ]
+ };
+ res = coll.find(geoQuery);
+ assert.eq(res.itcount(), 1);
+
+ // Tests an $and of the negated $geoWithin and an expression on a non-geo field.
+ geoQuery = {$and: [{loc: {$not: {$geoWithin: {$geometry: targetPolygonWithin}}}}, {a: 0}]};
+ res = coll.find(geoQuery);
+ assert.eq(res.itcount(), 1);
+
+ // Tests an $and of the negated $geoIntersects and an expression on a non-geo field.
+ geoQuery = {$and: [{loc: {$not: {$geoIntersects: {$geometry: targetLineIntersect}}}}, {a: 0}]};
+ res = coll.find(geoQuery);
+ assert.eq(res.itcount(), 1);
+}
+
+// Run test with just a simple btree index.
+assert.commandWorked(coll.createIndex({loc: 1}));
+runTest();
+
+// Run test with a simple btree index and a geo index.
+assert.commandWorked(coll.createIndex({loc: "2dsphere"}));
+runTest();
+
+// Run test with just a geo index.
+assert.commandWorked(coll.dropIndex({loc: 1}));
+runTest();
+})();
diff --git a/jstests/core/opcounters_write_cmd.js b/jstests/core/opcounters_write_cmd.js
index 6f74185e9f7..9e0d68cd928 100644
--- a/jstests/core/opcounters_write_cmd.js
+++ b/jstests/core/opcounters_write_cmd.js
@@ -2,6 +2,7 @@
// @tags: [
// uses_multiple_connections,
// assumes_standalone_mongod,
+// inspects_command_opcounters,
// ]
// Legacy write mode test also available at jstests/gle.
diff --git a/jstests/core/plan_cache_list_plans.js b/jstests/core/plan_cache_list_plans.js
index ca571a9e39e..802a25635e0 100644
--- a/jstests/core/plan_cache_list_plans.js
+++ b/jstests/core/plan_cache_list_plans.js
@@ -12,6 +12,7 @@
// assumes_unsharded_collection,
// does_not_support_stepdowns,
// inspects_whether_plan_cache_entry_is_active,
+// references_foreign_collection,
// ]
(function() {
diff --git a/jstests/core/profile_agg.js b/jstests/core/profile_agg.js
index d6611fa98ab..b1ce28dd696 100644
--- a/jstests/core/profile_agg.js
+++ b/jstests/core/profile_agg.js
@@ -1,6 +1,7 @@
// @tags: [
// does_not_support_stepdowns,
// requires_profiling,
+// references_foreign_collection,
// ]
// Confirms that profiled aggregation execution contains all expected metrics with proper values.
diff --git a/jstests/core/query/find_all_values_at_path_expression.js b/jstests/core/query/find_all_values_at_path_expression.js
new file mode 100644
index 00000000000..22a26c593ed
--- /dev/null
+++ b/jstests/core/query/find_all_values_at_path_expression.js
@@ -0,0 +1,33 @@
+/**
+ * Tests that $_internalFindAllValuesAtPath asserts when provided a non-string input.
+ */
+const coll = db.find_all_values_at_path_expression;
+coll.drop();
+
+// In query stats, this fails with a different error code.
+const errorCodes = [9567004, 9423101];
+
+// Insert some documents because running aggregation on a non-existent collection on mongos will
+// return empty instead of erroring.
+let documents = [{a: 4}, {a: 5, b: 1}, {a: 0, b: 1}, {a: 0, b: 1}, {a: 2, b: {c: 1}}];
+assert.commandWorked(coll.insert(documents));
+assert.commandFailedWithCode(db.runCommand({
+ aggregate: coll.getName(),
+ pipeline: [
+ {$replaceRoot: {newRoot: {$_internalFindAllValuesAtPath: null}}},
+ {$unwind: {path: "$_internalUnwoundField", preserveNullAndEmptyArrays: true}},
+ {$group: {_id: null, distinct: {$addToSet: "$<key>"}}}
+ ],
+ cursor: {}
+}),
+ errorCodes);
+assert.commandFailedWithCode(db.runCommand({
+ aggregate: coll.getName(),
+ pipeline: [
+ {$replaceRoot: {newRoot: {$_internalFindAllValuesAtPath: 12345}}},
+ {$unwind: {path: "$_internalUnwoundField", preserveNullAndEmptyArrays: true}},
+ {$group: {_id: null, distinct: {$addToSet: "$<key>"}}}
+ ],
+ cursor: {}
+}),
+ errorCodes);
diff --git a/jstests/core/query/internal_strip_invalid_assignment.js b/jstests/core/query/internal_strip_invalid_assignment.js
index 4385e6730a4..b8868c6e951 100644
--- a/jstests/core/query/internal_strip_invalid_assignment.js
+++ b/jstests/core/query/internal_strip_invalid_assignment.js
@@ -3,6 +3,11 @@
* assertion failure when we strip its index assignment from special indexes.
*
* Originally intended to reproduce SERVER-82717.
+ *
+ * @tags: [
+ * # Explain command does not support read concerns other than local.
+ * assumes_read_concern_local,
+ * ]
*/
(function() {
load('jstests/libs/analyze_plan.js'); // for planHasStage
diff --git a/jstests/core/rename_collection_system_db.js b/jstests/core/rename_collection_system_db.js
index 8d46ad27a04..e9e166914c0 100644
--- a/jstests/core/rename_collection_system_db.js
+++ b/jstests/core/rename_collection_system_db.js
@@ -16,10 +16,9 @@ systemUsers.drop();
coll.drop();
coll.insert({});
-// system.foo isn't in the allowlist so it can't be renamed to or from
+// system.foo and system.users aren't in the allowlist so they can't be renamed to or from
assert.commandFailed(coll.renameCollection(systemFoo.getName()));
assert.commandFailed(systemFoo.renameCollection(coll.getName()));
-// system.users is allowlisted so these should work
-assert.commandWorked(coll.renameCollection(systemUsers.getName()));
-assert.commandWorked(systemUsers.renameCollection(coll.getName()));
+assert.commandFailed(coll.renameCollection(systemUsers.getName()));
+assert.commandFailed(systemUsers.renameCollection(coll.getName()));
diff --git a/jstests/core/timeseries/libs/timeseries.js b/jstests/core/timeseries/libs/timeseries.js
index d9e22926520..540e0bcea55 100644
--- a/jstests/core/timeseries/libs/timeseries.js
+++ b/jstests/core/timeseries/libs/timeseries.js
@@ -11,6 +11,20 @@ var TimeseriesTest = class {
return FeatureFlagUtil.isEnabled(conn, "TimeseriesBucketCompression");
}
+ static bucketsMayHaveMixedSchemaData(coll) {
+ const catalog = coll.aggregate([{$listCatalog: {}}]).toArray()[0];
+ const tsMixedSchemaOptionNewFormat = catalog.md.options.storageEngine &&
+ catalog.md.options.storageEngine.wiredTiger &&
+ catalog.md.options.storageEngine.wiredTiger.configString;
+ // TODO SERVER-92533 Simplify once SERVER-91195 is backported to all supported branches
+ if (tsMixedSchemaOptionNewFormat !== undefined) {
+ return tsMixedSchemaOptionNewFormat ==
+ "app_metadata=(timeseriesBucketsMayHaveMixedSchemaData=true)";
+ } else {
+ return catalog.md.timeseriesBucketsMayHaveMixedSchemaData;
+ }
+ }
+
/**
* Returns whether time-series updates and deletes are supported.
*/
diff --git a/jstests/core/timeseries/timeseries_collmod.js b/jstests/core/timeseries/timeseries_collmod.js
index 69fd7dbeb82..07c9166b632 100644
--- a/jstests/core/timeseries/timeseries_collmod.js
+++ b/jstests/core/timeseries/timeseries_collmod.js
@@ -19,6 +19,17 @@ assert.commandWorked(
db.createCollection(collName, {timeseries: {timeField: "time", granularity: 'seconds'}}));
assert.commandWorked(coll.createIndex({"time": 1}));
+// Setting prepareUnique should return an error on a time-series collection.
+assert.commandFailedWithCode(
+ db.runCommand(
+ {"collMod": collName, "index": {"keyPattern": {"time": 1}, "prepareUnique": true}}),
+ ErrorCodes.InvalidOptions);
+
+assert.commandFailedWithCode(
+ db.runCommand(
+ {"collMod": collName, "index": {"keyPattern": {"time": 1}, "prepareUnique": false}}),
+ ErrorCodes.InvalidOptions);
+
// Tries to convert a time-series secondary index to TTL index.
assert.commandFailedWithCode(
db.runCommand(
@@ -56,4 +67,4 @@ assert.commandWorked(db.runCommand({"collMod": collName, "expireAfterSeconds": 6
// Successfully sets the granularity for a time-series collection.
assert.commandWorked(
db.runCommand({"collMod": collName, "timeseries": {"granularity": "minutes"}}));
-})(); \ No newline at end of file
+})();
diff --git a/jstests/core/timeseries/timeseries_computed_field.js b/jstests/core/timeseries/timeseries_computed_field.js
new file mode 100644
index 00000000000..fab03d1a3b0
--- /dev/null
+++ b/jstests/core/timeseries/timeseries_computed_field.js
@@ -0,0 +1,856 @@
+/**
+ * Test use of computed fields in aggregations on time series collections.
+ * @tags: [
+ * requires_timeseries,
+ * does_not_support_stepdowns,
+ * directly_against_shardsvrs_incompatible,
+ * # "Explain of a resolved view must be executed by mongos"
+ * directly_against_shardsvrs_incompatible,
+ * # Some suites use mixed-binary cluster setup where some nodes might have the flag enabled while
+ * # others -- not. For this test we need control over whether the flag is set on the node that
+ * # ends up executing the query.
+ * assumes_standalone_mongod
+ * ]
+ */
+load("jstests/core/timeseries/libs/timeseries.js");
+
+TimeseriesTest.run((insert) => {
+ const datePrefix = 1680912440;
+
+ let coll = db.timeseries_computed_field;
+ const bucketsColl = db.getCollection('system.buckets.' + coll.getName());
+
+ const timeFieldName = 'time';
+ const metaFieldName = 'measurement';
+
+ coll.drop();
+ assert.commandWorked(db.createCollection(coll.getName(), {
+ timeseries: {timeField: timeFieldName, metaField: metaFieldName},
+ }));
+ assert.contains(bucketsColl.getName(), db.getCollectionNames());
+
+ insert(coll, {
+ _id: 0,
+ [timeFieldName]: new Date(datePrefix + 100), // ISODate("1970-01-20T10:55:12.540Z")
+ [metaFieldName]: "cpu",
+ topLevelScalar: 123,
+ topLevelScalarDouble: 123.8778645,
+ topLevelLargeNumber: 12345678912345,
+ topLevelArray: [1, 2, 3, 4],
+ arrOfObj: [{x: 1}, {x: 2}, {x: 3}, {x: 4}],
+ obj: {a: 123},
+ length: 0,
+ });
+ insert(coll, {
+ _id: 1,
+ [timeFieldName]: new Date(datePrefix + 200), // ISODate("1970-01-20T10:55:12.640Z")
+ [metaFieldName]: "cpu",
+ topLevelScalar: 456,
+ topLevelScalarDouble: 546.76858699,
+ topLevelArray: [101, 102, 103, 104],
+ arrOfObj: [{x: 101}, {x: 102}, {x: 103}, {x: 104}],
+ obj: {a: 456},
+ length: 23,
+ });
+ // Insert a document that will be placed in a different bucket.
+ insert(coll, {
+ _id: 2,
+ [timeFieldName]: new Date(datePrefix + 300),
+ [metaFieldName]: "gpu",
+ length: -2,
+ });
+
+ // Computing a field on a dotted path which is an array, then grouping on it. Note that the
+ // semantics for setting a computed field on a dotted array path are particularly strange, but
+ // should be preserved for backwards compatibility.
+ {
+ const res = coll.aggregate([
+ {$addFields: {"arrOfObj.x": {$trim: {input: "test string"}}}},
+ {$match: {topLevelScalar: {$gte: 0}}},
+ {$group: {_id: null, max: {$max: "$arrOfObj.x"}}}
+ ])
+ .toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].max, ["test string", "test string", "test string", "test string"], res);
+ }
+
+ {
+ const res = coll.aggregate([
+ {$addFields: {"arrOfObj.x": {$add: ["$topLevelScalar", 1]}}},
+ {$match: {topLevelScalar: {$gte: 0}}},
+ {$group: {_id: null, max: {$max: "$arrOfObj.x"}}}
+ ])
+ .toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].max, [457, 457, 457, 457], res);
+ }
+
+ // Computing a field and then filtering by it.
+ {
+ const res = coll.aggregate([
+ {$addFields: {"arrOfObj.x": {$trim: {input: "test string"}}}},
+ {$match: {"arrOfObj.x": "test string"}},
+ {$group: {_id: null, max: {$max: "$arrOfObj.x"}}}
+ ])
+ .toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].max, ["test string", "test string", "test string", "test string"], res);
+ }
+
+ {
+ // Computing a field based on a dotted path which does not traverse arrays.
+ const res = coll.aggregate([
+ {$addFields: {"computedA": {$add: ["$obj.a", 1]}}},
+ // Only one document should have a value where obj.a was 457
+ // (456 + 1).
+ {$match: {"computedA": 457}},
+ {$count: "count"}
+ ])
+ .toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 1, res);
+ }
+
+ {
+ // Include an unnecessary computed field before counting the number of documents.
+ const res = coll.aggregate([{$addFields: {"a": 1}}, {$count: "count"}]).toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 3, res);
+ }
+
+ // mathematical expressions
+ {
+ let pipeline = [
+ {$addFields: {"computedA": {$add: ["$topLevelScalar", 1]}}},
+ {$match: {"computedA": 457}},
+ {$count: "count"}
+ ];
+
+ const res = coll.aggregate(pipeline).toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 1, res);
+ }
+ {
+ let pipeline = [
+ {$addFields: {"computedA": {$subtract: ["$topLevelScalar", 1]}}},
+ {$match: {"computedA": 455}},
+ {$count: "count"}
+ ];
+
+ const res = coll.aggregate(pipeline).toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 1, res);
+ }
+ {
+ let pipeline = [
+ {$addFields: {"computedA": {$multiply: ["$topLevelScalar", 10]}}},
+ {$match: {"computedA": 4560}},
+ {$count: "count"}
+ ];
+
+ const res = coll.aggregate(pipeline).toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 1, res);
+ }
+ {
+ let pipeline = [
+ {$addFields: {"computedA": {$divide: ["$topLevelScalar", 2]}}},
+ {$match: {"computedA": 228}},
+ {$count: "count"}
+ ];
+
+ const res = coll.aggregate(pipeline).toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 1, res);
+ }
+ {
+ let pipeline = [
+ {$addFields: {"computedA": {$add: [1, "$topLevelScalar"]}}},
+ {$match: {"computedA": 457}},
+ {$count: "count"}
+ ];
+
+ const res = coll.aggregate(pipeline).toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 1, res);
+ }
+ {
+ let pipeline = [
+ {$addFields: {"computedA": {$subtract: [200, "$topLevelScalar"]}}},
+ {$match: {"computedA": 77}},
+ {$count: "count"}
+ ];
+
+ const res = coll.aggregate(pipeline).toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 1, res);
+ }
+ {
+ let pipeline = [
+ {$addFields: {"computedA": {$multiply: [10, "$topLevelScalar"]}}},
+ {$match: {"computedA": 4560}},
+ {$count: "count"}
+ ];
+
+ const res = coll.aggregate(pipeline).toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 1, res);
+ }
+ {
+ let pipeline = [
+ {$addFields: {"computedA": {$divide: [4560, "$topLevelScalar"]}}},
+ {$match: {"computedA": 10}},
+ {$count: "count"}
+ ];
+
+ const res = coll.aggregate(pipeline).toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 1, res);
+ }
+
+ {
+ let pipeline = [
+ {$addFields: {"computedA": {$add: ["$topLevelScalar", "$topLevelScalar"]}}},
+ {$match: {"computedA": 912}},
+ {$count: "count"}
+ ];
+
+ const res = coll.aggregate(pipeline).toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 1, res);
+ }
+ {
+ let pipeline = [
+ {$addFields: {"computedA": {$subtract: ["$topLevelScalar", "$topLevelScalar"]}}},
+ {$match: {"computedA": 0}},
+ {$count: "count"}
+ ];
+
+ const res = coll.aggregate(pipeline).toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 2, res);
+ }
+ {
+ let pipeline = [
+ {$addFields: {"computedA": {$multiply: ["$topLevelScalar", "$topLevelScalar"]}}},
+ {$match: {"computedA": 15129}},
+ {$count: "count"}
+ ];
+
+ const res = coll.aggregate(pipeline).toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 1, res);
+ }
+ {
+ let pipeline = [
+ {$addFields: {"computedA": {$divide: ["$topLevelScalar", "$topLevelScalar"]}}},
+ {$match: {"computedA": 1}},
+ {$count: "count"}
+ ];
+
+ const res = coll.aggregate(pipeline).toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 2, res);
+ }
+
+ {
+ let pipeline = [
+ {
+ $addFields: {
+ "hourDiff": {
+ $dateDiff: {
+ "startDate": "$time",
+ "endDate": new Date("1970-01-21"),
+ "unit": "hour"
+ }
+ }
+ }
+ },
+ {$match: {"hourDiff": {$gte: 12}}},
+ {
+ $group: {
+ "_id": {"time": {"$dateTrunc": {"date": "$time", "unit": "minute"}}},
+ "open": {"$first": "$topLevelScalar"},
+ }
+ }
+ ];
+
+ assert.docEq([{"_id": {"time": ISODate("1970-01-20T10:55:00Z")}, "open": 123}],
+ coll.aggregate(pipeline).toArray());
+ }
+
+ {
+ let pipeline = [
+ {$addFields: {"mt": {$multiply: ["$topLevelScalar", 10]}}},
+ {$match: {"mt": {$gte: 2000}}},
+ {
+ $group: {
+ "_id": {"time": {"$dateTrunc": {"date": "$time", "unit": "minute"}}},
+ "open": {"$first": "$topLevelScalar"},
+ }
+ }
+ ];
+
+ assert.docEq([{"_id": {"time": ISODate("1970-01-20T10:55:00Z")}, "open": 456}],
+ coll.aggregate(pipeline).toArray());
+ }
+
+ {
+ let pipeline = [
+ {
+ $addFields: {
+ "hourDiff": {
+ $dateDiff: {
+ "startDate": "$time",
+ "endDate": new Date("1970-01-21"),
+ "unit": "hour"
+ }
+ }
+ }
+ },
+ {$match: {$or: [{topLevelScalar: {$gt: 200, $lt: 800}}, {hourDiff: {$gte: 12}}]}},
+ {
+ $group: {
+ "_id": {"time": {"$dateTrunc": {"date": "$time", "unit": "minute"}}},
+ "open": {"$first": "$topLevelScalar"},
+ }
+ }
+ ];
+
+ assert.docEq([{"_id": {"time": ISODate("1970-01-20T10:55:00Z")}, "open": 123}],
+ coll.aggregate(pipeline).toArray());
+ }
+
+ {
+ // Try a project stage which adds and remove subfields.
+ const res = coll.aggregate([
+ {$project: {"obj.newField": "$topLevelScalar"}},
+ {$project: {"_id": 0, "obj.a": 0}}
+ ])
+ .toArray();
+ assert.eq(res.length, 3, res);
+ assert.eq(res[0], {"obj": {"newField": 123}}, res);
+ assert.eq(res[1], {"obj": {"newField": 456}}, res);
+ assert.eq(res[2], {"obj": {}}, res);
+ }
+
+ {
+ // Try a replaceRoot stage which remove all fields.
+ const res = coll.aggregate([
+ {$match: {"time": {$gte: new Date(datePrefix + 200)}}},
+ {$addFields: {}},
+ {$project: {"measurement0": {$floor: "$topLevelScalar"}}},
+ {$replaceRoot: {newRoot: {}}}
+ ])
+ .toArray();
+ assert.eq(res.length, 2, res);
+ assert.eq(res[0], {}, res);
+ assert.eq(res[1], {}, res);
+ }
+
+ {
+ // Try a $match that works on fields that are not projected.
+ const res =
+ coll.aggregate([
+ {$project: {"obj.a": 1}},
+ {$match: {$or: [{"topLevelScalar": {$gt: 10}}, {$expr: {$literal: true}}]}},
+ {$sort: {_id: 1}},
+ {$count: "count"}
+ ])
+ .toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 3, res);
+ }
+
+ {
+ const res = coll.aggregate([{
+ "$project": {
+ "t": {
+ "$dateDiff": {
+ "startDate": "$time",
+ "endDate": new Date(datePrefix + 150),
+ "unit": "millisecond"
+ }
+ }
+ }
+ }])
+ .toArray();
+ assert.eq(res.length, 3, res);
+ assert.docEq(res[0], {_id: 0, "t": NumberLong(50)}, res);
+ assert.docEq(res[1], {_id: 1, "t": NumberLong(-50)}, res);
+ assert.docEq(res[2], {_id: 2, "t": NumberLong(-150)}, res);
+ }
+
+ {
+ const res = coll.aggregate([{
+ "$project": {
+ "t": {
+ "$dateDiff": {
+ "startDate": new Date(datePrefix - 10),
+ "endDate": "$time",
+ "unit": "millisecond"
+ }
+ }
+ }
+ }])
+ .toArray();
+ assert.eq(res.length, 3, res);
+ assert.docEq(res[0], {_id: 0, "t": NumberLong(110)}, res);
+ assert.docEq(res[1], {_id: 1, "t": NumberLong(210)}, res);
+ assert.docEq(res[2], {_id: 2, "t": NumberLong(310)}, res);
+ }
+
+ {
+ const res = coll.aggregate([
+ {
+ $addFields: {
+ "computedField": {
+ $dateTrunc: {
+ date: "$time",
+ unit: "second",
+ }
+ }
+ }
+ },
+ {$match: {computedField: new Date(datePrefix - 440)}},
+ {$count: "count"}
+ ])
+ .toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 3, res);
+ }
+
+ {
+ const res = coll.aggregate([{$match: {topLevelScalar: {$exists: true}}}, {$count: "count"}])
+ .toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 2, res);
+ }
+
+ {
+ const res =
+ coll.aggregate([{$match: {topLevelScalar: {$lt: 456}}}, {$count: "count"}]).toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 1, res);
+ }
+
+ {
+ const res =
+ coll.aggregate([{$match: {topLevelScalar: {$lte: 456}}}, {$count: "count"}]).toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 2, res);
+ }
+
+ {
+ const res =
+ coll.aggregate([{$match: {topLevelScalar: {$gt: 123}}}, {$count: "count"}]).toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 1, res);
+ }
+
+ {
+ const res =
+ coll.aggregate([{$match: {topLevelScalar: {$gte: 123}}}, {$count: "count"}]).toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 2, res);
+ }
+
+ {
+ const res =
+ coll.aggregate([{$match: {topLevelScalar: {$eq: 123}}}, {$count: "count"}]).toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 1, res);
+ }
+
+ {
+ const res =
+ coll.aggregate([{$match: {topLevelScalar: {$ne: 123}}}, {$count: "count"}]).toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 2, res);
+ }
+
+ {
+ const res = coll.aggregate([
+ {
+ $match: {
+ $or: [
+ {"topLevelScalar": 123},
+ {"topLevelScalar": 456},
+ ]
+ }
+ },
+ {$count: "count"}
+ ])
+ .toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 2, res);
+ }
+
+ {
+ const res = coll.aggregate([
+ {$addFields: {"computedField": {$and: ["$topLevelScalar", true]}}},
+ {$match: {computedField: true}},
+ {$count: "count"}
+ ])
+ .toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 2, res);
+ }
+
+ {
+ const res = coll.aggregate([
+ {$addFields: {"computedField": {$and: ["$topLevelScalar", "$obj.a"]}}},
+ {$match: {computedField: true}},
+ {$count: "count"}
+ ])
+ .toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 2, res);
+ }
+
+ {
+ const res = coll.aggregate([
+ {$addFields: {"computedField": {$or: ["$topLevelScalar", false]}}},
+ {$match: {computedField: true}},
+ {$count: "count"}
+ ])
+ .toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 2, res);
+ }
+
+ {
+ const res = coll.aggregate([
+ {$addFields: {"computedField": {$or: ["$topLevelScalar", "$obj.a"]}}},
+ {$match: {computedField: true}},
+ {$count: "count"}
+ ])
+ .toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 2, res);
+ }
+
+ {
+ const res = coll.aggregate([
+ {$addFields: {"computedField": {$not: ["$topLevelScalar"]}}},
+ {$match: {computedField: true}},
+ {$count: "count"}
+ ])
+ .toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 1, res);
+ }
+
+ {
+ const res =
+ coll.aggregate([
+ {$addFields: {"computedField": {$anyElementTrue: [["$topLevelScalar"]]}}},
+ {$match: {computedField: true}},
+ {$count: "count"}
+ ])
+ .toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 2, res);
+ }
+
+ {
+ const res =
+ coll.aggregate([
+ {$match: {length: {$ne: 0}}},
+ {$set: {"computedA": {$multiply: ["$topLevelScalar", "$topLevelScalar"]}}},
+ {$addFields: {"ratio": {$divide: ["$computedA", "$length"]}}},
+ {$match: {ratio: {$gt: 0}}},
+ ])
+ .toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0]._id, 1, res);
+ }
+
+ {
+ let pipeline = [
+ {$addFields: {"computedA": {$round: ["$topLevelScalarDouble", 2]}}},
+ {$match: {"computedA": {$gte: 100}}},
+ {
+ $group: {
+ "_id": {"time": {"$dateTrunc": {"date": "$time", "unit": "minute"}}},
+ "value": {$sum: "$computedA"},
+ }
+ }
+ ];
+
+ const res = coll.aggregate(pipeline).toArray();
+ assert.docEq([{"_id": {"time": ISODate("1970-01-20T10:55:00Z")}, "value": 670.65}], res);
+ }
+ {
+ let pipeline = [
+ {$addFields: {"computedA": {$round: ["$topLevelScalarDouble"]}}},
+ {$match: {"computedA": {$gte: 100}}},
+ {
+ $group: {
+ "_id": {"time": {"$dateTrunc": {"date": "$time", "unit": "minute"}}},
+ "value": {$sum: "$computedA"},
+ }
+ }
+ ];
+
+ const res = coll.aggregate(pipeline).toArray();
+ assert.docEq([{"_id": {"time": ISODate("1970-01-20T10:55:00Z")}, "value": 671}], res);
+ }
+ {
+ let pipeline = [
+ {$addFields: {"computedA": {$round: [2, "$topLevelScalarDouble"]}}},
+ {$match: {"computedA": {$gte: 100}}},
+ {
+ $group: {
+ "_id": {"time": {"$dateTrunc": {"date": "$time", "unit": "minute"}}},
+ "value": {$sum: "$computedA"},
+ }
+ }
+ ];
+
+ assert.throws(() => coll.aggregate(pipeline));
+ }
+ {
+ let pipeline = [
+ {$addFields: {"computedA": {$round: ["$topLevelScalarDouble", "$topLevelScalar"]}}},
+ {$match: {"computedA": {$gte: 100}}},
+ {
+ $group: {
+ "_id": {"time": {"$dateTrunc": {"date": "$time", "unit": "minute"}}},
+ "value": {$sum: "$computedA"},
+ }
+ }
+ ];
+
+ assert.throws(() => coll.aggregate(pipeline));
+ }
+
+ {
+ let pipeline = [
+ {$addFields: {"computedA": {$trunc: ["$topLevelScalarDouble", 2]}}},
+ {$match: {"computedA": {$gte: 100}}},
+ {
+ $group: {
+ "_id": {"time": {"$dateTrunc": {"date": "$time", "unit": "minute"}}},
+ "value": {$sum: "$computedA"},
+ }
+ }
+ ];
+
+ const res = coll.aggregate(pipeline).toArray();
+ assert.docEq([{"_id": {"time": ISODate("1970-01-20T10:55:00Z")}, "value": 670.63}], res);
+ }
+ {
+ let pipeline = [
+ {$addFields: {"computedA": {$trunc: ["$topLevelScalarDouble"]}}},
+ {$match: {"computedA": {$gte: 100}}},
+ {
+ $group: {
+ "_id": {"time": {"$dateTrunc": {"date": "$time", "unit": "minute"}}},
+ "value": {$sum: "$computedA"},
+ }
+ }
+ ];
+
+ const res = coll.aggregate(pipeline).toArray();
+ assert.docEq([{"_id": {"time": ISODate("1970-01-20T10:55:00Z")}, "value": 669}], res);
+ }
+ {
+ let pipeline = [
+ {$addFields: {"computedA": {$trunc: [2, "$topLevelScalarDouble"]}}},
+ {$match: {"computedA": {$gte: 100}}},
+ {
+ $group: {
+ "_id": {"time": {"$dateTrunc": {"date": "$time", "unit": "minute"}}},
+ "value": {$sum: "$computedA"},
+ }
+ }
+ ];
+
+ assert.throws(() => coll.aggregate(pipeline));
+ }
+ {
+ let pipeline = [
+ {$addFields: {"computedA": {$trunc: ["$topLevelScalarDouble", "$topLevelScalar"]}}},
+ {$match: {"computedA": {$gte: 100}}},
+ {
+ $group: {
+ "_id": {"time": {"$dateTrunc": {"date": "$time", "unit": "minute"}}},
+ "value": {$sum: "$computedA"},
+ }
+ }
+ ];
+
+ assert.throws(() => coll.aggregate(pipeline));
+ }
+
+ {
+ let pipeline = [
+ {$addFields: {md: {$mod: ["$topLevelScalar", 5]}}},
+ {
+ $group: {
+ "_id": {$dateTrunc: {"date": "$time", "unit": "minute"}},
+ "total1": {$sum: "$md"},
+ "total2": {$sum: "$topLevelScalar"}
+ }
+ }
+ ];
+
+ assert.docEq([{"_id": ISODate("1970-01-20T10:55:00Z"), "total1": 4, "total2": 579}],
+ coll.aggregate(pipeline).toArray());
+ }
+
+ {
+ let pipeline = [
+ {$addFields: {md: {$mod: [500, "$topLevelScalar"]}}},
+ {
+ $group: {
+ "_id": {$dateTrunc: {"date": "$time", "unit": "minute"}},
+ "total1": {$sum: "$md"},
+ "total2": {$sum: "$topLevelScalar"}
+ }
+ }
+ ];
+
+ assert.docEq([{"_id": ISODate("1970-01-20T10:55:00Z"), "total1": 52, "total2": 579}],
+ coll.aggregate(pipeline).toArray());
+ }
+
+ {
+ let pipeline = [
+ {$addFields: {md: {$mod: ["$topLevelScalar", "$topLevelScalar"]}}},
+ {
+ $group: {
+ "_id": {$dateTrunc: {"date": "$time", "unit": "minute"}},
+ "total1": {$sum: "$md"},
+ "total2": {$sum: "$topLevelScalar"}
+ }
+ }
+ ];
+
+ assert.docEq([{"_id": ISODate("1970-01-20T10:55:00Z"), "total1": 0, "total2": 579}],
+ coll.aggregate(pipeline).toArray());
+ }
+
+ {
+ let pipeline = [
+ {$addFields: {md: {$mod: ["$topLevelScalar", 5]}}},
+ {$match: {md: {$mod: [4, 1]}}},
+ {
+ $group: {
+ "_id": {$dateTrunc: {"date": "$time", "unit": "minute"}},
+ "total1": {$sum: "$md"},
+ "total2": {$sum: "$topLevelScalar"}
+ }
+ }
+ ];
+
+ assert.docEq([{"_id": ISODate("1970-01-20T10:55:00Z"), "total1": 1, "total2": 456}],
+ coll.aggregate(pipeline).toArray());
+ }
+ {
+ let pipeline = [{$match: {topLevelLargeNumber: {$mod: [1, 0]}}}, {$count: "count"}];
+
+ const res = coll.aggregate(pipeline).toArray();
+
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 1, res);
+ }
+ {
+ const res =
+ coll.aggregate([
+ {
+ $addFields: {
+ "computedField":
+ {$dateAdd: {startDate: "$time", unit: "millisecond", amount: 100}}
+ }
+ },
+ {$match: {computedField: new Date(datePrefix + 400)}},
+ {$count: "count"}
+ ])
+ .toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 1, res);
+ }
+
+ {
+ const res = coll.aggregate([
+ {
+ $addFields: {
+ "computedField": {
+ $dateSubtract:
+ {startDate: "$time", unit: "millisecond", amount: 100}
+ }
+ }
+ },
+ {$match: {computedField: new Date(datePrefix)}},
+ {$count: "count"}
+ ])
+ .toArray();
+ assert.eq(res.length, 1, res);
+ assert.eq(res[0].count, 1, res);
+ }
+
+ {
+ // Test the case where a computed meta field is computed to missing.
+ const res =
+ coll.aggregate([{"$project": {"_id": 0, [metaFieldName]: "$$REMOVE"}}]).toArray();
+ assert.eq(res.length, coll.count(), res);
+ for (let doc of res) {
+ assert.eq(doc, {}, res);
+ }
+ }
+
+ {
+ // Test the case where a computed meta field is computed to missing because of a project
+ // out.
+ const res = coll.aggregate([
+ {"$project": {[metaFieldName]: 0}},
+ {"$project": {[metaFieldName]: "$" + metaFieldName}},
+ {$match: {a: 1}}
+ ])
+ .toArray();
+ assert.eq(res.length, 0, res);
+ }
+
+ {
+ // Test the case where a field is projected out and then projected back in.
+ const res = coll.aggregate([
+ {"$project": {"_id": 0, [metaFieldName]: 1}},
+ {"$project": {"_id": 0, [timeFieldName]: "$" + timeFieldName}},
+ {"$project": {"_id": 1, [timeFieldName]: 1}}
+ ])
+ .toArray();
+ assert.eq(res.length, coll.count(), res);
+ for (let doc of res) {
+ assert.eq(doc, {}, res);
+ }
+ }
+
+ {
+ // Test the case where a field is projected out and then projected back in.
+ const res = coll.aggregate([
+ {"$project": {"_id": 0, [metaFieldName]: 1}},
+ {"$project": {"_id": 0, [timeFieldName]: 1}}
+ ])
+ .toArray();
+ assert.eq(res.length, coll.count(), res);
+ for (let doc of res) {
+ assert.eq(doc, {}, res);
+ }
+ }
+
+ {
+ // Test the case where a field is projected out and then projected back in.
+ const res = coll.aggregate([
+ {"$project": {"_id": 0, [metaFieldName]: 0}},
+ {"$project": {"_id": 0, [metaFieldName]: 1}},
+ {"$project": {"_id": 0, [timeFieldName]: 1}}
+ ])
+ .toArray();
+ assert.eq(res.length, coll.count(), res);
+ for (let doc of res) {
+ assert.eq(doc, {}, res);
+ }
+ }
+});
diff --git a/jstests/core/timeseries/timeseries_filter_extended_range.js b/jstests/core/timeseries/timeseries_filter_extended_range.js
index 2b86e29c943..34018b3d2f4 100644
--- a/jstests/core/timeseries/timeseries_filter_extended_range.js
+++ b/jstests/core/timeseries/timeseries_filter_extended_range.js
@@ -1,6 +1,6 @@
/**
- * Test that find/match type queries work properly on dates ouside the 32 bit epoch range,
- * [1970-01-01 00:00:00 UTC - 2038-01-29 03:13:07 UTC].
+ * Test that find and match type queries work properly on dates outside the 32 bit epoch range,
+ * [1970-01-01 00:00:00 UTC - 2038-01-19 03:14:07 UTC].
*
* @tags: [
* # Refusing to run a test that issues an aggregation command with explain because it may
@@ -12,174 +12,301 @@
* does_not_support_transactions,
* # Explain of a resolved view must be executed by mongos.
* directly_against_shardsvrs_incompatible,
+ * requires_fcv_60
* ]
*/
(function() {
"use strict";
+
const timeFieldName = "time";
+const standardDocs = [
+ {[timeFieldName]: ISODate("1975-12-01")},
+ {[timeFieldName]: ISODate("1980-01-13")},
+ {[timeFieldName]: ISODate("2018-07-14")},
+ {[timeFieldName]: ISODate("2030-09-30")},
+];
+const beforeEpochDocs = [
+ {[timeFieldName]: ISODate("1969-12-31T23:00:59.001Z")},
+ {[timeFieldName]: ISODate("1969-12-31T23:59:59.001Z")} /* one millisecond before the epoch */,
+];
+const afterEpochDocs = [
+ // This date is one millisecond after the maximum (the largest 32 bit integer) number of seconds
+ // since the epoch.
+ {[timeFieldName]: ISODate("2038-01-19T03:14:07.001Z")},
+ {[timeFieldName]: ISODate("2050-01-20T03:14:00.003Z")}
+];
+const allExtendedRangeDocs = beforeEpochDocs.concat(afterEpochDocs);
/*
- * Creates a collection, populates it, runs the `query` and ensures that the result set
- * is equal to `results`.
- *
- * If overflow is set we create a document with dates above the 32 bit range (year 2040)
- * If underflow is set, we create a document with dates below the 32 bit range (year 1965)
+ * Creates a collection, populates it using the `standardDocs` and any dates passed in by
+ * `extendedRangeDocs`, runs the `query` and ensures that the result set is equal to `results`.
*/
-function runTest(underflow, overflow, query, results) {
- // Setup our DB & our collections.
+function runTest({query, results, extendedRangeDocs}) {
+ // Setup the collection and insert the dates in `standardDocs` and `extendedRangeDocs`.
const tsColl = db.getCollection(jsTestName());
tsColl.drop();
-
assert.commandWorked(
db.createCollection(tsColl.getName(), {timeseries: {timeField: timeFieldName}}));
-
- const dates = [
- // If underflow, we want to insert a date that would fall below the epoch
- // i.e. 1970-01-01 00:00:00 UTC. Otherwise we use a date within the epoch.
- {[timeFieldName]: underflow ? new Date("1965-01-01") : new Date("1971-01-01")},
- {[timeFieldName]: new Date("1975-01-01")},
- {[timeFieldName]: new Date("1980-01-01")},
- {[timeFieldName]: new Date("1995-01-01")},
- // If overflow, we want to insert a date that would use more than 32 bit milliseconds after
- // the epoch. This overflow will occur 2038-01-29 03:13:07 UTC. Otherwise we go slightly
- // before the end of the 32 bit epoch.
- {[timeFieldName]: overflow ? new Date("2040-01-01") : new Date("2030-01-01")}
- ];
- assert.commandWorked(tsColl.insert(dates));
-
- // Make sure the expected results are in the correct order for comparison below.
- function cmpTimeFields(a, b) {
- return (b[timeFieldName].getTime() - a[timeFieldName].getTime());
- }
- results.sort(cmpTimeFields);
+ assert.commandWorked(tsColl.insert(standardDocs.concat(extendedRangeDocs)));
const pipeline = [{$match: query}, {$project: {_id: 0, [timeFieldName]: 1}}];
-
const plan = tsColl.explain().aggregate(pipeline);
- // Verify agg pipeline. We don't want to go through a plan that encourages a sort order to
- // avoid BUS and index selection, so we sort after gathering the results.
+ // Verify the results.
const aggActuals = tsColl.aggregate(pipeline).toArray();
- aggActuals.sort(cmpTimeFields);
- assert.docEq(results, aggActuals, JSON.stringify(plan, null, 4));
+ assert.sameMembers(results, aggActuals, JSON.stringify(plan, null, 4));
- // Verify the equivalent find command. We again don't want to go through a plan that
- // encourages a sort order to avoid BUS and index selection, so we sort after gathering the
- // results.
+ // Verify the equivalent find command.
let findActuals = tsColl.find(query, {_id: 0, [timeFieldName]: 1}).toArray();
- findActuals.sort(cmpTimeFields);
- assert.docEq(findActuals, results);
+ assert.sameMembers(results, findActuals, JSON.stringify(plan, null, 4));
}
-runTest(false,
- false,
- {[timeFieldName]: {$eq: new Date("1980-01-01")}},
- [{[timeFieldName]: new Date("1980-01-01")}]);
-runTest(false,
- true,
- {[timeFieldName]: {$eq: new Date("2040-01-01")}},
- [{[timeFieldName]: new Date("2040-01-01")}]);
-runTest(true,
- false,
- {[timeFieldName]: {$eq: new Date("1965-01-01")}},
- [{[timeFieldName]: new Date("1965-01-01")}]);
-
-runTest(false,
- false,
- {[timeFieldName]: {$lt: new Date("1980-01-01")}},
- [{[timeFieldName]: new Date("1971-01-01")}, {[timeFieldName]: new Date("1975-01-01")}]);
-runTest(false,
- true,
- {[timeFieldName]: {$lt: new Date("1980-01-01")}},
- [{[timeFieldName]: new Date("1971-01-01")}, {[timeFieldName]: new Date("1975-01-01")}]);
-runTest(true,
- false,
- {[timeFieldName]: {$lt: new Date("1980-01-01")}},
- [{[timeFieldName]: new Date("1965-01-01")}, {[timeFieldName]: new Date("1975-01-01")}]);
-runTest(true,
- true,
- {[timeFieldName]: {$lt: new Date("1980-01-01")}},
- [{[timeFieldName]: new Date("1965-01-01")}, {[timeFieldName]: new Date("1975-01-01")}]);
-
-runTest(false,
- false,
- {[timeFieldName]: {$gt: new Date("1980-01-01")}},
- [{[timeFieldName]: new Date("1995-01-01")}, {[timeFieldName]: new Date("2030-01-01")}]);
-runTest(false,
- true,
- {[timeFieldName]: {$gt: new Date("1980-01-01")}},
- [{[timeFieldName]: new Date("1995-01-01")}, {[timeFieldName]: new Date("2040-01-01")}]);
-runTest(true,
- false,
- {[timeFieldName]: {$gt: new Date("1980-01-01")}},
- [{[timeFieldName]: new Date("1995-01-01")}, {[timeFieldName]: new Date("2030-01-01")}]);
-runTest(true,
- true,
- {[timeFieldName]: {$gt: new Date("1980-01-01")}},
- [{[timeFieldName]: new Date("1995-01-01")}, {[timeFieldName]: new Date("2040-01-01")}]);
-
-runTest(false, false, {[timeFieldName]: {$lte: new Date("1980-01-01")}}, [
- {[timeFieldName]: new Date("1971-01-01")},
- {[timeFieldName]: new Date("1975-01-01")},
- {[timeFieldName]: new Date("1980-01-01")}
-]);
-runTest(false, true, {[timeFieldName]: {$lte: new Date("1980-01-01")}}, [
- {[timeFieldName]: new Date("1971-01-01")},
- {[timeFieldName]: new Date("1975-01-01")},
- {[timeFieldName]: new Date("1980-01-01")}
-]);
-runTest(true, false, {[timeFieldName]: {$lte: new Date("1980-01-01")}}, [
- {[timeFieldName]: new Date("1965-01-01")},
- {[timeFieldName]: new Date("1975-01-01")},
- {[timeFieldName]: new Date("1980-01-01")}
-]);
-runTest(true, true, {[timeFieldName]: {$lte: new Date("1980-01-01")}}, [
- {[timeFieldName]: new Date("1965-01-01")},
- {[timeFieldName]: new Date("1975-01-01")},
- {[timeFieldName]: new Date("1980-01-01")}
-]);
-
-runTest(false, false, {[timeFieldName]: {$gte: new Date("1980-01-01")}}, [
- {[timeFieldName]: new Date("1980-01-01")},
- {[timeFieldName]: new Date("1995-01-01")},
- {[timeFieldName]: new Date("2030-01-01")}
-]);
-runTest(false, true, {[timeFieldName]: {$gte: new Date("1980-01-01")}}, [
- {[timeFieldName]: new Date("1980-01-01")},
- {[timeFieldName]: new Date("1995-01-01")},
- {[timeFieldName]: new Date("2040-01-01")}
-]);
-runTest(true, false, {[timeFieldName]: {$gte: new Date("1980-01-01")}}, [
- {[timeFieldName]: new Date("1980-01-01")},
- {[timeFieldName]: new Date("1995-01-01")},
- {[timeFieldName]: new Date("2030-01-01")}
-]);
-runTest(true, true, {[timeFieldName]: {$gte: new Date("1980-01-01")}}, [
- {[timeFieldName]: new Date("1980-01-01")},
- {[timeFieldName]: new Date("1995-01-01")},
- {[timeFieldName]: new Date("2040-01-01")}
-]);
-
-// Verify ranges that straddle the lower and upper epoch boundaries work properly.
-runTest(
- true, false, {[timeFieldName]: {$gt: new Date("1920-01-01"), $lt: new Date("1980-01-01")}}, [
- {[timeFieldName]: new Date("1965-01-01")},
- {[timeFieldName]: new Date("1975-01-01")},
- ]);
-runTest(
- false, true, {[timeFieldName]: {$gt: new Date("1980-01-01"), $lt: new Date("2050-01-01")}}, [
- {[timeFieldName]: new Date("1995-01-01")},
- {[timeFieldName]: new Date("2040-01-01")},
- ]);
+// Verify when there are no extended range dates in the collection, we handle querying by extended
+// range dates. The code for this is shared by multiple operators, so we don't have to test each
+// operator separately.
+runTest({
+ query: {[timeFieldName]: {$lte: beforeEpochDocs[1].time}},
+ results: [],
+ extendedRangeDocs: []
+});
+runTest({
+ query: {[timeFieldName]: {$lte: afterEpochDocs[0].time}},
+ results: standardDocs,
+ extendedRangeDocs: []
+});
+runTest({
+ query: {[timeFieldName]: {$gt: beforeEpochDocs[1].time}},
+ results: standardDocs,
+ extendedRangeDocs: []
+});
runTest(
- false, false, {[timeFieldName]: {$gt: new Date("1920-01-01"), $lt: new Date("1980-01-01")}}, [
- {[timeFieldName]: new Date("1971-01-01")},
- {[timeFieldName]: new Date("1975-01-01")},
- ]);
-runTest(
- false, false, {[timeFieldName]: {$gt: new Date("1980-01-01"), $lt: new Date("2050-01-01")}}, [
- {[timeFieldName]: new Date("1995-01-01")},
- {[timeFieldName]: new Date("2030-01-01")},
- ]);
-})();
+ {query: {[timeFieldName]: {$gt: afterEpochDocs[0].time}}, results: [], extendedRangeDocs: []});
+runTest({query: {[timeFieldName]: afterEpochDocs[0].time}, results: [], extendedRangeDocs: []});
+
+/*
+ * Verify $eq queries for dates inside, below and above the epoch ranges.
+ */
+// Test in the epoch range when there are measurements before and after the epoch.
+runTest({
+ query: {[timeFieldName]: {$eq: standardDocs[1].time}},
+ results: [standardDocs[1]],
+ extendedRangeDocs: allExtendedRangeDocs
+});
+
+// Test when there is one date above the epoch range. The date is one millisecond after the maximum
+// (the largest 32 bit integer) number of seconds since the epoch.
+runTest({
+ query: {[timeFieldName]: {$eq: afterEpochDocs[0].time}},
+ results: [afterEpochDocs[0]],
+ extendedRangeDocs: [afterEpochDocs[0]]
+});
+
+// Test when there are multiple dates after the epoch range.
+runTest({
+ query: {[timeFieldName]: {$eq: afterEpochDocs[0].time}},
+ results: [afterEpochDocs[0]],
+ extendedRangeDocs: afterEpochDocs
+});
+
+// Test when there is one date before the epoch. The date is one millisecond before the epoch.
+runTest({
+ query: {[timeFieldName]: {$eq: beforeEpochDocs[1].time}},
+ results: [beforeEpochDocs[1]],
+ extendedRangeDocs: [beforeEpochDocs[1]]
+});
+
+// Test when there are multiple dates before the epoch.
+runTest({
+ query: {[timeFieldName]: {$eq: beforeEpochDocs[0].time}},
+ results: [beforeEpochDocs[0]],
+ extendedRangeDocs: beforeEpochDocs
+});
+
+/*
+ * $lt queries.
+ */
+// Test with dates below the epoch that match the predicate.
+runTest({
+ query: {[timeFieldName]: {$lt: beforeEpochDocs[1].time}},
+ results: [beforeEpochDocs[0]],
+ extendedRangeDocs: beforeEpochDocs
+});
+
+// Test with dates above the epoch that do not match the predicate.
+runTest({
+ query: {[timeFieldName]: {$lt: standardDocs[2].time}},
+ results: [standardDocs[0], standardDocs[1]],
+ extendedRangeDocs: afterEpochDocs
+});
+
+// Test with dates both above and below the epoch. Only the before dates will match the predicate.
+runTest({
+ query: {[timeFieldName]: {$lt: standardDocs[1].time}},
+ results: [standardDocs[0], beforeEpochDocs[0], beforeEpochDocs[1]],
+ extendedRangeDocs: allExtendedRangeDocs
+});
+
+// Test with dates both above and below the epoch. Both before and after dates match the predicate.
+runTest({
+ query: {[timeFieldName]: {$lt: afterEpochDocs[1].time}},
+ results: standardDocs.concat(beforeEpochDocs, [afterEpochDocs[0]]),
+ extendedRangeDocs: allExtendedRangeDocs
+});
+
+/*
+ * $gt queries.
+ */
+// Test with dates below the epoch that do not match the predicate.
+runTest({
+ query: {[timeFieldName]: {$gt: beforeEpochDocs[1].time}},
+ results: standardDocs,
+ extendedRangeDocs: beforeEpochDocs
+});
+
+// Test with dates above the epoch that do not match the predicate.
+runTest({
+ query: {[timeFieldName]: {$gt: afterEpochDocs[1].time}},
+ results: [],
+ extendedRangeDocs: afterEpochDocs
+});
+
+// Test with dates both above and below the epoch. Only the after dates will match the predicate.
+runTest({
+ query: {[timeFieldName]: {$gt: standardDocs[2].time}},
+ results: [standardDocs[3], afterEpochDocs[0], afterEpochDocs[1]],
+ extendedRangeDocs: allExtendedRangeDocs
+});
+
+// Test with dates both above and below the epoch. Both before and after dates match the predicate.
+runTest({
+ query: {[timeFieldName]: {$gt: beforeEpochDocs[0].time}},
+ results: standardDocs.concat([beforeEpochDocs[1]], afterEpochDocs),
+ extendedRangeDocs: allExtendedRangeDocs
+});
+
+/*
+ * $lte queries.
+ */
+
+// Test with dates below the epoch that do match the predicate.
+runTest({
+ query: {[timeFieldName]: {$lte: standardDocs[0].time}},
+ results: beforeEpochDocs.concat([standardDocs[0]]),
+ extendedRangeDocs: beforeEpochDocs
+});
+
+// Test with dates above the epoch that do match the predicate.
+runTest({
+ query: {[timeFieldName]: {$lte: standardDocs[2].time}},
+ results: [standardDocs[0], standardDocs[1], standardDocs[2]],
+ extendedRangeDocs: afterEpochDocs
+});
+
+// Test with dates both above and below the epoch. Only the before dates will match the predicate.
+runTest({
+ query: {[timeFieldName]: {$lte: standardDocs[2].time}},
+ results: beforeEpochDocs.concat(standardDocs.slice(0, -1)),
+ extendedRangeDocs: allExtendedRangeDocs
+});
+
+// Test with dates both above and below the epoch. Both before and after dates will match the
+// predicate.
+runTest({
+ query: {[timeFieldName]: {$lte: afterEpochDocs[0].time}},
+ results: standardDocs.concat(beforeEpochDocs, [afterEpochDocs[0]]),
+ extendedRangeDocs: allExtendedRangeDocs
+});
+
+/*
+ * $gte queries.
+ */
+// Test with dates below the epoch that do not match the predicate.
+runTest({
+ query: {[timeFieldName]: {$gte: standardDocs[1].time}},
+ results: standardDocs.slice(1),
+ extendedRangeDocs: beforeEpochDocs
+});
+
+// Test with dates above the epoch that do match the predicate.
+runTest({
+ query: {[timeFieldName]: {$gte: standardDocs[2].time}},
+ results: afterEpochDocs.concat(standardDocs.slice(2)),
+ extendedRangeDocs: afterEpochDocs
+});
+
+// Test with dates both above and below the epoch. Only the after dates will match the predicate.
+runTest({
+ query: {[timeFieldName]: {$gte: standardDocs[1].time}},
+ results: afterEpochDocs.concat(standardDocs.slice(1)),
+ extendedRangeDocs: allExtendedRangeDocs
+});
+
+// Test with dates both above and below the epoch. Both before and after dates will match the
+// predicate.
+runTest({
+ query: {[timeFieldName]: {$gte: beforeEpochDocs[1].time}},
+ results: afterEpochDocs.concat(standardDocs, [beforeEpochDocs[1]]),
+ extendedRangeDocs: allExtendedRangeDocs
+});
+
+/*
+ * Compound predicates ($and, $or).
+ */
+
+// Test with dates below the epoch that do match the predicate.
+runTest({
+ query: {[timeFieldName]: {$gt: ISODate("1920-01-01"), $lt: ISODate("1980-01-01")}},
+ results: beforeEpochDocs.concat([standardDocs[0]]),
+ extendedRangeDocs: beforeEpochDocs
+});
+
+// Test with dates below the epoch that do not match the predicate.
+runTest({
+ query:
+ {[timeFieldName]: {$gt: ISODate("1970-01-01T00:00:00.001Z"), $lt: ISODate("1980-01-01")}},
+ results: [standardDocs[0]],
+ extendedRangeDocs: beforeEpochDocs
+});
+
+// Test with dates above the epoch that do match the predicate.
+runTest({
+ query: {
+ [timeFieldName]:
+ {$gt: ISODate("2030-09-29T23:59:59.001Z"), $lt: ISODate("2050-01-20T03:14:00.001Z")}
+ },
+ results: [standardDocs[3], afterEpochDocs[0]],
+ extendedRangeDocs: afterEpochDocs
+});
+
+// Test with dates above the epoch that do not match the predicate.
+runTest({
+ query: {
+ [timeFieldName]:
+ {$gt: ISODate("2030-09-29T23:59:59.001Z"), $lt: ISODate("2038-01-19T03:14:00.000Z")}
+ },
+ results: [standardDocs[3]],
+ extendedRangeDocs: afterEpochDocs
+});
+
+// Test with dates both above and below the epoch. Both before and after dates will match the
+// predicate.
+runTest({
+ query: {
+ $or: [
+ {[timeFieldName]: {$lt: ISODate("1975-12-01T23:59:00.001Z")}},
+ {[timeFieldName]: {$gt: ISODate("2038-01-19T03:14:07.002Z")}}
+ ]
+ },
+ results: beforeEpochDocs.concat([standardDocs[0], afterEpochDocs[1]]),
+ extendedRangeDocs: allExtendedRangeDocs
+});
+
+// Test with dates both above and below the epoch. Neither before nor after dates will match the
+// predicate.
+runTest({
+ query: {[timeFieldName]: {$in: [standardDocs[1].time, standardDocs[3].time]}},
+ results: [standardDocs[1], standardDocs[3]],
+ extendedRangeDocs: allExtendedRangeDocs
+});
+})(); \ No newline at end of file
diff --git a/jstests/core/timeseries/timeseries_geonear_lookup.js b/jstests/core/timeseries/timeseries_geonear_lookup.js
new file mode 100644
index 00000000000..78f68eb014e
--- /dev/null
+++ b/jstests/core/timeseries/timeseries_geonear_lookup.js
@@ -0,0 +1,40 @@
+/**
+ * Test that time-series works as expected with $geoNear within a $lookup.
+ *
+ * @tags: [
+ * does_not_support_transactions,
+ * requires_pipeline_optimization,
+ * # We need a timeseries collection.
+ * requires_timeseries,
+ * references_foreign_collection,
+ * ]
+ */
+
+// create a timeseries collection
+const timeFieldName = "time";
+const metaFieldName = "tags";
+const testDB = db;
+
+const tsColl = db.getCollection("ts_coll");
+
+const kMaxDistance = Math.PI * 2.0;
+
+tsColl.drop();
+assert.commandWorked(testDB.createCollection(
+ tsColl.getName(), {timeseries: {timeField: timeFieldName, metaField: metaFieldName}}));
+
+assert.commandWorked(tsColl.createIndex({'tags.loc': '2dsphere'}));
+
+tsColl.insert({time: ISODate(), tags: {loc: [40, 40], descr: 0}, value: 0});
+
+const coll2 = db.getCollection("store_min_max_values");
+coll2.drop();
+assert.commandWorked(coll2.insert({_id: 0, minimumDist: 0.0, maximumDist: kMaxDistance}));
+
+coll2.aggregate([{$lookup: {from: tsColl.getName(),
+let: {minVal: "$minimumDist",maxVal:"$maximumDist"},
+pipeline: [
+ {$geoNear: {near: {type: "Point", coordinates: [0, 0]},
+ key: 'tags.loc',
+ distanceField: "tags.distance"}}],
+ as: 'output'}}]);
diff --git a/jstests/core/timeseries/timeseries_graph_lookup.js b/jstests/core/timeseries/timeseries_graph_lookup.js
index 7b152cc6b1f..25f47aa2cef 100644
--- a/jstests/core/timeseries/timeseries_graph_lookup.js
+++ b/jstests/core/timeseries/timeseries_graph_lookup.js
@@ -5,6 +5,7 @@
* does_not_support_transactions,
* requires_timeseries,
* requires_fcv_51,
+ * references_foreign_collection,
* ]
*/
(function() {
diff --git a/jstests/core/timeseries/timeseries_insert_mixed_schema_bucket.js b/jstests/core/timeseries/timeseries_insert_mixed_schema_bucket.js
new file mode 100644
index 00000000000..cbce31e9795
--- /dev/null
+++ b/jstests/core/timeseries/timeseries_insert_mixed_schema_bucket.js
@@ -0,0 +1,75 @@
+/**
+ * Tests directly inserting a time-series bucket with mixed schema.
+ *
+ * @tags: [
+ * # $listCatalog does not include the tenant prefix in its results.
+ * command_not_supported_in_serverless,
+ * requires_timeseries,
+ * # $listCatalog not supported inside of a multi-document transaction
+ * does_not_support_transactions,
+ * # $listCatalog only exists since v6
+ * multiversion_incompatible,
+ * ]
+ */
+(function() {
+"use strict";
+
+load("jstests/core/timeseries/libs/timeseries.js"); // For 'TimeseriesTest'.
+
+TestData.skipEnforceTimeseriesBucketsAreAlwaysCompressedOnValidate = true;
+
+const testDB = db.getSiblingDB(jsTestName());
+const collName = "ts";
+
+assert.commandWorkedOrFailedWithCode(testDB.runCommand({drop: collName}),
+ ErrorCodes.NamespaceNotFound);
+assert.commandWorked(
+ testDB.createCollection(collName, {timeseries: {timeField: "t", metaField: "m"}}));
+const coll = testDB[collName];
+const bucketsColl = testDB["system.buckets." + collName];
+
+const bucket = {
+ _id: ObjectId("65a6eb806ffc9fa4280ecac4"),
+ control: {
+ version: NumberInt(1),
+ min: {
+ _id: ObjectId("65a6eba7e6d2e848e08c3750"),
+ t: ISODate("2024-01-16T20:48:00Z"),
+ a: 1,
+ },
+ max: {
+ _id: ObjectId("65a6eba7e6d2e848e08c3751"),
+ t: ISODate("2024-01-16T20:48:39.448Z"),
+ a: "a",
+ },
+ },
+ meta: 0,
+ data: {
+ _id: {
+ 0: ObjectId("65a6eba7e6d2e848e08c3750"),
+ 1: ObjectId("65a6eba7e6d2e848e08c3751"),
+ },
+ t: {
+ 0: ISODate("2024-01-16T20:48:39.448Z"),
+ 1: ISODate("2024-01-16T20:48:39.448Z"),
+ },
+ a: {
+ 0: "a",
+ 1: 1,
+ },
+ }
+};
+
+assert.commandFailedWithCode(bucketsColl.insert(bucket),
+ ErrorCodes.CannotInsertTimeseriesBucketsWithMixedSchema);
+assert.eq(TimeseriesTest.bucketsMayHaveMixedSchemaData(bucketsColl), false);
+assert.commandWorked(
+ testDB.runCommand({collMod: collName, timeseriesBucketsMayHaveMixedSchemaData: true}));
+assert.eq(TimeseriesTest.bucketsMayHaveMixedSchemaData(bucketsColl), true);
+assert.commandWorked(bucketsColl.insert(bucket));
+assert.commandWorked(bucketsColl.deleteOne({_id: bucket._id}));
+assert.eq(TimeseriesTest.bucketsMayHaveMixedSchemaData(bucketsColl), true);
+assert.commandWorked(
+ testDB.runCommand({collMod: collName, timeseriesBucketsMayHaveMixedSchemaData: false}));
+assert.eq(TimeseriesTest.bucketsMayHaveMixedSchemaData(bucketsColl), false);
+})();
diff --git a/jstests/core/timeseries/timeseries_lookup.js b/jstests/core/timeseries/timeseries_lookup.js
index ba804c4ec92..6d559e9356d 100644
--- a/jstests/core/timeseries/timeseries_lookup.js
+++ b/jstests/core/timeseries/timeseries_lookup.js
@@ -5,11 +5,13 @@
* does_not_support_transactions,
* requires_timeseries,
* requires_fcv_51,
+ * references_foreign_collection,
* ]
*/
(function() {
"use strict";
+load("jstests/aggregation/extras/utils.js");
load("jstests/core/timeseries/libs/timeseries.js");
TimeseriesTest.run((insert) => {
@@ -245,3 +247,91 @@ TimeseriesTest.run((insert) => {
});
});
})();
+
+{
+ // Test that we get the right results for $lookup on a timeseries collection with an internal
+ // pipeline containing both correlated and uncorrelated $match stages. Ensures we do not cache
+ // the results of this internal pipeline incorrectly
+ // (src/mongo/db/pipeline/document_source_sequential_document_cache.h) regardless of the order
+ // of the $match stages.
+ const testDB = db.getSiblingDB(jsTestName());
+ testDB.local.insertMany([{_id: 0, key: 1}, {_id: 1, key: 2}]);
+ testDB.createCollection("foreign", {timeseries: {timeField: "time", metaField: "meta"}});
+ testDB.foreign.insertMany([
+ {time: new Date(), _id: 0, meta: 1, val1: 42, val2: 100},
+ {time: new Date(), _id: 2, meta: 2, val1: 17, val2: 100}
+ ]);
+
+ // The $sequentialCache (document_source_sequential_document_cache.h) decides whether or not it
+ // can cache the results of the internal lookup pipeline based on if the pipeline is correlated
+ // or uncorrelated. With timeseries, many rewrites occur which can merge $match stages together,
+ // have them pushed into the $_internalUnpackBucket stage as an eventFilter, or push them in
+ // front of the
+ // $_internalUnpackBucket stage. We need to make sure that the ability of the cache to recognize
+ // when there is a correlated $match in the pipeline to remain regardless of these rewrites.
+ (function testUncorrelatedFollowedByCorrelatedMatch() {
+ const lookupStage = {$lookup: {
+ from: "foreign",
+ let: {lkey: "$key"},
+ pipeline: [
+ {$match: {$expr: {$lt: ["$val1","$val2"]}}},
+ {$match: {$expr: {$eq: ["$meta","$$lkey"]}}},
+ {$project: {lkey: "$$lkey",fkey: "$meta",val: "$val1",_id: 0,}},
+ ],
+ as: "joined"
+ }};
+ const result = testDB.local.aggregate(lookupStage);
+ assertArrayEq({
+ actual: result.toArray(),
+ expected: [
+ {"_id": 1, "key": 2, "joined": [{"lkey": 2, "fkey": 2, "val": 17}]},
+ {"_id": 0, "key": 1, "joined": [{"lkey": 1, "fkey": 1, "val": 42}]}
+ ],
+ extraErrorMsg: `Unexpected result of running pipeline ${tojson(lookupStage)}`
+ });
+ })();
+
+ (function testCorrelatedFollowedByUncorrelatedMatch() {
+ const lookupStage = {$lookup: {
+ from: "foreign",
+ let: {lkey: "$key"},
+ pipeline: [
+ {$match: {$expr: {$eq: ["$meta","$$lkey"]}}},
+ {$match: {$expr: {$lt: ["$val1","$val2"]}}},
+ {$project: {lkey: "$$lkey",fkey: "$meta",val: "$val1",_id: 0,}},
+ ],
+ as: "joined"
+ }};
+ const result = testDB.local.aggregate(lookupStage);
+ assertArrayEq({
+ actual: result.toArray(),
+ expected: [
+ {"_id": 1, "key": 2, "joined": [{"lkey": 2, "fkey": 2, "val": 17}]},
+ {"_id": 0, "key": 1, "joined": [{"lkey": 1, "fkey": 1, "val": 42}]}
+ ],
+ extraErrorMsg: `Unexpected result of running pipeline ${tojson(lookupStage)}`
+ });
+ })();
+
+ (function testUncorrelatedFollowedByUncorrelatedMatch() {
+ const lookupStage = {$lookup: {
+ from: "foreign",
+ let: {lkey: "$key"},
+ pipeline: [
+ {$match: {$expr: {$lt: ["$meta","$val1"]}}},
+ {$match: {$expr: {$lt: ["$val1","$val2"]}}},
+ {$project: {meta: "$meta",val: "$val1",_id: 0,}},
+ ],
+ as: "joined"
+ }};
+ const result = testDB.local.aggregate(lookupStage);
+ assertArrayEq({
+ actual: result.toArray(),
+ expected: [
+ {"_id": 0, "key": 1, "joined": [{"meta": 1, "val": 42}, {"meta": 2, "val": 17}]},
+ {"_id": 1, "key": 2, "joined": [{"meta": 1, "val": 42}, {"meta": 2, "val": 17}]}
+ ],
+ extraErrorMsg: `Unexpected result of running pipeline ${tojson(lookupStage)}`
+ });
+ })();
+}
diff --git a/jstests/core/timeseries/timeseries_merge.js b/jstests/core/timeseries/timeseries_merge.js
index 59d4dbee889..fb6a23df803 100644
--- a/jstests/core/timeseries/timeseries_merge.js
+++ b/jstests/core/timeseries/timeseries_merge.js
@@ -6,6 +6,7 @@
* does_not_support_stepdowns,
* does_not_support_transactions,
* requires_timeseries,
+ * references_foreign_collection,
* ]
*/
(function() {
diff --git a/jstests/core/timeseries/timeseries_project.js b/jstests/core/timeseries/timeseries_project.js
index 11ca90f2efe..b735a8a3b66 100644
--- a/jstests/core/timeseries/timeseries_project.js
+++ b/jstests/core/timeseries/timeseries_project.js
@@ -129,4 +129,171 @@ tsDoc = tsColl.aggregate(pipeline).toArray();
regDoc = regColl.aggregate(pipeline).toArray();
assert.docEq(tsDoc, regDoc);
})();
+
+// Test that an includes projection that doesn't include previously included computed meta fields
+// outputs correctly.
+(function testIncludeComputedMetaFieldThenProjectWithoutComputedMetaField() {
+ coll.drop();
+ assert.commandWorked(
+ db.createCollection(coll.getName(), {timeseries: {timeField: 'time', metaField: 'tag'}}));
+
+ const doc = {_id: 0, time: ISODate("2024-01-01T00:00:00.000Z"), tag: {field: "A"}};
+ assert.commandWorked(coll.insert(doc));
+ let result = {};
+
+ // Added field which uses meta should not be in the result.
+ result =
+ coll.aggregate(
+ [{$addFields: {time: {$dateFromParts: {year: "$tag.none"}}}}, {$project: {tag: 1}}])
+ .toArray();
+ assert.docEq([{"tag": {"field": "A"}, "_id": 0}], result);
+
+ // Test with non-null value.
+ result = coll.aggregate([{$addFields: {time: {$toLower: "$tag.field"}}}, {$project: {tag: 1}}])
+ .toArray();
+ assert.docEq([{"tag": {"field": "A"}, "_id": 0}], result);
+
+ // Testing with $match between $addFields and $project.
+ result = coll.aggregate([
+ {$addFields: {time: {$dateFromParts: {year: "$tag.none"}}}},
+ {$match: {tag: {field: "A"}}},
+ {$project: {tag: 1}}
+ ])
+ .toArray();
+ assert.docEq([{"tag": {field: "A"}, "_id": 0}], result);
+
+ // Test with non-null value.
+ result =
+ coll.aggregate(
+ [{$addFields: {time: "$tag.field"}}, {$match: {time: "A"}}, {$project: {tag: 1}}])
+ .toArray();
+ assert.docEq([{"tag": {field: "A"}, "_id": 0}], result);
+
+ // Testing with $project after $project.
+ result = coll.aggregate([{$project: {tag: 1}}, {$project: {time: 1}}]).toArray();
+ assert.docEq([{"_id": 0}], result);
+
+ // Testing with $set.
+ result = coll.aggregate([{$set: {tag: "$tag.field"}}, {$project: {time: 1}}]).toArray();
+ assert.docEq([{"_id": 0, "time": ISODate("2024-01-01T00:00:00Z")}], result);
+
+ // Test that computedMetaFields that are included by the $project are still included.
+ result = coll.aggregate([
+ {$addFields: {hi: {$dateFromParts: {year: "$tag.none"}}}},
+ {$addFields: {bye: {$dateFromParts: {year: "$tag.none"}}}},
+ {$project: {hi: 1}}
+ ])
+ .toArray();
+ assert.docEq([{"_id": 0, "hi": null}], result);
+
+ // Test with non-null value.
+ result = coll.aggregate([
+ {$addFields: {hi: "$tag.field"}},
+ {$addFields: {bye: "$tag.field"}},
+ {$project: {hi: 1}}
+ ])
+ .toArray();
+ assert.docEq([{"_id": 0, "hi": "A"}], result);
+
+ // Test that $project that replaces field that is used works.
+ result = coll.aggregate([
+ {$addFields: {hello: "$tag.field"}},
+ {$project: {newTime: "$time", time: "$tag.field"}}
+ ])
+ .toArray();
+
+ assert.docEq([{"_id": 0, newTime: ISODate("2024-01-01T00:00:00.000Z"), time: "A"}], result);
+
+ // Test adding fields and including one of them.
+ result = coll.aggregate([
+ {$addFields: {a: {$toLower: "$tag.field"}}},
+ {$addFields: {b: {$toUpper: "$tag.field"}}},
+ {$project: {b: 1}}
+ ])
+ .toArray();
+ assert.docEq([{b: "A", "_id": 0}], result);
+})();
+
+// Test that an excludes projection that excludes previously included computed meta fields
+// outputs correctly.
+(function testIncludeComputedMetaFieldThenExcludeComputedMetaField() {
+ coll.drop();
+ assert.commandWorked(
+ db.createCollection(coll.getName(), {timeseries: {timeField: 'time', metaField: 'tag'}}));
+
+ const doc = {_id: 0, time: ISODate("2024-01-01T00:00:00.000Z"), tag: {field: "A"}};
+ assert.commandWorked(coll.insert(doc));
+ let result = {};
+
+ // Excluded '_computedMetaProjField' should not be included.
+ result = coll.aggregate([
+ {$addFields: {hello: {$dateFromParts: {year: "$tag.none"}}}},
+ {$project: {hello: 0}}
+ ])
+ .toArray();
+ assert.docEq([{"time": ISODate("2024-01-01T00:00:00Z"), "tag": {"field": "A"}, "_id": 0}],
+ result);
+
+ // Test with non-null value.
+ result = coll.aggregate([{$addFields: {time: {$toLower: "$tag.field"}}}, {$project: {time: 0}}])
+ .toArray();
+ assert.docEq([{"tag": {"field": "A"}, "_id": 0}], result);
+
+ // Testing with $match between $addFields and $project.
+ result = coll.aggregate([
+ {$addFields: {time: {$dateFromParts: {year: "$tag.none"}}}},
+ {$match: {tag: {field: "A"}}},
+ {$project: {time: 0}}
+ ])
+ .toArray();
+ assert.docEq([{"tag": {field: "A"}, "_id": 0}], result);
+
+ // Test with non-null value.
+ result =
+ coll.aggregate(
+ [{$addFields: {time: "$tag.field"}}, {$match: {time: "A"}}, {$project: {time: 0}}])
+ .toArray();
+ assert.docEq([{"tag": {field: "A"}, "_id": 0}], result);
+
+ // Testing with exclude $project after include $project.
+ result = coll.aggregate([{$project: {tag: 1}}, {$project: {tag: 0}}]).toArray();
+ assert.docEq([{"_id": 0}], result);
+
+ // Testing with $set.
+ result = coll.aggregate([{$set: {tag: "$tag.field"}}, {$project: {tag: 0}}]).toArray();
+ assert.docEq([{"time": ISODate("2024-01-01T00:00:00Z"), "_id": 0}], result);
+
+ // Exclude one added field.
+ result = coll.aggregate([
+ {$addFields: {hi: {$dateFromParts: {year: "$tag.none"}}}},
+ {$addFields: {bye: {$dateFromParts: {year: "$tag.none"}}}},
+ {$project: {hi: 0}}
+ ])
+ .toArray();
+ assert.docEq(
+ [{"time": ISODate("2024-01-01T00:00:00Z"), "tag": {"field": "A"}, "_id": 0, "bye": null}],
+ result);
+
+ // Test with non-null value.
+ result = coll.aggregate([
+ {$addFields: {hi: "$tag.field"}},
+ {$addFields: {bye: "$tag.field"}},
+ {$project: {hi: 0}}
+ ])
+ .toArray();
+ assert.docEq(
+ [{"time": ISODate("2024-01-01T00:00:00Z"), "tag": {"field": "A"}, "_id": 0, "bye": "A"}],
+ result);
+
+ // Test adding fields and excluding one of them.
+ result = coll.aggregate([
+ {$addFields: {a: {$toLower: "$tag.field"}}},
+ {$addFields: {b: {$toUpper: "$tag.field"}}},
+ {$project: {b: 0}}
+ ])
+ .toArray();
+ assert.docEq(
+ [{"time": ISODate("2024-01-01T00:00:00Z"), "tag": {"field": "A"}, "_id": 0, "a": "a"}],
+ result);
+})();
})();
diff --git a/jstests/core/timeseries/timeseries_union_with.js b/jstests/core/timeseries/timeseries_union_with.js
index b5d5369dcc8..e92e4c4ca37 100644
--- a/jstests/core/timeseries/timeseries_union_with.js
+++ b/jstests/core/timeseries/timeseries_union_with.js
@@ -8,6 +8,7 @@
* # migrations may result in writes splitting between two primaries, and thus different buckets.
* does_not_support_stepdowns,
* tenant_migration_incompatible,
+ * references_foreign_collection,
* ]
*/
(function() {
diff --git a/jstests/core/timeseries/timeseries_update_mixed_schema_bucket.js b/jstests/core/timeseries/timeseries_update_mixed_schema_bucket.js
new file mode 100644
index 00000000000..0211daa29d8
--- /dev/null
+++ b/jstests/core/timeseries/timeseries_update_mixed_schema_bucket.js
@@ -0,0 +1,79 @@
+/**
+ * Tests directly updating a time-series bucket to contain mixed schema.
+ *
+ * @tags: [
+ * # $listCatalog does not include the tenant prefix in its results.
+ * command_not_supported_in_serverless,
+ * requires_timeseries,
+ * # $listCatalog not supported inside of a multi-document transaction
+ * does_not_support_transactions,
+ * # $listCatalog only exists since v6
+ * multiversion_incompatible,
+ * ]
+ */
+(function() {
+"use strict";
+load("jstests/core/timeseries/libs/timeseries.js"); // For 'TimeseriesTest'.
+
+TestData.skipEnforceTimeseriesBucketsAreAlwaysCompressedOnValidate = true;
+
+const testDB = db.getSiblingDB(jsTestName());
+const collName = "ts";
+
+assert.commandWorkedOrFailedWithCode(testDB.runCommand({drop: collName}),
+ ErrorCodes.NamespaceNotFound);
+assert.commandWorked(
+ testDB.createCollection(collName, {timeseries: {timeField: "t", metaField: "m"}}));
+const coll = testDB[collName];
+const bucketsColl = testDB["system.buckets." + collName];
+
+const bucket = {
+ _id: ObjectId("65a6eb806ffc9fa4280ecac4"),
+ control: {
+ version: NumberInt(1),
+ min: {
+ _id: ObjectId("65a6eba7e6d2e848e08c3750"),
+ t: ISODate("2024-01-16T20:48:00Z"),
+ a: 0,
+ },
+ max: {
+ _id: ObjectId("65a6eba7e6d2e848e08c3751"),
+ t: ISODate("2024-01-16T20:48:39.448Z"),
+ a: 1,
+ },
+ },
+ meta: 0,
+ data: {
+ _id: {
+ 0: ObjectId("65a6eba7e6d2e848e08c3750"),
+ 1: ObjectId("65a6eba7e6d2e848e08c3751"),
+ },
+ t: {
+ 0: ISODate("2024-01-16T20:48:39.448Z"),
+ 1: ISODate("2024-01-16T20:48:39.448Z"),
+ },
+ a: {
+ 0: 0,
+ 1: 1,
+ },
+ }
+};
+
+const update = function() {
+ return bucketsColl.update({_id: bucket._id},
+ {$set: {"control.min.a": 1, "control.max.a": "a", "data.a.0": "a"}});
+};
+
+assert.commandWorked(bucketsColl.insert(bucket));
+assert.commandFailedWithCode(update(), ErrorCodes.CannotInsertTimeseriesBucketsWithMixedSchema);
+assert.eq(TimeseriesTest.bucketsMayHaveMixedSchemaData(bucketsColl), false);
+assert.commandWorked(
+ testDB.runCommand({collMod: collName, timeseriesBucketsMayHaveMixedSchemaData: true}));
+assert.eq(TimeseriesTest.bucketsMayHaveMixedSchemaData(bucketsColl), true);
+assert.commandWorked(update());
+assert.commandWorked(bucketsColl.deleteOne({_id: bucket._id}));
+assert.eq(TimeseriesTest.bucketsMayHaveMixedSchemaData(bucketsColl), true);
+assert.commandWorked(
+ testDB.runCommand({collMod: collName, timeseriesBucketsMayHaveMixedSchemaData: false}));
+assert.eq(TimeseriesTest.bucketsMayHaveMixedSchemaData(bucketsColl), false);
+})();
diff --git a/jstests/core/txns/abort_expired_transaction.js b/jstests/core/txns/abort_expired_transaction.js
index b211ef7b132..54418596967 100644
--- a/jstests/core/txns/abort_expired_transaction.js
+++ b/jstests/core/txns/abort_expired_transaction.js
@@ -33,6 +33,11 @@ try {
const session = db.getMongo().startSession(sessionOptions);
const sessionDb = session.getDatabase(testDBName);
+ // Number of passes made by the "abortExpiredTransactions" thread before the transaction
+ // expires.
+ const abortExpiredTransactionsPassesPreAbort =
+ db.serverStatus().metrics.abortExpiredTransactions.passes;
+
let txnNumber = 0;
jsTest.log("Insert a document starting a transaction.");
@@ -64,6 +69,14 @@ try {
"currentOp reports that the idle transaction still exists, it has not been " +
"aborted as expected.");
+ assert.soon(() => {
+ // For this expired transaction to abort, the "abortExpiredTransactions" thread has to
+ // perform at least one pass.
+ const serverStatus = db.serverStatus();
+ return abortExpiredTransactionsPassesPreAbort <
+ serverStatus.metrics.abortExpiredTransactions.passes;
+ });
+
jsTest.log(
"Attempt to do a write in the transaction, which should fail because the transaction " +
"was aborted");
diff --git a/jstests/core/txns/aggregation_in_transaction.js b/jstests/core/txns/aggregation_in_transaction.js
index ec1c62133bb..40d7030fe1f 100644
--- a/jstests/core/txns/aggregation_in_transaction.js
+++ b/jstests/core/txns/aggregation_in_transaction.js
@@ -1,5 +1,5 @@
// Tests that aggregation is supported in transactions.
-// @tags: [uses_transactions, uses_snapshot_read_concern]
+// @tags: [uses_transactions, uses_snapshot_read_concern, references_foreign_collection]
(function() {
"use strict";
diff --git a/jstests/core/txns/prepare_conflict_aggregation_behavior.js b/jstests/core/txns/prepare_conflict_aggregation_behavior.js
index c62b7370dc6..c07f96e2b54 100644
--- a/jstests/core/txns/prepare_conflict_aggregation_behavior.js
+++ b/jstests/core/txns/prepare_conflict_aggregation_behavior.js
@@ -3,7 +3,12 @@
* should not block on prepare conflicts, but writing out to a collection as a part of an aggregate
* pipeline should block on prepare conflicts.
*
- * @tags: [uses_transactions, uses_prepare_transaction]
+ * The test runs commands that are not allowed with security token: endSession, prepareTransaction.
+ * @tags: [
+ * references_foreign_collection,
+ * uses_transactions,
+ * uses_prepare_transaction,
+ * ]
*/
(function() {
"use strict";
diff --git a/jstests/core/views/invalid_system_views.js b/jstests/core/views/invalid_system_views.js
index da2b60d170f..15b4ab6bc3b 100644
--- a/jstests/core/views/invalid_system_views.js
+++ b/jstests/core/views/invalid_system_views.js
@@ -14,6 +14,7 @@
* # The drop of offending views may not happen on the donor after a committed migration.
* tenant_migration_incompatible,
* uses_compact,
+ * references_foreign_collection,
* ]
*/
diff --git a/jstests/core/views/views_aggregation.js b/jstests/core/views/views_aggregation.js
index 537ec3ee008..287bc5af667 100644
--- a/jstests/core/views/views_aggregation.js
+++ b/jstests/core/views/views_aggregation.js
@@ -9,6 +9,7 @@
* requires_non_retryable_commands,
* # Explain of a resolved view must be executed by mongos.
* directly_against_shardsvrs_incompatible,
+ * references_foreign_collection,
* ]
*/
(function() {
diff --git a/jstests/core/views/views_collation.js b/jstests/core/views/views_collation.js
index 169e9309740..65deb11edbc 100644
--- a/jstests/core/views/views_collation.js
+++ b/jstests/core/views/views_collation.js
@@ -6,6 +6,7 @@
// requires_non_retryable_commands,
// # Explain of a resolved view must be executed by mongos.
// directly_against_shardsvrs_incompatible,
+// references_foreign_collection,
// ]
/**
diff --git a/jstests/core/views/views_creation.js b/jstests/core/views/views_creation.js
index 9528199996a..c24a008342d 100644
--- a/jstests/core/views/views_creation.js
+++ b/jstests/core/views/views_creation.js
@@ -11,6 +11,7 @@
* requires_non_retryable_commands,
* # Tenant migrations don't support applyOps.
* tenant_migration_incompatible,
+ * references_foreign_collection,
* ]
*/
(function() {
diff --git a/jstests/core/views/views_validation.js b/jstests/core/views/views_validation.js
index 02c060fd50a..4dea7c9491b 100644
--- a/jstests/core/views/views_validation.js
+++ b/jstests/core/views/views_validation.js
@@ -2,6 +2,7 @@
// # Running getCollection on views in sharded suites tries to shard views, which fails.
// assumes_unsharded_collection,
// requires_non_retryable_commands,
+// references_foreign_collection,
// ]
(function() {
diff --git a/jstests/core/wildcard_index_validindex.js b/jstests/core/wildcard_index_validindex.js
index 24ecdcf77cf..c4a2ea9c2ac 100644
--- a/jstests/core/wildcard_index_validindex.js
+++ b/jstests/core/wildcard_index_validindex.js
@@ -98,6 +98,18 @@ assert.commandFailedWithCode(coll.createIndex({"$**": "wildcard"}), ErrorCodes.C
// Cannot create a compound wildcard index.
assert.commandFailedWithCode(coll.createIndex({"$**": 1, "a": 1}), ErrorCodes.CannotCreateIndex);
assert.commandFailedWithCode(coll.createIndex({"a": 1, "$**": 1}), ErrorCodes.CannotCreateIndex);
+assert.commandFailedWithCode(coll.createIndex({"obj.$**": 1, "a": 1}),
+ ErrorCodes.CannotCreateIndex);
+assert.commandFailedWithCode(db.runCommand({
+ createIndexes: kCollectionName,
+ indexes: [{wildcardProjection: {a: 1, c: 1, d: 1}, key: {"$**": 1, b: 1}}]
+}),
+ ErrorCodes.CannotCreateIndex);
+assert.commandFailedWithCode(db.runCommand({
+ createIndexes: kCollectionName,
+ indexes: [{key: {"$**": 1, b: 1}, wildcardProjection: {a: 1, c: 1, d: 1}}]
+}),
+ ErrorCodes.CannotCreateIndex);
// Cannot create an wildcard index with an invalid spec.
assert.commandFailedWithCode(coll.createIndex({"a.$**.$**": 1}), ErrorCodes.CannotCreateIndex);
@@ -141,4 +153,9 @@ assert.commandFailedWithCode(
assert.commandFailedWithCode(
createIndexHelper({"a.$**": 1}, {name: kIndexName, wildcardProjection: {b: 0}}),
ErrorCodes.FailedToParse);
+assert.commandFailedWithCode(db.runCommand({
+ createIndexes: kCollectionName,
+ indexes: [{wildcardProjection: {b: 1}, key: {"a.$**": 1}}]
+}),
+ ErrorCodes.FailedToParse);
})();
diff --git a/jstests/disk/libs/wt_file_helper.js b/jstests/disk/libs/wt_file_helper.js
index 862d189c85d..5fe8b299cb3 100644
--- a/jstests/disk/libs/wt_file_helper.js
+++ b/jstests/disk/libs/wt_file_helper.js
@@ -234,3 +234,16 @@ let truncateUriAndRestartMongod = function(uri, conn, mongodOptions) {
runWiredTigerTool("-h", conn.dbpath, "truncate", uri);
return startMongodOnExistingPath(conn.dbpath, mongodOptions);
};
+
+/**
+ * Stops the given mongod and runs the alter command to modify the index table's metadata.
+ */
+let alterIndexFormatVersion = function(uri, conn, formatVersion) {
+ MongoRunner.stopMongod(conn, null, {skipValidation: true});
+ runWiredTigerTool(
+ "-h",
+ conn.dbpath,
+ "alter",
+ "table:" + uri,
+ "app_metadata=(formatVersion=" + formatVersion + "),exclusive_refreshed=false");
+};
diff --git a/jstests/disk/repair_index_format_version.js b/jstests/disk/repair_index_format_version.js
new file mode 100644
index 00000000000..46922a98b09
--- /dev/null
+++ b/jstests/disk/repair_index_format_version.js
@@ -0,0 +1,47 @@
+/**
+ * Tests that mismatch of index type and index format version will be resolved during startup.
+ */
+
+(function() {
+
+load('jstests/disk/libs/wt_file_helper.js');
+
+const baseName = "repair_index_format_version";
+const collNamePrefix = "test_";
+let count = 0;
+const dbpath = MongoRunner.dataPath + baseName + "/";
+
+resetDbpath(dbpath);
+
+jsTestLog("Repair the format version of a unique index.");
+
+// Uses the modified data files in the same dbpath over restarts.
+let mongod = startMongodOnExistingPath(dbpath);
+let db = mongod.getDB(baseName);
+let collName = collNamePrefix + count++;
+db.createCollection(collName);
+let testColl = db[collName];
+assert.commandWorked(testColl.createIndex({a: 1}, {unique: true}));
+
+let uri = getUriForIndex(testColl, "a_1");
+alterIndexFormatVersion(uri, mongod, 8);
+
+mongod = startMongodOnExistingPath(dbpath);
+checkLog.containsJson(mongod, 6818600);
+
+jsTestLog("Repair the format version of a non-unique index.");
+
+db = mongod.getDB(baseName);
+collName = collNamePrefix + count++;
+db.createCollection(collName);
+testColl = db[collName];
+assert.commandWorked(testColl.createIndex({b: 1}));
+
+uri = getUriForIndex(testColl, "b_1");
+alterIndexFormatVersion(uri, mongod, 14);
+
+mongod = startMongodOnExistingPath(dbpath);
+checkLog.containsJson(mongod, 6818600);
+
+MongoRunner.stopMongod(mongod, null, {skipValidation: true});
+})();
diff --git a/jstests/hooks/run_aggregate_metrics_background.js b/jstests/hooks/run_aggregate_metrics_background.js
deleted file mode 100644
index 32335852fcd..00000000000
--- a/jstests/hooks/run_aggregate_metrics_background.js
+++ /dev/null
@@ -1,112 +0,0 @@
-/**
- * Runs the $operationMetrics stage and ensures that all the expected fields are present.
- */
-
-'use strict';
-
-(function() {
-load('jstests/libs/discover_topology.js'); // For Topology and DiscoverTopology.
-
-if (typeof db === 'undefined') {
- throw new Error(
- "Expected mongo shell to be connected a server, but global 'db' object isn't defined");
-}
-
-// Disable implicit sessions so FSM workloads that kill random sessions won't interrupt the
-// operations in this test that aren't resilient to interruptions.
-TestData.disableImplicitSessions = true;
-
-const topology = DiscoverTopology.findConnectedNodes(db.getMongo());
-
-const aggregateMetricsBackground = function(host) {
- function verifyFields(doc) {
- const kTopLevelFields = [
- "docBytesWritten",
- "docUnitsWritten",
- "idxEntryBytesWritten",
- "idxEntryUnitsWritten",
- "totalUnitsWritten",
- "cpuNanos",
- "db",
- "primaryMetrics",
- "secondaryMetrics"
- ];
- const kReadFields = [
- "docBytesRead",
- "docUnitsRead",
- "idxEntryBytesRead",
- "idxEntryUnitsRead",
- "keysSorted",
- "docUnitsReturned"
- ];
-
- for (let key of kTopLevelFields) {
- assert(doc.hasOwnProperty(key), "The metrics output is missing the property: " + key);
- }
- let primaryMetrics = doc.primaryMetrics;
- for (let key of kReadFields) {
- assert(primaryMetrics.hasOwnProperty(key),
- "The metrics output is missing the property: primaryMetrics." + key);
- }
- let secondaryMetrics = doc.secondaryMetrics;
- for (let key of kReadFields) {
- assert(secondaryMetrics.hasOwnProperty(key),
- "The metrics output is missing the property: secondaryMetrics." + key);
- }
- }
-
- let conn = new Mongo(host);
- conn.setSecondaryOk();
-
- assert.neq(
- null, conn, "Failed to connect to host '" + host + "' for background metrics collection");
-
- // Filter out arbiters.
- if (conn.adminCommand({isMaster: 1}).arbiterOnly) {
- print("Skipping background aggregation against test node: " + host +
- " because it is an arbiter and has no data.");
- return;
- }
-
- let db = conn.getDB("admin");
- let clearMetrics = Math.random() < 0.9 ? false : true;
- print("Running $operationMetrics with {clearMetrics: " + clearMetrics + "} on host: " + host);
- const cursor = db.aggregate([{$operationMetrics: {clearMetrics: clearMetrics}}]);
- while (cursor.hasNext()) {
- let doc = cursor.next();
- try {
- verifyFields(doc);
- } catch (e) {
- print("caught exception while verifying that all expected fields are in the metrics " +
- "output: " + tojson(doc));
- throw (e);
- }
- }
-};
-
-// This file is run continuously and is very fast so we want to impose some kind of rate limiting
-// which is why we sleep for 1 second here. This sleep is here rather than in
-// aggregate_metrics_background.py because the background job that file uses is designed to be run
-// continuously so it is easier and cleaner to just sleep here.
-sleep(1000);
-if (topology.type === Topology.kStandalone) {
- try {
- aggregateMetricsBackground(topology.mongod);
- } catch (e) {
- print("background aggregate metrics against the standalone failed");
- throw e;
- }
-} else if (topology.type === Topology.kReplicaSet) {
- for (let replicaMember of topology.nodes) {
- try {
- aggregateMetricsBackground(replicaMember);
- } catch (e) {
- print("background aggregate metrics was not successful against all replica set " +
- "members");
- throw e;
- }
- }
-} else {
- throw new Error("Unsupported topology configuration: " + tojson(topology));
-}
-})();
diff --git a/jstests/libs/backup_utils.js b/jstests/libs/backup_utils.js
index c17b2a3d645..9a99e179b23 100644
--- a/jstests/libs/backup_utils.js
+++ b/jstests/libs/backup_utils.js
@@ -64,7 +64,9 @@ function getBackupCursorMetadata(backupCursor) {
function copyBackupCursorFiles(
backupCursor, namespacesToSkip, dbpath, destinationDirectory, async, fileCopiedCallback) {
resetDbpath(destinationDirectory);
- mkdir(destinationDirectory + "/journal");
+ let separator = _isWindows() ? '\\' : '/';
+ // TODO(SERVER-13455): Replace `journal/` with the configurable journal path.
+ mkdir(destinationDirectory + separator + "journal");
let copyThread = copyBackupCursorExtendFiles(
backupCursor, namespacesToSkip, dbpath, destinationDirectory, async, fileCopiedCallback);
@@ -82,6 +84,7 @@ function copyBackupCursorExtendFiles(
_copyFiles(files, dbpath, destinationDirectory, _copyFileHelper);
}
+ // TODO(SERVER-13455): Replace `journal/` with the configurable journal path.
jsTestLog({
msg: "Destination",
destination: destinationDirectory,
@@ -107,24 +110,39 @@ function _cursorToFiles(cursor, namespacesToSkip, fileCopiedCallback) {
fileCopiedCallback(doc);
}
- files.push(doc.filename);
+ let file = {filename: doc.filename};
+
+ if (doc.hasOwnProperty("fileSize")) {
+ file.fileSize = Number(doc.fileSize);
+ }
+
+ if (doc.hasOwnProperty("offset")) {
+ assert(doc.hasOwnProperty("length"));
+ file.offset = Number(doc.offset);
+ file.length = Number(doc.length);
+ }
+
+ files.push(file);
}
return files;
}
function _copyFiles(files, dbpath, destinationDirectory, copyFileHelper) {
files.forEach((file) => {
- let dbgDoc = copyFileHelper(file, dbpath, destinationDirectory);
- dbgDoc["msg"] = "File copy";
- jsTestLog(dbgDoc);
+ jsTestLog(copyFileHelper(file, dbpath, destinationDirectory));
});
}
-function _copyFileHelper(absoluteFilePath, sourceDbPath, destinationDirectory) {
+function _copyFileHelper(file, sourceDbPath, destinationDirectory) {
+ let absoluteFilePath = file.filename;
+
// Ensure the dbpath ends with an OS appropriate slash.
let separator = '/';
if (_isWindows()) {
separator = '\\';
+ // Convert dbpath which may contain directoryperdb/wiredTigerDirectoryForIndexes
+ // subdirectory in POSIX style.
+ absoluteFilePath = absoluteFilePath.replace(/[\/]/g, separator);
}
let lastChar = sourceDbPath[sourceDbPath.length - 1];
if (lastChar !== '/' && lastChar !== '\\') {
@@ -140,6 +158,41 @@ function _copyFileHelper(absoluteFilePath, sourceDbPath, destinationDirectory) {
let destination = destinationDirectory + separator + relativePath;
const newFileDirectory = destination.substring(0, destination.lastIndexOf(separator));
mkdir(newFileDirectory);
- copyFile(absoluteFilePath, destination);
- return {fileSource: absoluteFilePath, relativePath: relativePath, fileDestination: destination};
+
+ let msg = "File copy";
+ if (!pathExists(destination)) {
+ // If the file hasn't had an initial backup yet, then a full file copy is needed.
+ copyFile(absoluteFilePath, destination);
+ } else if (file.fileSize == undefined || file.length == undefined ||
+ file.fileSize == file.length) {
+ // - $backupCursorExtend, which only returns journal files does not report a 'fileSize'.
+ // - 'length' is only reported for incremental backups.
+ // - When 'fileSize' == 'length', that's used as an indicator to do a full file copy. Mostly
+ // used for internal tables.
+ if (pathExists(destination)) {
+ // Remove the old backup of the file. For journal files specifically, if a checkpoint
+ // didn't take place between two incremental backups, then the backup cursor can specify
+ // journal files we've already copied at an earlier time. We should remove these old
+ // journal files so that we can copy them over again in the event that their contents
+ // have changed over time.
+ jsTestLog(`Removing existing file ${
+ destination} in preparation of copying a newer version of it`);
+ removeFile(destination);
+ }
+
+ copyFile(absoluteFilePath, destination);
+ } else {
+ assert(file.offset != undefined);
+ assert(file.length != undefined);
+ msg = "Range copy, offset: " + file.offset + ", length: " + file.length;
+ _copyFileRange(
+ absoluteFilePath, destination, NumberLong(file.offset), NumberLong(file.length));
+ }
+
+ return {
+ fileSource: absoluteFilePath,
+ relativePath: relativePath,
+ fileDestination: destination,
+ msg: msg
+ };
}
diff --git a/jstests/libs/badSAN.pem b/jstests/libs/badSAN.pem
index 18601973be3..e9b01d12aee 100644
--- a/jstests/libs/badSAN.pem
+++ b/jstests/libs/badSAN.pem
@@ -3,53 +3,53 @@
#
# Certificate with an otherwise permissible CommonName, but with an unmatchable SubjectAlternateName.
-----BEGIN CERTIFICATE-----
-MIIDwjCCAqqgAwIBAgIEYtIbgTANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDwjCCAqqgAwIBAgIEFmwgdDANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTMzWhcNMjYwNDE4MTYxMTMzWjBvMQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ2WhcNMjYwOTA3MTYxNDQ2WjBvMQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDESMBAGA1UEAwwJ
-MTI3LjAuMC4xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq6LvcQEH
-8e/xghmIkLsW8q0s/5GylCnIulKlYzkjdvrGQlZhs9T2BgiDbOSowqRa43j/ovAT
-oZzen3bmOFu0rlSK9SIx/a+ETdvY6/xRKRNFS/D4bjp2vH11FaE6f/V1waPzBSB1
-6OtomMR/qKniIi0H20PjHLyLaxkVSQwF7FVWMTFScK6jVEyoPqg1Njc8ESTvrEv2
-vXIXHKk7r+H6V59VATd7bMV1FiVKb+/4Mhb9SI/qXDOdPR4/U5SNr5haIPQVHFap
-TmQic9u/k/pnVp3Iqy5DI3T0PlTEJNIyCxR28pvDGMquH7R6av+6ryNkyM2D0thU
-0GooYQkIRrqf3QIDAQABo2EwXzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDATBgNV
-HSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUxlSdKO0y56x2zPPy1YzvIoPdTdkw
-EQYDVR0RBAowCIIGYmFkU0FOMA0GCSqGSIb3DQEBCwUAA4IBAQA3UyxTgvJN0eCJ
-6q/Hpb7DYp+h9uuO08D5g6CBVLg5lMqbk2mHwxTrKxi3AtB0Ukv8PNIE/mkSbxvx
-UegrWHbJGWxqRIfMZao94ncuVWyA35Bvlx1D9iADtYC2LBA6uiqkB9dlqC5GaUdF
-pwxwOPEx9AKC7UKsV/f0t8E4v/CBOLoAnUZ82M4T7SzLtRSqkh3b6l1QMWjyAAKe
-AiC0bFyWyf2Gjq3hwEOdwZ/4tkMCdnh1y1rbHb5DhaEezeNeIs+HbFMhXLpr6s7l
-brJHCDwQcfTtUB3Vaj8r9k5H3uAi69fr/R++SENkOkalbeNAVLh9GeFqHHp+Hq1G
-b9EFxXOO
+MTI3LjAuMC4xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuuuf9fFu
+64rZa8BKKbPcQLZkMB5YZaYfGAFom79Gs6jqbCfw67fukUQHbxvLz/MArqT1Xgib
+kl8eJ20OpQmTOiEKdlUR2WHJ/FuIwtYFVjF4pDlcW5bP8vZgkrLVgIEeYt/ZpSYf
+JW+IBa/wp3DRFiWz9AFfrDnorI6tk4oW9tpAOFUNcvvgjMyoUFEawpbZHh0II+6j
+uKiGWHyysagOqqqTorxxd/LEV3apHmw7gNw0zHB0ZyYPCQjVgg5Xz1U8peXPbKDk
+h7qJdxdekXqHmBBlMTokwUhhSFqU+LnLbAtHnP+Qx4NEvv4k+Y9e1DYBOL8ml4Yr
+/gKwAuYnB3QgHwIDAQABo2EwXzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDATBgNV
+HSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUAPOr/VMkyhl8UzbPlGyFoXROgAMw
+EQYDVR0RBAowCIIGYmFkU0FOMA0GCSqGSIb3DQEBCwUAA4IBAQBlQu7ajIiU5UKQ
+EAHb/qbwKCmQUawuhJ4l7PhAgGOBWvIpj4u56VR+2Gx//hc8g4FWB/7LafOkulYc
+o/UdRk9mLB/XtMJ+HSYbh3rq8YegVizm4ZkK2UWGgDG2KhhFYwc2mdkHvHE/NbJj
+YVDuSYaEGrv7NZt6RSrykecFNy9jhQPsQZYZv70loyJCtmcD8lTBVvZosiTyY5ES
+FioTOBMMlSOSxILQDIew2NPJnPqqiWfxbUgox+VMDa9cCvp05DC+eaQpJDPwAy62
+PEjVSKU8BkIVZdUgE4QGt7vgLI/TsqCFQPrE2Zf/bR5YsvK8N/XNEUNjx3FXP83O
+sZL2hIQG
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCrou9xAQfx7/GC
-GYiQuxbyrSz/kbKUKci6UqVjOSN2+sZCVmGz1PYGCINs5KjCpFrjeP+i8BOhnN6f
-duY4W7SuVIr1IjH9r4RN29jr/FEpE0VL8PhuOna8fXUVoTp/9XXBo/MFIHXo62iY
-xH+oqeIiLQfbQ+McvItrGRVJDAXsVVYxMVJwrqNUTKg+qDU2NzwRJO+sS/a9chcc
-qTuv4fpXn1UBN3tsxXUWJUpv7/gyFv1Ij+pcM509Hj9TlI2vmFog9BUcVqlOZCJz
-27+T+mdWncirLkMjdPQ+VMQk0jILFHbym8MYyq4ftHpq/7qvI2TIzYPS2FTQaihh
-CQhGup/dAgMBAAECggEASxVQlMlELgDu0CCWXuYRUGEUncqhafJrdqLf6eudiZeD
-spJyVEaVx6biw3i2IMvgXMFaZ2+Jzvm+Y9kSNlZb0KV4Ums+nkExahQCLZ3n7UWa
-W3HTY/kcZzGkzi0FV+PLu0Wa8sO0AQw2ahoP1HtYyuWTGcb1a+VJQjUrXBSv5KXq
-BswClU+pYZL8HtTXK3cjRT7dUTrV7AjN0hXsbAy2O4ncmZkPOBPv+93x7jyzi2oT
-jNAmIkBB6PRxj/XkHGUHe869Rl+kRd0RFfVwy1MhwA8vd80ku8e4Ed+oakMdXmuJ
-RDigiQHghzURKxKcOsbg8Wi+JZqd6P/a1gIyjnIQOwKBgQDmK2y0yawDr+kPxe0f
-9hSEyB7OH0Llvo80E8BSceI/47J7f45uiHjow3PYc/ShBPQAsYed84+tYacTie2d
-UGFj/DYDv2YqZWTuqNbmiPdxgO/xkxOQQ5H1GA2BHGUAH/lnVdxu7MMuXnVDMb+t
-GKen2bDv8tfRC1YzbeX7RuSvCwKBgQC+5ec/15xKofPY9gTTdxxiCIfPuv5QaJlN
-JvWYXWXWX2eayX7cXlSg7wdiFFpwp7oEnS2x77TqJ2yhOjT8hbCkkQJCslqXzPgW
-CSdRO/Hvkax4JN9M5cjze4U3LzO06DxbW5BnHCUPMNPGQLHeS2Ziz97iXq0GcgPI
-ZL2ClY/dtwKBgCIJ8f2ahZHWBgWLI9JCNi6c2dFp1h7b25m8AgkvRmJkbhTNfGbk
-T908anlsTJUzglJH7uJxDqJ5epftIfLN3FlJB0PunlFOxWp2FbHqN43Vn6Z+Nbp0
-A7XXZMffRyCJmfyqOfs9kG/fEEBrrwkOSF0OWJhjtX74yjq42fYbOd6ZAoGALcul
-gFFPMzBK+V97pOdMLdByFEl9vPh63mFcRaMSTS0yA5YXEvKmRr1Q/hx33dK+82Bp
-l+gzdIDktIDsOTAxQilva2SyCvym/1JO1lQVJC3EPEZMM3xkitS1DpoKQ3n7EMeU
-isfbtBs4krTudq+L7mSDybaAt60ebzKLrAoJK10CgYBU/9Gj5bfoh/8WoEp6nXqP
-NCE9DggBg5hgnhnHTcW2+ctz5XsQFpt531vTzCcGQzwtjYwods2zRVjC1TlKYcrK
-MLvqzLQOkk7CQrqibb0SK8MwoOBViFRUvBIZG6eHHeshw4hkgfJTuB3BXDUUQGf/
-zR2vBc+WAv/VN55bxnHiuQ==
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC665/18W7ritlr
+wEops9xAtmQwHlhlph8YAWibv0azqOpsJ/Drt+6RRAdvG8vP8wCupPVeCJuSXx4n
+bQ6lCZM6IQp2VRHZYcn8W4jC1gVWMXikOVxbls/y9mCSstWAgR5i39mlJh8lb4gF
+r/CncNEWJbP0AV+sOeisjq2Tihb22kA4VQ1y++CMzKhQURrCltkeHQgj7qO4qIZY
+fLKxqA6qqpOivHF38sRXdqkebDuA3DTMcHRnJg8JCNWCDlfPVTyl5c9soOSHuol3
+F16ReoeYEGUxOiTBSGFIWpT4uctsC0ec/5DHg0S+/iT5j17UNgE4vyaXhiv+ArAC
+5icHdCAfAgMBAAECggEAI5vhtFPTQrIH63wNZNZr3jQg7/3H701vXP5ftFQDHxTN
+297cCbvXifsAw4zzDeGIPr0UNV7EbGUMdIxVHuGtF4TV3mckaFo1xYqWii+Fgr8X
+8Ykv7A7V/L4s9aV2AO4YINPuPYT+p/4QVq0G1o8qdeKm3pQoasH5bm4b6SCEcXAc
+v5who3anXgKTxc51r/I8xEyVV9lf2wXqVwI7OAcLKsE/WK97BlaffiRStI3DUa7L
+tYbX/JYtQ+H6tuHM1WAGcDQRNRQZ59BDwolOPQi/YoZk3FkI/nYvy6zx8ubokG6V
+RzbQ5mDCZVaP+pxB2sSLgwln3XeZ4rmdmfrVE2VTaQKBgQDy86Z2H9m5ZWqIWAdi
+cY0/RhLkhklLpmdNTAK5w5yWyz//DPrQSSs+JpA1rNX2kuvmyFWRGc426WvtFVuz
+J0kXycKHQI6ue5T2kPab+2e0oQhlHT1quljwv6IOJ+3L/TfREenMl059sLp+uNYS
+uVKpK1d4BnyLxG05A3pcP4kmUwKBgQDE9ZkjYScOmKGh0VMPWavmmiZHXfGgkUPX
+CcyUrXMtMvbPMEMaBSRKXQemqq7GXap6gSF618QxkDgdk0wlgPfzZescg83UHoPx
+3B7RGLVqwUXQVAE1zZ8JJxVMErObtkgUJVbYe+AJYti7XnidwPzYkDSgoENRkAVf
+TX5jfpsNhQKBgQCsbZK6CXbsJvdKFzf+fVrjCmfEOy5v+4UbjhPtJdDQESa1bM/h
+3dxL+vCkt6sPmkzE+XAJUIhT3qzTkjIH35z3viFK/t2FJn6d1FrCb9a1kwizQuJh
+Ciqvi0KHy3zxJyFjR9RoeQajHDfwUlzU4ySwnesxa2EfjWR7b2V7bTh4swKBgAkP
+n27wPkK+pNjz71VKc80VFGO+H6qaZDuVWNMSM7VFnfMkLkIZMHU3WG3DdmzrzDb8
+j9S97mm1T8+UgjFLgJyy+KEEM0jp6noK/WPzNg1mPNb7tl6KSiG6qZEpXxfvx9sd
+aKRm9oSYBo6AJx5izX8NC07EcLRk4spin0jmfy2dAoGAI5Q5Hf+ctMlDIFP38rh0
+ZFCWm9kN303LUW5JYzaaTQcmDiLl9Aiho680mbRzrIyrplX0FRqZWTrKOVy/xXsk
+vl4mDa1cCVXvPWAnHfiDMbOpuCQilgwVWHJIEjAb2kzM67i6Zu9HoLsmvKFRFN8M
+dcRSdkysE93EGwxUw0mjfxU=
-----END PRIVATE KEY-----
diff --git a/jstests/libs/badSAN.pem.digest.sha1 b/jstests/libs/badSAN.pem.digest.sha1
index 00ac89dec1d..3bec51350a4 100644
--- a/jstests/libs/badSAN.pem.digest.sha1
+++ b/jstests/libs/badSAN.pem.digest.sha1
@@ -1 +1 @@
-5D77E7567EDB5326EE99196E077FC491F1EC7CAD \ No newline at end of file
+2F4EBB3F6D06460FA0A61B1B50D556BA5342E912 \ No newline at end of file
diff --git a/jstests/libs/badSAN.pem.digest.sha256 b/jstests/libs/badSAN.pem.digest.sha256
index f9a8077fb77..d64adc98683 100644
--- a/jstests/libs/badSAN.pem.digest.sha256
+++ b/jstests/libs/badSAN.pem.digest.sha256
@@ -1 +1 @@
-124185DAD5425965CEC63AC32C78ECA4664A6A5C41414D0A475151927A1CB766 \ No newline at end of file
+8441DA1B9B21ADF14B3676F957C22C3943257A0A868C197B5608DC06A5E9E317 \ No newline at end of file
diff --git a/jstests/libs/ca.pem b/jstests/libs/ca.pem
index ca3f4277556..7324756755f 100644
--- a/jstests/libs/ca.pem
+++ b/jstests/libs/ca.pem
@@ -3,53 +3,53 @@
#
# Primary Root Certificate Authority Most Certificates are issued by this CA.
-----BEGIN CERTIFICATE-----
-MIIDeTCCAmGgAwIBAgIEUuls7DANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDeTCCAmGgAwIBAgIEIGnWnzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTMzWhcNMjYwNDE4MTYxMTMzWjB0MQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ2WhcNMjYwOTA3MTYxNDQ2WjB0MQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwO
-S2VybmVsIFRlc3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDl
-0p4T7cqWDu/0AZ+5LTrt7U66WVm0Fm4yU8ZJgYpQ7BLuIGb664/BqpvitrKzogwh
-4O61sO1UtKOiD/KiyTjq8SzA1Go9WtdsIfDQkz6lU1cgy4HChOw/kLI6i012tg9E
-UzSoH+bvLxr18LtpOvyY6yLiT824AqN/Q/NjvRNrihh5HOcDkRR8+XzcWcg4fgKo
-8RvnEHxZ3jY7gpT5URfaisyOzNImWvB3hWjQseo7BpMIJLes7Sp2TSFtaHw0+Koe
-t2e/Ex9ls5X1fmN2Y5N9hUNN641eMMXUqIPdPq6mSeF7CCHWBETG+908TFBuQQJp
-ZJ8CmKeP7qJLxciseL7lAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
-hvcNAQELBQADggEBAHtFJmKTdyEGJlnl+zKNbOWK6+H8VglYQdWFojNXrWCnqiuK
-4NdEv8lTpEaUuV83Dz4neueFGiw9w0UIpspRPPahR5CVkVs1Oxy/LD3qAKPmxcJy
-nfj3eEYY7CSpc7TmNXHRFIWrv+40m7UJvfi+ns2MKL7IppY4A1bAwjoozvAI4rD+
-CkU61xGLYAD8YjzhNEu88LrIkV0JluBmsMen8tUce3rzVrNRouWpcc29am6JWyB6
-FLsPhUfHDZnxKl/SosXd2JvEDj27NvNtAEydpPQB4084KjDqfVzyJgMXLflkXBDS
-pdhzraLljLpRKZt6FvfDBDw4DzsW1abYUEUGJNg=
+S2VybmVsIFRlc3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDU
+tM92EQ+UJAvDZHjcHGCM5M2E/wHRXWV6z3pXNT+cZliEsUbCBqwA+rs3KYyT0NxM
+2bxDo7/yplFGEb8Kz3gZJGiXcp0WEqZKN8yfTd6p2OTzSlQ/Yw4wcsfnhDX/i2HK
+NQVh258vf1e4t8spr3udsPnfQo0ap/28F3Jq2QxGmKiTPQ2xdyWvk/K5zABHX4mu
+3c29FdViZpcYoKCdYhIsO7IWPBvvPQEqRDPRU/UDweYbJFyrlWNWMCislj0EfGIn
+LBhtXxeZHIXh9fWO8DfMzER+r1fIhxX7lvzdpyT+t3NcOGSWYRKcG8q2+iUnCK4H
+2a2Vg5YKQYGGWmkEQ++XAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAMjiHKAOjasqJPeqSaibtcpClQ2qK6xVMvAdX2YofNzO9/WD
+T1vqF06nuUlUTN+onacW9bT/cABzX2WmBlXH3N0kkr3bQ3dZy6KJpZnLhat3TLYd
+pYWbbVvHUJ31DGnZXNpWzvH/7KSK/IUixfjlYXaKocRNacXtRlidKN1IgTjaMNvL
+gTGaeiaylRYQ0wwirxVJWUzCkRahVlu8nHipl4oWoRfzCxeKGLpXWPBBVJPmupxJ
+qeU0X4fppEYMfXBZLoA5XFPeGcA+epZxNCOEP9f+0CxLmJibe/IUWRcNPS2WWznT
+MV/vxlcqKt0YqxFFk8LzbYMfKa4RXKvk/xpy87g=
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDl0p4T7cqWDu/0
-AZ+5LTrt7U66WVm0Fm4yU8ZJgYpQ7BLuIGb664/BqpvitrKzogwh4O61sO1UtKOi
-D/KiyTjq8SzA1Go9WtdsIfDQkz6lU1cgy4HChOw/kLI6i012tg9EUzSoH+bvLxr1
-8LtpOvyY6yLiT824AqN/Q/NjvRNrihh5HOcDkRR8+XzcWcg4fgKo8RvnEHxZ3jY7
-gpT5URfaisyOzNImWvB3hWjQseo7BpMIJLes7Sp2TSFtaHw0+Koet2e/Ex9ls5X1
-fmN2Y5N9hUNN641eMMXUqIPdPq6mSeF7CCHWBETG+908TFBuQQJpZJ8CmKeP7qJL
-xciseL7lAgMBAAECggEAKYfU/x7yhAlw/TQp6+mrg4Flv7ETz8JZ6YhQBcp99z+h
-8Bw039UfpkyxXNfNFT8MWDbwjC7LxIncJBYjr50TRwmMH9CC3lGDKkw720Uwhem4
-jfmYmlEw7A+21XOE7RXbTmqG0nbpYYGuqpD1HQAG049yP1lSgJUhfIcH/ZcWYlE7
-jRAIwkKS5L7YWkY+vrKUMXnDhhnKdXO3ExhsL/kpQaiJAWXUTW90M6NRvfDleDZg
-1lep/W/JJlqo5rpQ6cF7jAAinh8XyDv74Mz5GYKP0otFlhpJ9kPXOSBLDxrC1WOV
-lwwHHgk9wcrk4gRRgX4XCZxtXp/BV9Ikicro9zC0AQKBgQD1Z7x4NyeTYH8AHEK5
-d08z1HXX3Z/QcqgDaSglfiRWcUpnP5EC5B05Y0K/DtOuW71X9/FYVCtSAERFS4YQ
-hY5gWjE1vU8MEa7Vpn+S67jtZrc0wJS5wGet7pl11/bVxR/o/6dMoqwHkEVbV1GX
-whg5XVi1pHpd53ckO3xtSZW75QKBgQDvvqkhuwaK1OQ1sgxbcy9Otb6JBFT4GEbP
-WSmTrfyiDM3FyKezx2bbyAfWXg10zolt+a/7elqB+Mt26s1EJdHjRmwn+LGCYocu
-OzhFwW13yPaQC9x0y8Rvcdxh7Qf+kynzEHOSCa7AW68fJ2E8RpJ6EXDF33Hr2mlC
-4UiKcUTHAQKBgB40EEwzbZmD7N2UnNm6x3K3mXFiA4NiOS+CR8Clj89bzi568lwK
-u1YO0240YvU4sUscZwXaBiLniX+F1hA+f9F4CEp27D2uB3igL19jx7TgSXgio6tg
-9OHBVf3dALI6urywimSyOL4NkZu2WYJ2DwkwZfSlM7JPBKje8Wd6AQXJAoGAHc6C
-kKMECTa2uMZOKwCDHTITYk2bkszR4O2g8a9r/WnCG5j64Ksl6qVP9CL1YVRcWcP1
-UTrBDe+0vDAtHQ/mrG8Q+1c8Go3NaL4MHQATcBUYMoiG/C5pWcG6OKKTn98EFCgz
-djCl/VxoxWLMAAZ2J58Lek5xh3U8KQiBUFUMzAECgYAy5/m0QQojrdsTM9gSv8RP
-YyHDleewjFlyQkR+74XBSGZ7x4/FaDecKum0Ohci2Ehj/DUdSTCZL94ZEvd1XEyv
-hlwpVnvnKQdsnXWWbS6r+bmj1GdNheHrbLFnc8UhisWPcBeRKUucspoM0sfOVyky
-NasRHILUgeKTTFJscxgVJQ==
+MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDUtM92EQ+UJAvD
+ZHjcHGCM5M2E/wHRXWV6z3pXNT+cZliEsUbCBqwA+rs3KYyT0NxM2bxDo7/yplFG
+Eb8Kz3gZJGiXcp0WEqZKN8yfTd6p2OTzSlQ/Yw4wcsfnhDX/i2HKNQVh258vf1e4
+t8spr3udsPnfQo0ap/28F3Jq2QxGmKiTPQ2xdyWvk/K5zABHX4mu3c29FdViZpcY
+oKCdYhIsO7IWPBvvPQEqRDPRU/UDweYbJFyrlWNWMCislj0EfGInLBhtXxeZHIXh
+9fWO8DfMzER+r1fIhxX7lvzdpyT+t3NcOGSWYRKcG8q2+iUnCK4H2a2Vg5YKQYGG
+WmkEQ++XAgMBAAECggEBAMe8phfje3KLyrQHk+p1h0Cm1kruP2G/xzxkuihMK1iN
+TtADvEMUis48pDLvhD+F4GkWCVCm4udTwHwAzBm1qrxJUSHuEY6ZoqeM8EwjjlSG
+BLBk+umu9bMPBaLkpuQ5mXGNCmnTFw8+EDy38kJJs9XnSyyYTPJcD8thZSLqgDmF
+BvGyIBOBqp8B93wLuqhfcqukaLD8+CVkmqsfBY5kCgLgpXlN5k3rZbjBDot58kBX
+8Dy1SjiyChIH+Egc/jx/ZdugoAj/thH9YMzOJickIIY99X6T3IRccqGOnW191qn7
+jeQIEduQMu6eN8HxPAKSQO7o0XPrItmhfrNUnFZ6KuECgYEA/dPXnTpEyz2qG0JK
+Zt5gnQ/y6pxlT7hVmXVRnSZInYqaMok6S0KnvbDa/5TagsD7tlCInxONQ1vlf193
+8DIILbKRq4UiiUPbMCg5UGetG2DpPDNlm0/aiFnrrZpz08hnhYRnXornOMrYAw7b
+ytA6X7Ghd9D3mtdVgbezu/q/7pECgYEA1obeOIvsCgheKkFz2i2hZQBtgBJ8MfEt
+/zt2x1dtnZXRgE7f1LoBAB4g6++qUB6zCEyr6P9hr966fAq+NON4Gec3iyWDCjKD
+vkUDJ4Z83yMmdcyh2419bkVDAIIYkJI9RuTqfIOckRRWU7esFSUy5qo1IVgW3Lu5
+htPiAknP36cCgYEApvKL0VT+5HKVjMJIL2q6PvO7gUYGeK20V2/Lk0IX5s6/5tdN
+aSzZKTHGiO393pxRsrM7eO2iLxilVOaU+33c1TmrCBZUBdaEtyLtt43JVMWkAj2H
+6eRWxvHlylRZNIWOWUohtxRDSp5X/4LpW3cjvccWfbkK8mQJUH1kERK25JECgYEA
+iHNOY180aok6A9yP6OV/M7Qa8gxP7KBAJojXGyIT+djyYY9JtY/91OpU/Fz70mxE
+afIConfV1bxwlzdqFk/c83TrEllwyQqqW1qgEALt6Cv+aY0YIoMTlhD99hPJtiMe
+ULqIH1zDOFBcPHGmRejcQHVgx+201P+emRCqP9RdIR8CgYEAy5Ol++717xe8/tds
+bp7Vx98mUxuM8iRd/C4vvXDN/C2yZLaXaFm++Vc+AESIHNX+5GdiIBGc5pPYLBxr
+JTwVtXXHDHVsTeNVZ2vRv9hYuaCYf3oioDdW89V6t0KwHiOrahIeXQXQ9lZKAVtK
+AIq4PHBOGbgPGW95aB7kIyKsIoo=
-----END PRIVATE KEY-----
# Certificate from jstests/libs/ca-2019.pem
-----BEGIN CERTIFICATE-----
diff --git a/jstests/libs/ca.pem.digest.sha1 b/jstests/libs/ca.pem.digest.sha1
index e771ea3472f..094d60417bb 100644
--- a/jstests/libs/ca.pem.digest.sha1
+++ b/jstests/libs/ca.pem.digest.sha1
@@ -1 +1 @@
-F2FE3C922B6A5408AA06C1A0EBBEAF0363C52046 \ No newline at end of file
+13D573B8FF4C9E4AAEF37A360BA2D52AAD8FAE48 \ No newline at end of file
diff --git a/jstests/libs/ca.pem.digest.sha256 b/jstests/libs/ca.pem.digest.sha256
index 6537d4ba893..7f833323449 100644
--- a/jstests/libs/ca.pem.digest.sha256
+++ b/jstests/libs/ca.pem.digest.sha256
@@ -1 +1 @@
-6796FD7146BB58523E125BCA35AB2D882A6A2699C82BA63496636386703A998C \ No newline at end of file
+ABFD56D37533C4F7EE311891B1749818EDB90DEBFC957968A37066688598C607 \ No newline at end of file
diff --git a/jstests/libs/client-all-the-oids.pem b/jstests/libs/client-all-the-oids.pem
index 97c6d451647..c0ece75e80d 100644
--- a/jstests/libs/client-all-the-oids.pem
+++ b/jstests/libs/client-all-the-oids.pem
@@ -3,10 +3,10 @@
#
# Client certificate with a long list of OIDs. Ensures the server functions well in unexpected circumstances.
-----BEGIN CERTIFICATE-----
-MIIG4zCCBcugAwIBAgIEG5Pd1TANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIG4zCCBcugAwIBAgIESFwL7DANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTMzWhcNMjYwNDE4MTYxMTMzWjCCA/ExEDAO
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ2WhcNMjYwOTA3MTYxNDQ2WjCCA/ExEDAO
BgNVBAMMB0RhdHVtLTMxEDAOBgNVBAQMB0RhdHVtLTQxEDAOBgNVBAUTB0RhdHVt
LTUxCzAJBgNVBAYTAlVTMRAwDgYDVQQHDAdEYXR1bS03MQswCQYDVQQIDAJOWTEQ
MA4GA1UECQwHRGF0dW0tOTERMA8GA1UECgwIRGF0dW0tMTAxETAPBgNVBAsMCERh
@@ -28,44 +28,44 @@ ETAPBgNVBC8MCERhdHVtLTQ3MREwDwYDVQQwDAhEYXR1bS00ODERMA8GA1UEMQwI
RGF0dW0tNDkxETAPBgNVBDIMCERhdHVtLTUwMREwDwYDVQQzDAhEYXR1bS01MTER
MA8GA1UENAwIRGF0dW0tNTIxETAPBgNVBDUMCERhdHVtLTUzMREwDwYDVQQ2DAhE
YXR1bS01NDERMA8GA1UEQQwIRGF0dW0tNjUxETAPBgNVBEgMCERhdHVtLTcyMIIB
-IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmyM6iPTPfHHFKXdzcmxuEwA+
-hFb6REa637gjP/XsTh14y487MDb+7mUqfi2uF1Up92doba5sTnEwMHXdcTj9ma5s
-OCCmKm6INb0VxH4Uzjttz/+TeUTmur2xfMpTpeGAYxYKecGBjlbLqc9mJ1pvvklL
-/sD+SSoNtSKBgbxJIIU5V+Zkiz2k2nrlpaMDzCwnB7fifbGRdy4yrvXeyvn5Wgfh
-trIHTs/Z0egIhZW9E5ud6fy+fndZJ/V0Z7WuS5xmtUsErtIBvnUSzkdcSpE2aNZy
-mtsEvZvj7q+fTy9o6G3i2rX/9MrKeFD83MO6b6G9TB5v/WDLMJXRpXi0DMQ9VQID
-AQABMA0GCSqGSIb3DQEBCwUAA4IBAQDeF+wXMn+P6FAEY71C20/8CsSxk1mmTc9j
-+XxF1tnVBTRZfKh5YdMIPgOuxwtndzdBJk6pt3unpa2QTQKdAXM+j7ZfxkvwgSHo
-DS71NipPjLoZZ7OUvER4hDxBslJ0+EtRStFiib5edhJ1O0CqUiUeYM3+JXizjP9h
-eB0WGWbS6z3K9dDy3xv4/y78K1/so4fShDYIO8Gf87ZBF0C+Wdau4BHc/YV2dnX3
-6VG6mnd7ECJjMx3xKIvWuPE8gnd8edrgv0UX64rzh+PNvhi4hESD3Jay+NO+LEMf
-+C4D/BDf/7szGL0V1vBh0Vm8p2ObEBubzlSxDUCLUsTF26e9WI3/
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqN/+QfDLC21iZUh9n/sxub5Y
+ttMKWeEZjQbqOaRZW45VxfPFj22OzNKookMj5rzPDjGdf2FVcL20erRF8LiaHTOg
+2T+DSY/L0tiSC3qvvzD+/bSar/2WCKDI+tPfLv3HpAhdMVD6BIUBK8W/ZNI+oLVw
+g5+vQq9iATb1/+lW1xv7j2IxtTkKZgGbUdlanO0bUjcj80memR4bUpBMzR6TVppT
+sPog09sY5Y6xgv9zuU9u20HCmTQLI5PG50dtDGniQj7KMjIclzc4jY7153ikL28N
+oViYVDMVSrQzROryo88DLET0K3w8xEykS91MXBHbBmhHnKw0jvtLZCp8blkJ+QID
+AQABMA0GCSqGSIb3DQEBCwUAA4IBAQAey9FFfRBseYNDrpgwROrp85v4RYrE/CHG
+opfqY6QKjHjFmaL9nJUwBiWSnGr3kNAy9Uj0LL4lDCYFmtzVzCcJc178LOfEN3WI
+n2kSI/cZD/IuQxEurrJ1CoBjJpNZECbibCxz9oT67vWYokgrVoooBUNUO1PiHpiY
+sbHFK32NhTWqq+M3jM3uGJ8vSrOolOIaCWN4qc4Ln71M8XlNSNI2kdUQ1uMWg6SZ
+Nhkhn7btAlKNFdZ3poYuU+ySxtLHOzQO70IxFBRNetv8Y+28khL4Y9I8sN93RMWh
+J2gXo9VVDCiMr0H5sYwk7Ix3kVsy+WS2LWkafFqKStw2AZkcR4iL
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCbIzqI9M98ccUp
-d3NybG4TAD6EVvpERrrfuCM/9exOHXjLjzswNv7uZSp+La4XVSn3Z2htrmxOcTAw
-dd1xOP2Zrmw4IKYqbog1vRXEfhTOO23P/5N5ROa6vbF8ylOl4YBjFgp5wYGOVsup
-z2YnWm++SUv+wP5JKg21IoGBvEkghTlX5mSLPaTaeuWlowPMLCcHt+J9sZF3LjKu
-9d7K+flaB+G2sgdOz9nR6AiFlb0Tm53p/L5+d1kn9XRnta5LnGa1SwSu0gG+dRLO
-R1xKkTZo1nKa2wS9m+Pur59PL2jobeLatf/0ysp4UPzcw7pvob1MHm/9YMswldGl
-eLQMxD1VAgMBAAECggEAH7FkOWtt4dnqMez1uEf/esE/hFCygvVCIwceqGfolRK/
-RTKnIFPz46bmNe3GFX0v/BtzgYizFplYA2ZozUMbx+QStqqw15VKHVRaGJC7VmBc
-sDPhoFIbosWy9y/sQ8ScMmHj1Pjbq0T/CVtV3q9Cici2jj5GFJNTRpBcjbD17X8I
-XCKbb76FBAudLlrJZPUHdpq98i0VFmxl2mxBAUOqpTM/jeAfP2exexgdkyIq5vNH
-UhQYAztp10bycvMzjhzHdTOMcqTzgn5n44YXe4m8A2KpWSSB/TljnpxvguBQUTli
-Ep78jUjAr8HP06Xt6mjNPMa6rXUpfAqto0yv3xNrIQKBgQDU4SGCLIbJmMjtaoGM
-iVaZhOgmgyJ9Rb5y2q3uaZrQQuRdIX5Ft3M+E1V64kaGHuRB7kPhCkKBgDrtjd+b
-OAaPNP9sAIPbL8TTMiF7kwJ6RsynGcxwJVoUJYa/oy+A0z9i0gsnDJW6mMsjfAok
-gFi68VJuG4rSKsgt2ENFnRLVBQKBgQC6j+UBh8ITUVy+V9TwdrXrNdiRMoQAuloW
-8omrHVYZU+guUQrasktuMWavzVx2+t6lxgXTK5O/XjZ+Ij6AzianCiWvt8WkxoED
-N81KZUucK4wtAVnu77889NwBYrZuTRPltYdTsjuVMX5+3D2wz+w7WkCqLj73dd4g
-0HtTFC84EQKBgQC08IYituX6BDsEUTq70SAibK1FzsBJ6jXuOaEMvAYybijcX9OM
-PlldseE+CYYYCbnJsFNRu/67Q9rSf3xH2l746fsQOX/ZlcieGkYLWvEILZVVksAJ
-sjXWWe8mg/Wkcem2fQGttyys5aIEDzIvxEem3edKX26nJGXxUZgcW13eYQKBgFfl
-hbKj4JczZSu0u/mTJICt/Nvj3fdt1RYsrRn2l2MVejWgLyn8iLdhBQ1dBuxzo8Sc
-uI/WXyTxYWEqByKufd2DVWAliDPq5ku61bjwYqAwkDmAAnwlbodsod7xQBxVqkM2
-tIyFU7cl+4APie0s+RK5oe/MHBSA7ues8f2ha+HRAoGAQZKau/BrhjfGraunQYJM
-nAbVHrJBiHtc3c1Qv4reByH4r50LLi3OyoLI7yqM42Cf5AYHTvK4czmz2kTmN3hy
-mP81DcId+YvK40bz8+pc5e6DjYonLOYfYlFZ7s8xWeTpFyBjbtCWfFO7Itft/UPY
-QLNDi0UvbJmnwafNCPEQBDo=
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCo3/5B8MsLbWJl
+SH2f+zG5vli20wpZ4RmNBuo5pFlbjlXF88WPbY7M0qiiQyPmvM8OMZ1/YVVwvbR6
+tEXwuJodM6DZP4NJj8vS2JILeq+/MP79tJqv/ZYIoMj6098u/cekCF0xUPoEhQEr
+xb9k0j6gtXCDn69Cr2IBNvX/6VbXG/uPYjG1OQpmAZtR2Vqc7RtSNyPzSZ6ZHhtS
+kEzNHpNWmlOw+iDT2xjljrGC/3O5T27bQcKZNAsjk8bnR20MaeJCPsoyMhyXNziN
+jvXneKQvbw2hWJhUMxVKtDNE6vKjzwMsRPQrfDzETKRL3UxcEdsGaEecrDSO+0tk
+KnxuWQn5AgMBAAECggEAQv/DL0QqOllmbUqKVLtjKg8jwT0PYUNWUMZKjR3wOcvJ
+qeSiH9pWilqVfvLmPnfwKfBzTQM/05/gB8KX8P48XpOKIEb7fmbndbpojtdY/KCi
+ueM6b9JLARdRRXpjlJAo8aJD3voCh2KBaW1mFsj3AemaPw5OiUVtu4+jn6liw6p4
+cpHhsXnPw3OtHF/onOCVMEIFQYAHF6uAmZb04/j5UfAFxndJQ5QkgDtBGSI6kuHq
+f6DkJlMfemElAsAjw9sQ8sMTuw/DtTvDz0UTy6c+gME/ubKbwPSEYxxlOlDNDSg7
+9RiB+Qn+L+zco9kamlUCrj2uj6UIWDEhFC9gtQ1o5QKBgQDQIWAEMpZ49Lzcs7+Z
+ufsbhHuc82Y1ulPl+jigLHBzKD2R0rIVFaWDVMHejcHxWCjqQ4TnywKaFTFQREHi
+625OAsDOszftNkvDIylzxt5pKrN9xxBgCWEYRwznSdGgjL4saDsEsXRp6JCjdfms
+v5dyD1kUX4jEKoVYX1yiCiK1IwKBgQDPt0cL36SiJeyhFGrGQ7Ae2VQr0pNE4Ilc
+h8YhHRzHjODe6JRacQ3G6LIb9egUlAxdIqXd9Db/IDMIUOB5mQs0zgTxhVe2XTuX
+znrc95WmlWYqL4sReYQf5ERumfhVbaCEZxIHK4pWR9IhiUMS5qZzNkkOTdnIa9mq
+JaesF6Z8MwKBgDbOsyQn1iwf9qP/yZLHwPJsHskj52R6nqFPFR5I1Yvdquj9nNuk
+iaNd7HeYyNuvJYcbJKKNeS/uKMBEWT1SVgfA/djwpOeYhrbqSX4tfmAfWIjkpNFF
+ZwYnn6RAci1fIq06/V+tA0Tocz44UPlGsrDcjc6pobBWqiqtYg1hseYVAoGBAKvI
+r4EqXEWdh61P7V467JUWt33mkNUNvYxA3aLVKM//upmfT9HcXcB7AZIONPmP1wnP
+dc2yAynLv2jJOlxWLeZl28DCvl+bi4VoxkOonqM+O1f4KdMx5AtcBRxTSgWcvHvD
+oi073RSuISKLGmWvS0lNQ+4IhGw0hbcpnRm+FXnxAoGBAI6Bm8SmUHQyABiOTg97
+2IRsG8if2pbYluMVpwu/581tcj5FBh4/aDoQIUJD6CR4NytzXICjvJY8wL31A2w1
+jheJstb6OaR50tvhMpgzbH+b6GrV2sRmX3xNq5cRS6wJgRvQPT8JoHwW/vO+XxLV
+OyDEVGAYEmE+DawIHbQdxS1O
-----END PRIVATE KEY-----
diff --git a/jstests/libs/client-all-the-oids.pem.digest.sha1 b/jstests/libs/client-all-the-oids.pem.digest.sha1
index 73e3de5f333..79047c05e73 100644
--- a/jstests/libs/client-all-the-oids.pem.digest.sha1
+++ b/jstests/libs/client-all-the-oids.pem.digest.sha1
@@ -1 +1 @@
-0016EC9A837049B43DB4AB18C4C67D5D619B61CE \ No newline at end of file
+882321AA90864D3D808E80BA786ACFB3F3981B21 \ No newline at end of file
diff --git a/jstests/libs/client-all-the-oids.pem.digest.sha256 b/jstests/libs/client-all-the-oids.pem.digest.sha256
index b400a803ce7..c9d7690166c 100644
--- a/jstests/libs/client-all-the-oids.pem.digest.sha256
+++ b/jstests/libs/client-all-the-oids.pem.digest.sha256
@@ -1 +1 @@
-175666580D5CE2A76842C7B769F4504AF39C8143A75580C97877A12801F85496 \ No newline at end of file
+FEC0989BA68EB2861C5BE745250F617A3D37028AA7B50A17E8EFAA23294BC03D \ No newline at end of file
diff --git a/jstests/libs/client-multivalue-rdn.pem b/jstests/libs/client-multivalue-rdn.pem
index 0db618cb165..16a3394540f 100644
--- a/jstests/libs/client-multivalue-rdn.pem
+++ b/jstests/libs/client-multivalue-rdn.pem
@@ -4,50 +4,50 @@
# Client certificate containing multivalue RDNs
-----BEGIN CERTIFICATE-----
-MIIDUzCCAjsCBAc+yLIwDQYJKoZIhvcNAQELBQAwdDELMAkGA1UEBhMCVVMxETAP
+MIIDUzCCAjsCBCLEriowDQYJKoZIhvcNAQELBQAwdDELMAkGA1UEBhMCVVMxETAP
BgNVBAgMCE5ldyBZb3JrMRYwFAYDVQQHDA1OZXcgWW9yayBDaXR5MRAwDgYDVQQK
DAdNb25nb0RCMQ8wDQYDVQQLDAZLZXJuZWwxFzAVBgNVBAMMDktlcm5lbCBUZXN0
-IENBMB4XDTI0MDEyMjE2MTEzNFoXDTI2MDQyNTE2MTEzNFowaDEyMA0GA1UEAwwG
+IENBMB4XDTI0MDYxMjE2MTQ0NloXDTI2MDkxNDE2MTQ0NlowaDEyMA0GA1UEAwwG
Y2xpZW50MA4GA1UECgwHTW9uZ29EQjARBgNVBAsMCktlcm5lbFVzZXIxMjAJBgNV
BAYTAlVTMA8GA1UECAwITmV3IFlvcmswFAYDVQQHDA1OZXcgWW9yayBDaXR5MIIB
-IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArZXofUkc+Ldh8DIfOKsdYix7
-LkekzelazhEWLdVE3go5Icq23phyMuLid9ptrOGee2sFZTYlJ6tz1YK/gWzsRa4S
-fpnjWFyDEJSVfT+CB4rbKHb0nVzZG4/g53pO3ubd1ee1O6/JQErbdJEhbSB4aDWp
-T7HMEFhPEsPeWT0TpvfBQF6pb5ejXBNXjUxIgfHXS8Y71hpj6Fl63fGZ3PgVUfN0
-lOrS8P+fKDxp1jpOV21wXzjBfv982HCjS1jgx2per/ug36Lu9I0NgeuY+/lqnNp5
-iY/bsQ2ot1ZuZC5tBPCpGUrtpH5HxLdbT60rrBUYlLkN1xdKTGat1Zql8KG0NwID
-AQABMA0GCSqGSIb3DQEBCwUAA4IBAQBLQSo60nRj+hzz2K6kxdRQ+vqBO8Hd7/05
-8DutTuEJlMSP+UyTj5K30mq4wLaNMDbI5Hrrvm8rAbPNXo4gqjrfC1uVl7mesZ7q
-FP20V08exC0a6O2/UDfjw+6fmexQ4x15G7OMJQtwlurZ+Ox9xualMVLATO9W5Mi1
-blEv6BymMnPL1IAxkZjriGzhAldWl6pHamONE/i9SaPGWEe5Lesgcwj1jKWFQgDc
-oP11D+Sy1MLRANdkM8ujh/EOojNjejSAm5wRCSeTvK4S4qDythrDCW323Xpv/ME5
-RYu+RkBJ2tV69lPDm7E69FW0UQvkTsIYHjizTURwfNgP0K999yTR
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtLWIrwqndJQaCOieJBjQ8in+
+evUHQmTae28A8KtVDGspHzQIfRPiAzrOUXngPOm7+U6twDK2ZGD4BQjMF5U/rz0S
+JlCCBTIvDeri7vGm57JT5mqmk5wPJlubLBFNjkroh5ZWHDxNz11zfJ7no1eSoZyz
+ykLJp+MCOw3R9htuq4ZaKNnhgBz0LqyGSw5W4aVh/A5JOXc/ey80qFuoaKVVVz6e
+QGKr+UT4kkBFmQ5Ibrm62zNrf13Rt2B+TyD3KjPGei9anjyu21Jgy2IrNgX+RWyt
+MNbSZBsibffow9a0IZy5zgaKyWuxp5axwmzKi0J27oUnVxs6g5Oq9PforNJV1wID
+AQABMA0GCSqGSIb3DQEBCwUAA4IBAQBvFPx6SyKKog6FF7f0Ehrp4EVzJqR8Fp12
+5d1mzWEr4OrSKjmwqdV5+MpsPZHIPI6CZJ1gBOguhOZbtmnlSUlT7aWw3G66L4OQ
+7NERoB1kPrcu6wQ5L3YuxUv0vZEeUiyzs99HeD52j7mXZjx0ywqE2Kx++v8NEFKp
+cOUmjK9w33kgCY7Y2T9SPUOOlrXwqI+s6K+td9b2e0R5bziCE6g6/ift6vNuWIpz
+ngC6OqVllLOyHkVxAzedZyd1oG/3kyq+g+mNo5DFHhc78SFg1zayUO9ALqDBorHG
+F8ZfUP0bVawkBFpybPLo5Ky9EetQs+7hZrYcbJlk0YCHG22T/0Px
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCtleh9SRz4t2Hw
-Mh84qx1iLHsuR6TN6VrOERYt1UTeCjkhyrbemHIy4uJ32m2s4Z57awVlNiUnq3PV
-gr+BbOxFrhJ+meNYXIMQlJV9P4IHitsodvSdXNkbj+Dnek7e5t3V57U7r8lAStt0
-kSFtIHhoNalPscwQWE8Sw95ZPROm98FAXqlvl6NcE1eNTEiB8ddLxjvWGmPoWXrd
-8Znc+BVR83SU6tLw/58oPGnWOk5XbXBfOMF+/3zYcKNLWODHal6v+6Dfou70jQ2B
-65j7+Wqc2nmJj9uxDai3Vm5kLm0E8KkZSu2kfkfEt1tPrSusFRiUuQ3XF0pMZq3V
-mqXwobQ3AgMBAAECggEAQS3/iP/JpaiyWU9wwsYZ9/Gs5VFYlEsR4juvQNGKlPdw
-wXwNU6MZinsAP7HgqeBkMoKamYkNxYoPKjZ4s2ATjgyRfEFLiTPfsPuh8FBHAo8E
-wPp92pLxIPTTJggakn9NABOLzVgx8PbK1cfjLcdZ/wNbSoYAEokeU/UBSi/xb6mL
-WkTpA4y2rxGq/Qv0jJl7ccFkq9RaSisAEADaE+rS7HX5TXsXUTJ7FtMu3Vkz1khi
-2OnY6KPdZ4j2+c4au14EVYNhdaOWy7x4hfhiO3//APFZnTb6t2fKUsDOjx5zVDCV
-FLZisdQUi3T2Yy4ErwYQ8iodHFNXKkMIxObVkuaayQKBgQC26slrCRvLH/TdHEAU
-3KULPY1uoEdVsRH/9oWBPb5hryBuOBtbKxohS0Z1LLgAb87wnQbEzYXJwLuNGSqg
-ZV8Wk22CiT/NFRcvLD6YpxO9intb2z9OVFXohdbYc+GTJCSX2ySS19xh0pzpR1Jr
-it7XqcGJzeqD3ulZ33HFL98SeQKBgQDy8Kq1C8Hz4Kx/ir+mo46i+3495b9vNQ4g
-X2UKyzBp3wmUhiMYADeeoQ2C2UnzJ7bfKRlMMUMKz5yCfMzGngJRRrScC8btmEqV
-oR0LMYe03+SYV0hu9fvYh89aGhatsLc/ka4qZxzd/LLW2yz2qU4uO1glQWyHiSzB
-0nivIkPQLwKBgQCeiB7Jhbtw8OFoQXPIoPLqKw7JMmChBDZ1gVN0D+9Q+ldBL5+G
-BHVBJdyK8ZcHyd+w6mdTakzp7wCd6ZHoMfOXvW7ME+gX9o+BcvdNloClZcBEfGEB
-olZSkK0ELGr0+/47HtMz8aIvpjoYdJgaXOGGSLpUlQMMB8Z2/hG8tSDBAQKBgGSZ
-J/ckUUItrQB7cfUNEUmIHrR+6JCiRaE+H1ci4H9Wrl7kVK/hlyaGxlOCqs6XiXBL
-UoBsfbiCU+rsxtcQIyGIx80+Szejsm7XcnFqJynM9JnousPH9GurgT9sQivWW2tl
-ZduFKzz5IQ07YRka7pbSWCPFPa26LeBsyTCsXaxdAoGBAJLZmrRD6rlS6jXZE+Jg
-4+XsOF+xs/YaMlEUBd/ikYRdh3AkT4ukVFEWHN/uuKR9fRg5gaqgN7dGkNr68g9g
-9TQJfG5oR8IGz0tCAqejTgP0pU2DULs2QvvIRw9HDXoaa4pqcZlawqU349cTYgCN
-x6/OPkifz2kNEksDbqtiIN/x
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC0tYivCqd0lBoI
+6J4kGNDyKf569QdCZNp7bwDwq1UMaykfNAh9E+IDOs5ReeA86bv5Tq3AMrZkYPgF
+CMwXlT+vPRImUIIFMi8N6uLu8abnslPmaqaTnA8mW5ssEU2OSuiHllYcPE3PXXN8
+nuejV5KhnLPKQsmn4wI7DdH2G26rhloo2eGAHPQurIZLDlbhpWH8Dkk5dz97LzSo
+W6hopVVXPp5AYqv5RPiSQEWZDkhuubrbM2t/XdG3YH5PIPcqM8Z6L1qePK7bUmDL
+Yis2Bf5FbK0w1tJkGyJt9+jD1rQhnLnOBorJa7GnlrHCbMqLQnbuhSdXGzqDk6r0
+9+is0lXXAgMBAAECggEATIOUxTDIqHbQ8zazRutvBSo8wwkessELNTpR9pVE5IY3
+Giwo7/TMPLvYge0NwhzhZ3Ul4nxWd/gK6+7Go7GhDmzYU3rBIrwV6lmrDqspFW+P
+UL+Vmmh4jbA56pXE9dvHyykfesMZ2xRhgsGxqJq6zk0QXzKaOcjHuANpBECnQl5f
+oiznudbecNfT/sC+vtE+1aD6GtY2pMt43zUceG0KPyFFEmhlujCNx4tWXS2RhVhu
+1sj+sDAVpMufO0077jSXuRT34BUizy0uMhrKRLNTaGg46tK2IOOhpQsSEtKmIjMu
+/G0h3xHJ3is7fHYEuYeHrcY6D6aTh07VPQ6/zr9kKQKBgQC6L78EufpXXKlsoggf
+tded7A2HQZ85644p6LBaGBFrWw01LHU0qizjwx+/L65z8eKVwruxLLii4tD94pyQ
+NQ21/I2eMZBFuwIzdwd1gTuXSg0TJBKjzRl/GWhagPfAKk8cnB7neUUr45Z+CdYT
+xuxiAtSo8x3asels+p+F31tT1QKBgQD4eAG5Qgdpvbj+KaibwI6HI1nHDZqfBzNQ
+96ZmoNz0rQ0pUFKwCBBcGnGEXjZH6M66wCTLf8ddfC1g3SznpA94wHSRbtUIIpLU
+CrwJNiCh74pb9iFXlSw337/XWNlHmNu0UVqKHcEf/7eGuemc8uLVicxDn/pINj0b
+odXa0pCU+wKBgEN1/V53DHAPEQxdgVgMCT4dQ6GYc1sHMJGa0Bs00Ur2yMhVfXpB
+ltZH4v7hBfLY1+KvllZR/+x1BoiXTWcq8fbYtW92QfIiGmAPZtJ6qt7cY/Rlg6N6
+MxzMVfVE+X/VVKjnIIN6e0e1xNeSNNEhqJCyud8lh9Gv2QY1oQterLapAoGAJ3mJ
+bJFc9CO8PEUKEJSrEDVBkipLInDWakquGSf9crH7oVCtkmH1l2xsFIeTQCFwlqLo
+NZx7ZBLScs0w0SxzeM+6tVBScBRuF1oNPblnvdJ8vNeBvJRqjgXySJhJDOLwJNm3
+9LF9eUP7OGBZCSJdf2eBGE1WShqz4qv3eehyJ/kCgYA8DOyaSf3goJ6Igg3oqBt5
+UnZBHw3YWcU0C8Ra5IiO5ILECeqnR5hU6mMunLkKcZl8put9In75bN+hZJVfaZ8B
+N/x7QXzEII0DmZ61lPV7rWPiQNBvhcO6vOO2rP/US/vRltQGJf3PyYNZ3ot7mdST
+/dzyqF/eOsxa1AfRgw0Czg==
-----END PRIVATE KEY-----
diff --git a/jstests/libs/client-multivalue-rdn.pem.digest.sha1 b/jstests/libs/client-multivalue-rdn.pem.digest.sha1
index 5af85910220..47965e0cf15 100644
--- a/jstests/libs/client-multivalue-rdn.pem.digest.sha1
+++ b/jstests/libs/client-multivalue-rdn.pem.digest.sha1
@@ -1 +1 @@
-BA1F55BEC2F3D28BA64FACA008FA1D4B895A04D5 \ No newline at end of file
+0A1255BA830FB73B4486149A1BD2AE47069D7611 \ No newline at end of file
diff --git a/jstests/libs/client-multivalue-rdn.pem.digest.sha256 b/jstests/libs/client-multivalue-rdn.pem.digest.sha256
index b987b43e30a..177acfcc466 100644
--- a/jstests/libs/client-multivalue-rdn.pem.digest.sha256
+++ b/jstests/libs/client-multivalue-rdn.pem.digest.sha256
@@ -1 +1 @@
-816EA47F519C6784DCDC9098BCE794ED0AFBCD75F904EE5DD74D98EF0FF95649 \ No newline at end of file
+F39D2FF30A3541D2D417F528C2CA7475EC0562CCD3033B9B9005236AC3E8F7A1 \ No newline at end of file
diff --git a/jstests/libs/client-self-signed.pem b/jstests/libs/client-self-signed.pem
index 778d49ea724..28a537faeb2 100644
--- a/jstests/libs/client-self-signed.pem
+++ b/jstests/libs/client-self-signed.pem
@@ -3,54 +3,54 @@
#
# A basic self-signed certificate.
-----BEGIN CERTIFICATE-----
-MIID8DCCAtigAwIBAgIEG8kwHzANBgkqhkiG9w0BAQsFADBwMQswCQYDVQQGEwJV
+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
-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
+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
-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
+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
-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
-vOx9ww==
+YXRlZCBDZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQsFAAOCAQEAPEyiPfuu/rkJ5psz
+Cnfs0syCmgb2CGNtIr9FAFqtGAo/kCs0KS/Cf0N686IoV6Fs3uzk2OSjQlYzQPkx
+BCfGjvm4+Hc2LQM/K21fzEeirDCoZGIEx5eQlgbrM5rsAg32eeJ48xuLatf7xbLk
+VXkmFUz6lzNcQ7eAYldNz8onNqHZvMcx1WBOYAbretK7fsvoyXMzlyxA8R0Q0l1V
+ow6+32JcThfwgfh0iqMJnUtsNdWY1EbMTqO2jse76dze1ztUSNsfxmxIKg8CTQTw
+qUCZgjt55p5aRNQREjulBW/OrTTOOJ0ipnCFr8YhKJ8Cw3no3prB+Xp3GUp6jQG8
+uLr34g==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCZynihSA2ZGPRQ
-4FuCcP5LPGIB+uZke4xOOm23jHe59cY9TXQelgP/1U/aHMOcWN3bfdodZoPbcZWx
-e4/yAdyX8vkt0dYhZagTNFTBS4d72dIk0vRDXztYvcazQWvKC8JDW8/ImnwuLY0J
-PDNiLajEuG+vXJ73g08GZftPTDdO0TrcjKqBg9NT86u1jGKTc41/M4aorBTK5AtQ
-KbW9JoojjEA10tenS6uFL9UnLN0+1YUYJxq9oWx3xvJI6pIIrya28maiLJ8mSM9l
-cqvJAPWVoHNbQ3RqkfvXfjkK3JH8GN9P5tZeYrN+dZIaK4FRwdkf2270Zv3w/fF5
-EVfoAB9HAgMBAAECggEAKG/kaAPaD3dQRjO33AR52K531q1yBtm1epxCXRDCKlNF
-XLkQ3znys0ITTPZjOKjlLOFaiIB8CydChPhIUQnMRufMPQ//jah9GQ+ZeXmylg4g
-Ay60q0JPCHZd2KRLA0U0PyHU8JouLLYtb1A08ouu5IraUvG3mr0b+kK2YZNYt5BD
-3DvCqJvEGV3s5I0sOABano717GZdkFuXYcsO5ztRJyUf75zBSdB4n/k9eSv8OHm+
-8oDOcsB69njbIrF4ur+LXP2asTZZXpRTH5O3d6qC+AlcnOET8iWZs/z2kchpLq9Y
-pMMBZaSALpabvSs9ry+q7pgXr5YYU2A/rZkHpsVkAQKBgQDKbMXLNU77qSBGq0DD
-Ygxe1DOD4nkAEywDh6R0KOunq/x2fC3YeV915GF67nyb4irt9ChAdL1oGHnO/ItD
-XxJhj5SdwVY0Rm6cCAIkrzMtyBUfIX3xeT3SwyH9b52IjVxLc949PRvVZuHthoVm
-Dx8NHaproa11WPS+aMh/SWPu4QKBgQDCfoUL63ytCxAm9uRzJGFwSeCRdiaSmOt+
-6JLLaNE488i66uWjF8prlC4ur989QT4XE9X0YOn+U5jwf0o4YAp+2MsC5NzqcdUv
-B0qhFBHXc/ykPKiACtu1p2VYn8cTEp7+hkoccrgpokqEMZ0mg83oUgNIJCtF5d+O
-m+vUGzUbJwKBgBDOQQmi7mDEZNKZKzJNdJt24KQFbGhOLyxH2aZvM0ljZP1tR90e
-DofaIyGypRPIDipdR+46AvOefJZrryAzx3HkGsGSKJcEdfBsVck35nbZkq9X933R
-xAk4fBzvZFPO8KevAfdxmFr6RK2UqoSTos9S9DAlZyJD9WXNiz/OFwbhAoGACNsJ
-48kNHDPswFltfXCinyI9/2GJ0BL2Zgjg5jIXlKhE833OhuaGaO+OSsHnQDrAQPy+
-OSpQfSwBQrIJBxgYYj4swCz7ghE8y69hToRDa7P0ROYeJfZYmqTMkIR15ABtDNnA
-dhsjF4I0MmCv7xkBPxq824QKFFyrGSswSbATcvECgYBtnTQ3GllNIZ6ioCMM9efP
-IGYaRO6vgRUOugJub9ajJkyfV3kSztoQ0YUWG8y6rSJG7k+aEMB6+qLwt1tAM64h
-CaIG9VDdZQmmecifIWlfuSmDZYopXcSPM9jYFain2pASM7CTBwTtQTQak+36DD4W
-o2/KLzZiGQhfzm/i01lrzw==
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDAhzSHoIitlwUa
+twOzH9M6tpGujFfoGHYrIW2HlUwDqnt7PO8S4Lhy2TQra3Iwoy0NcN9QxYCTHtvV
+AvU6QPKI0QjmKVl3Z+QS1kpFHccRatG3YR/O7FA5U7v7lWlx3Og9H4IM6a0rySMY
+bfOJuIAh3VfOa4Ts9UND7S5kcAKt8iw4Oun8fJumZO67I1RmJuRNpfMFcmPYEgjk
+3QNhb4GOxXS8Mdg+Wxpl57HkpsD6F3q419n+uy98WHurj8hjm+Z1EPjUgwwrwyWD
+7/Eiwe4hKtGz1V2ld5LAsCZymnAzmINgAD66/OsLt6wampE9ViBuyCemGE/y29lE
+WN/NNo8rAgMBAAECggEAAwddfTC6VbjFfMkaRsweX5MVsaBFlcIkwcLx3SstGfWp
+oaOwwyRD4pKmLnSvRDKc99QpvzSMNERNAwnb38G7zwky0aQe4zEANoemfXXddtmu
+WOsvO+sdy/kUQP31vbPS93syaY+XiNPOOIkqRqVfZqj7w6SPX8bv+vaVP0E/2Yqp
+uLW551zkU4IAaGWB6Yyet+IOii21SC/sF1TJ8TKG+qO56bnh21k3SvTqTv4nGvCK
+pZTamQ0SMHd0PbLvmZSWy4yY3MnBd8W6cseV+tjNuk79cXZbWfOxRw/+DirioJmw
+TrQCZCr8iDP6kr9qfwtMb4yLPZrRuRwsp0FwRLWZoQKBgQD+TQzlU0xW+/9OedrV
+uJtrcJqboYjtY7s8vEbn2u8tYAvBYWS1TnIylNQh0nyeEnl97F+Ay+W3bBFszNa6
+Uha1wof3sxF0bIJytg5Guso8j0BfbWg9Nqha8togLu4Mzwxzq+ruF470Cj8G2pRB
+OjdOmYatneq+MVx3kvM5L82kWwKBgQDB0IAN03NjG4qk37imo/omDcR4Wyjp8O+u
+y8BARxFLM8O+an7GwnPLtzOHJ6cCGxp9Y4/khRqvjMQG4uZrjOE3nZSSilJ9yt/O
+PVxjCStyOZcUDlwKQdsUW4y+9je8qT+bZojAlDB112Gb4euu/3Jg5KfUYI8SJVc3
+IF2TNeZ5cQKBgDyz78weIi7xYHQ/KjmyI4d2DbHw0Vq5X8yTtOlLnaRbNPMoaH3P
+B/uDA1A/infBOTcR4YpBIcizB0XNb8RyK/GfSg2atSPxcwIm6yl/FR93oook96kF
+DxMGvYLJMRHlqrdB5oaHIRyoBXuBWbpoRyOACmIPPCXCaqwwa9bOzmvZAoGBAIg3
+r1iITefRGp+IcbIFO7H1KSniAB5z7TEwGN3UVQ5CwoeZN6MgVdxO1VNfhhyPyg1o
+pWBaQIgzai7g2EusxzmcciiQOSwaIzRDoiQk9LkiStGYyg2XfY+QTJqGWGQrm/3v
+kZuwS2L3Tq4NmeTzuoLpEh/NAaEiR2sCP2JQlryxAoGAZV3YEHAC8h2bRxiv1c9U
+VNScsxP+pPTZCBTqW3vapnBABSmmWPzOrHm3Dxc516gIquRC6etgwdQALVXC34vE
+qhqnGQuzZmX+jk8T3yTnlapr+vnQk8vJD4b2EcUsjYOJpye83df/DhHAp/h8bc3Z
+RuBr6N41hynPkMnN/B4jTNw=
-----END PRIVATE KEY-----
diff --git a/jstests/libs/client-self-signed.pem.digest.sha1 b/jstests/libs/client-self-signed.pem.digest.sha1
index d41662273e1..66393b60363 100644
--- a/jstests/libs/client-self-signed.pem.digest.sha1
+++ b/jstests/libs/client-self-signed.pem.digest.sha1
@@ -1 +1 @@
-2C02F9FA59E8C299E2ECB4199FEF113C6193BC8E \ No newline at end of file
+D979A04391A0F6C48F70ED0F92EE1799514EF40C \ No newline at end of file
diff --git a/jstests/libs/client-self-signed.pem.digest.sha256 b/jstests/libs/client-self-signed.pem.digest.sha256
index a7ad674cbda..cee80e56163 100644
--- a/jstests/libs/client-self-signed.pem.digest.sha256
+++ b/jstests/libs/client-self-signed.pem.digest.sha256
@@ -1 +1 @@
-89B2806512047C7B03FD711576497939CBF4B2A05983A9B2E2A9A4F416F09A50 \ No newline at end of file
+FB9F70798B3F3E5A9165E6AF74D213736A403DA6F82FD7C8E4D752EF7C5DC0BD \ No newline at end of file
diff --git a/jstests/libs/client.pem b/jstests/libs/client.pem
index 2401017b994..e9d593335a0 100644
--- a/jstests/libs/client.pem
+++ b/jstests/libs/client.pem
@@ -3,52 +3,52 @@
#
# General purpose client certificate.
-----BEGIN CERTIFICATE-----
-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
+MIIDsDCCApigAwIBAgIEWVh2KTANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-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
+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
-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
+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
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCPXyRNDwiaUubj
-LQuLKWR9b8aPwdBokku1zI4nQKO/Il+mTLmW1nLYk2EnSU36RJvW68h63iw51Q+w
-mvY2Dw+uhNToSgxkj7qBZCIfcQhY/XE43cu66TeBaCGklplt68ilk2eMn+SVbYec
-cO2xwnPLO8GhCsp3V1uynoGIoQjIdm+IzhhslsY0e4LbjBF9fyefkHyrSaIerEav
-uN2y7dQVW+YHKmtRYe2ibLXmqpK5U7ZQC0dcNkmQwy/PZmAyPwr+fvDCWvnSzwP9
-CKY5iIfDlOk6N5zT9q95mTIc7gXy3JYKvaD5b94KUDjFiZlSdG+6lCUXaX8s7qHc
-VdlquPbjAgMBAAECggEAAXRbQQujXUk58bNKCH0qTHzVjqLqBIk/vqd85YxD8Of4
-I4EOOVTkyt5emvgXL74B7wGX0yFW5IX09QW0k51Peayv71pV1EGr5br+IZOOI2+U
-UCsRf0/8JpCTye9CAozkzy6EsesBaCr0Xkrlpt7mfrqtRCU4HDd9P9eP9j0Qbd5b
-CD8iSYHtvo6BTaGdte1VNxkfJevWolsP4vLbNDzpz414GF5Br3XabNIPIzd10xn2
-qe1F1PcSoho7l1Q4e9kBkC6nATrslgSyp1A8sX9m5Dx3V33Y+xBTegW7N0mN0XO1
-sX65QhcJP+mJ0ep1LSiGC8he2i4J0uT6KcaA7k0eAQKBgQC+i1xikR+PjXACZ6Rb
-xt2T3i5ggtuZ25df7O40TImp1DUNW7BscU1PdhkDGs4FXHb/MzjX7Gb04VFn1jj2
-1aec/oHdeSqzVtaXcMftiPWDk6F4GOeVCWniwI7t84obn3USilOGNBdLz96K56S1
-ksKcYdG8eN9SmFrKtmrD+SKWAQKBgQDAn16ouNwVY6VsU5VBBCgqCIFii5C57+rC
-8t/E8hDwBgpRXg8LjMYRhb5vsHHl2DIkemTQjOKmDWMHTZZxB+S1vG5hP4xpG3kK
-wsLuykW5grcGMMVnPEWBmH9iwRPnAP8fzafqBCzVNnDzI2Zq7GqtWDwcPmWAPy/u
-9ZWgPBX04wKBgQCd+PBJD8Q4waxBcifDpyYA980/Wn4yGupvLwF1/paLZFHvlzq3
-TWApJuIpvslbjINjpNXVvjrFfyB8lBB6JDxoXmDQeyo5sR8MQwaeGlRiF71g0lT9
-LObKhZZ6FNVFfXgUPPZuZzWBNv9r7gySNPB/smGufg+4bHOpaH8vppdUAQKBgQC6
-qvdZ/OPTmqCaLRnsSvH9Yga5EFWty3IvgJ0YSBnf8YqYNdXQtJjSLFFT/aMzQeO9
-9Bq0/IM8tqZsUmVjnmmnMTeq6KHSzjvsELhGHyGY2LMzvZngJMmbAMUaV9BIwm97
-S5rZLzifW0X0ai77mab73BFMsa89rH5wTfC1uuTwTwKBgQCQUlpPS+9a8dR2bCx9
-pKWhli7foeddPouXoxXTfmGia/CTQn7POD2VZXUbWmfZO9866rVuxVs1+kuUreMp
-1nNKSZtU02IzcxN52YNA/uBKpPAkvvb8SRYNb1c7dWAu3Rp/LbgP6jVw49QM3WPK
-ji/1IZWm46dqLZPZTxvTpWl4LA==
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCtjPhOz+JjgKmA
+0v+RquVWS60rNApH6fRa0/XfBO8bNTxGrM8QPbG7qRaAZfzvlVlXmgaTAJaK9Upu
+MZjwbgQNOgQAX7/yIqsoA5DqqYzJEkz2iLEe2zSVfwpnfUBYP/WbwfFoPqqJEPDe
+vy5QcO9hJYoGuHsiLfBuaTHemM6KabBmIp9EjxCXwc/qCRhToQ2KkWYo91HCGGA6
+b9Lv9LZVAlrLFuaRq1hCNYn0KZIZJ+AGj1VfYL3/AhRDUx3gjTDNuu62hOKDGCdL
+4tW9aAYpQBLJjOvpLc1Gnsc+jHyNzU6zhQW+3KqU7p+ZC4pe9CkbR2h08JKfSk4T
+XOMcFzl3AgMBAAECggEAAt7eDI+rsvGh3BuhVot5F6BQ0PIfaWkZPZdb7cBrJAwR
+XynkkuQyWGRHlwAY2u2heK13hl7wHoRIIuJ3ISLwtjdLcaYjyqGAKz1D3F3JklnX
+JAzGwTfm+sILLgMIWW1VZqoikBLZR0MceNK4tWPo0baJPes3Pi18WJcs1/23DNsD
+smQGUzG2myluodF99dyxOgd+Q6faG5S2dBEPwfP8bA51b8rSWdmdDxHYStBUe8T6
+8BxQXeQxd0lsdkPQ7IQaZnIq6HMe8/L+6gLaU0GOV3hNBqIHfSclL/oWowsRnJf9
+AveEM38LMCxGFvgyPOA1Zx14mPBgkFb6iJQoQqWeQQKBgQDXtHYxcv3f3XNzUwGD
+3evUknAuOMf9eYA8KxmI1nBta5L6UwPw85ULAa/NChIvhi/ZAUGRJi+DzOQ59zwE
+0mQ5/vjC8LE+kVThdxFr7FqXPu1+tiyHlxHyg385UEaWgn8YH7GXX5yMEFEglVhH
+CmWzfIK/jnIWUBmKW881RBBGvwKBgQDN+JaIdAmuKNIwXlJCbYY0jEULvZ5hpID9
+JS22Bb1Y9frVEu+AUoYHL8cRxv4LpJJPgEjuNjnhhYILfhdKGUDWFmrxh/ICoQHj
+WZinqlmSkdiZ/tE/rCxON3x1GkTMnksACNZ2KZVyxt4kgb5QTV2+hJV+xEGsUTAW
+AYuXdGUzSQKBgQCJOeBbcxl5uuuAuZTkLGGkuYiujycD5bEkFhNHj4y0v9QgdoGy
+X3Q5LViHK9oH6+kyt+7bhZyCz+19xwCi3Kowjzn44qEP+eszCMnHi/TR9ZGnpAPO
+OtiLHQbqElzl0Z1DXp5fe88e+B50iS5A+6dZuWOAtAF2mny1HdVDwMpOBwKBgQC8
+EptRqbMVJg0XQWkXYu7CmLqLR++Q9Sca/5HHvWHyE1mgqhOrNq9PbJ73ap6afwFi
+Op9ddIJRnRjr6YzWikybsAii1yFyqRYSRMORhYkYvrfrlbP30fz6xsuMGhpsRLXz
+KB678qiWD2TULOxcYuiQiHwBLq9Q6ylfTrXp68xkkQKBgQCJiw3GNJgU2KAFJTdg
++Io78w1y3To2GylJp8sMhrtBZIMT28WMrjd+n//R8HLUv3J3kdYMsOcXPMZPxG1B
+gNLQ1J8UmJOEDVqlQU6+w7P6y9fm0LIQFd/bZoundhHgfPfIIKpcIWbVAvylFDHY
+ZSF3OsSM7t1fLTQPRLdElY6nFQ==
-----END PRIVATE KEY-----
diff --git a/jstests/libs/client.pem.digest.sha1 b/jstests/libs/client.pem.digest.sha1
index 67f895679eb..af9b75d7646 100644
--- a/jstests/libs/client.pem.digest.sha1
+++ b/jstests/libs/client.pem.digest.sha1
@@ -1 +1 @@
-8C4521785D0C347F303771C275D7ABB4ED170CF7 \ No newline at end of file
+1831E998EFED1A712D852E4379044FA71D8E917A \ No newline at end of file
diff --git a/jstests/libs/client.pem.digest.sha256 b/jstests/libs/client.pem.digest.sha256
index d9ad07609b3..bb980170b9b 100644
--- a/jstests/libs/client.pem.digest.sha256
+++ b/jstests/libs/client.pem.digest.sha256
@@ -1 +1 @@
-43779EDD121225AAC6AAA1754741E625A5F291F4F28CBC662E8F1BD7DB84E1FD \ No newline at end of file
+1239EA1B24C79A3DCC6C55068AAB32B1899F1F7375A587DC76A48E2738FC8BF2 \ No newline at end of file
diff --git a/jstests/libs/client_email.pem b/jstests/libs/client_email.pem
index c77ca16f3f4..fd33c30af06 100644
--- a/jstests/libs/client_email.pem
+++ b/jstests/libs/client_email.pem
@@ -3,53 +3,53 @@
#
# Client certificate containing an email address. Includes authorizations for queryable backup.
-----BEGIN CERTIFICATE-----
-MIIDxzCCAq+gAwIBAgIEIZLgrzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDxzCCAq+gAwIBAgIEDi6fwDANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTM0WhcNMjYwNDE4MTYxMTM0WjCBlDELMAkG
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ2WhcNMjYwOTA3MTYxNDQ2WjCBlDELMAkG
A1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMRYwFAYDVQQHDA1OZXcgWW9yayBD
aXR5MRAwDgYDVQQKDAdNb25nb0RCMRMwEQYDVQQLDApLZXJuZWxVc2VyMQ8wDQYD
VQQDDAZjbGllbnQxIjAgBgkqhkiG9w0BCQEWE2V4YW1wbGVAbW9uZ29kYi5jb20w
-ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsJef9GV96bu40ETLVnIcg
-WGTvGWzpaSeO4xATxx1jX8T6pxnwStzY8xIFia6VDLxfJGib6Wgn0dHdCRpyNy83
-GGVbHkf470G17ARAEG8GK0PITdca/qrD9k5dNkhHfga7LEUe6LF1qFUyJ78LjzzL
-0tpBv8veW31jHjHK/zLRoiyvZGyk2mhKLeYsair0FxX3jZxnv/VaVXVG/0iI2Zqe
-R28a8y/ehH93WE5sJfj2x68mS9jmjLej6bRL349Qr9ExAMtOngf+2fHzh4paaZkM
-sj+2K7rYsttEXhx2fZjqZ1DPvveqQe6orT9jx1pUzCoOP3TptEcFyXWDHvCcgxOF
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDofHPqOGNvl3++6K0lPcka
+aePywLU5fLnnuS4Xf79b2hJzMdbWrYNyEi7AzJio495U4yHtPGnd8t3T+FHzzlmz
+BAUpMyQgNn2IWd5or7+T03d2KLvF33nH6g9i8tPYrZ15D0fIW1Q24kx1xUIftecR
+Xp14ytKLo2/pjfm8SrYgqYuK6NzvBFPfwX0YM0lZvMEqK8UrjzWwHprBJ1fDEyG9
+y7H9d/MSfemvAP/FnHEDOaZZnLWD4eJCOKt19vz7zgprPKx1EDkteyx54FoIjgYC
+qJN2X0cRi+gAmZ+VtDP24BzX7Xdfo714ZwVwqvE0DDg9fIiba/oQZku3DPr06QiV
AgMBAAGjQDA+MDwGCysGAQQBgo4pAgEBBC0xKzAPDAZiYWNrdXAMBWFkbWluMBgM
-D3JlYWRBbnlEYXRhYmFzZQwFYWRtaW4wDQYJKoZIhvcNAQELBQADggEBAADBR1Eu
-p8cCoj5Qu+yIfEvo6gw1pHb+G99yxjI6lf9H0XtADLkBIXYJa7dzlS8ZsYPD6XMp
-l0L3gaNrLdL/FWg/TJSU7+Sz78w+D4mLyM/4ENc2Qt0BLOV+gEb1abhenDzewi+z
-NpNqKZHGAQUrH/MTmvzsorolY2MtwoFHeFJOzqavv1IiEgXi6NLQnMNg3GsgGK+H
-9vHL5By4ZEfYUVyWSQxXN4x1B7xs4yYZtjIdN63/SSUNRCNFTWiT2bJoYGudDqHd
-GK1jGHIqztK+3ISHdmcYihT82keon002bMdmUGXd/dSgdvS6IxlehfjQE90Bsdxf
-GqYcQQeW+oMsELQ=
+D3JlYWRBbnlEYXRhYmFzZQwFYWRtaW4wDQYJKoZIhvcNAQELBQADggEBAI6hUHjl
+l8Nya419U5jNyfNjVQ/Tt8qjsGu0NY3jCqijJQczJNQo7bxF5Ru0qfXj8Tk7Mgzs
+h4lQAoGF6s25cCWnRIJIHuL3NndMKx7jCaSBTHjMgQjMPimHQyyJ1zIszAxVIg3a
+rpLfLWG9AQfkAoIjKB5C1+c25o+RvYZ5M35rdzIIgTgg3fj5k3nYvNhk5SHkvD7I
+rWPZPIGyin0Bl1IoS8bDDFhV7820G4UMyNRdFI1uG647e6lUYCt2j79xrIFGDZxe
+Ovhcud8Vk2EZiebfyC/g4wV01QAnP+oqGuRONFOGHHeTCzxCetKIjXmOmB9dsimv
+vzJ5GEKI9huzvkw=
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCsJef9GV96bu40
-ETLVnIcgWGTvGWzpaSeO4xATxx1jX8T6pxnwStzY8xIFia6VDLxfJGib6Wgn0dHd
-CRpyNy83GGVbHkf470G17ARAEG8GK0PITdca/qrD9k5dNkhHfga7LEUe6LF1qFUy
-J78LjzzL0tpBv8veW31jHjHK/zLRoiyvZGyk2mhKLeYsair0FxX3jZxnv/VaVXVG
-/0iI2ZqeR28a8y/ehH93WE5sJfj2x68mS9jmjLej6bRL349Qr9ExAMtOngf+2fHz
-h4paaZkMsj+2K7rYsttEXhx2fZjqZ1DPvveqQe6orT9jx1pUzCoOP3TptEcFyXWD
-HvCcgxOFAgMBAAECggEAAupg1gPJWIhX7vHqn6NwxqHqOOimlFAHj28184vM0Hgy
-Nk30Go9K01hpWGAqU+2dCoR4l0lm9IoXopJEpfIPnrO1hb5+MnX4GC9sEmfk2K2N
-AclPTxT7yelaQh0vY+YukYCqSmysLFi1pq2PJtA3rW3ZbFsl+TkpJyK/OtepiFNB
-pgPyshG6ritmghe4QC9GakC3f65zYmIUfEGN7zNSsf8JU1GQ6gRb2dvK+JprCb+p
-DLqQpT92/RbOutAik8lteXrazTKgmTXSOlIEbQ4dEYTmYuoihoKRsDlT0LYM5Dga
-ys9+/LOQZhgppO/4R+SAG83w3c+vdEf1Fe8JBeCu8QKBgQDetgi5zTwR8HnJrpnQ
-fTnImg+ftjZKkLG3WSIWcw8dRXxGSGC6wtHuqUltkVPhD4JsLG+cwiON/UjfdCgn
-abeLhXs7Bg8yHeUS5zptzFEv+HYs0wqFsObRlUULEKx+9x5MoXEgFo20KDNO+XP5
-oS6MI8io5QxkZBNrzfQXxa3KEQKBgQDF4Rh21kZqwy4dL1ra1o0tdgxNw6So+CUj
-h5yYZXbWTPdGrYh5hHAXOuMzGi4k61GUBpmND0UpqVnHMgsnYwrBYlUlEcM0EFlF
-ppEMNX88gAgziuqJVzHsgm4/BWqyNwxmt//c58W774b++vUZWZbb2ngeSY8z/3+j
-Kq+Ig/ZeNQKBgQC5EZPWspHEZo0N56Wx9x3ZcQyir4wWEn9b2RnWhe59aIyI6wRW
-riY9qTd3cVi+oWDD+3kUTs+04lF4PtJPTi5UJqvstHBUOTtupe+L5klhD5tETGtm
-BUcJyn0BYO225CutikqzW4qNtwpMCkcxnZtMoT/R+eR+WBs7bn30czSjwQKBgHLg
-lhJPnXvXqgrZdhZ73mQZF1WCEjLiNLVmwlua9B2/ewL2NbfOUkC6ODJvrYBTeP3F
-wxkoV0+zeGJzRBRupEzWqHWn1TqBj0InTCfZWu+lqJ07taNcEqiqpBREMcgau0Fa
-6ti1WY8cpLOcv/Qilbk3IOr8a32Vg+UXH+bSLZJNAoGAYfoYLXkOBVjG3m6sWTyt
-8lOHfu3EydUApNj8Rveg50bD6Nn99zW70mIynfcL4ov6n3w2r6o1UOunNxnyliqL
-/MftOoVPsMxe2Ys1mM9EoEeLx/XQpLSkuRc3s/FXBZRRp9wL5L34me0WNN+QxppF
-Kayzs4lqCkoU3sD0Zia8M0k=
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDofHPqOGNvl3++
+6K0lPckaaePywLU5fLnnuS4Xf79b2hJzMdbWrYNyEi7AzJio495U4yHtPGnd8t3T
++FHzzlmzBAUpMyQgNn2IWd5or7+T03d2KLvF33nH6g9i8tPYrZ15D0fIW1Q24kx1
+xUIftecRXp14ytKLo2/pjfm8SrYgqYuK6NzvBFPfwX0YM0lZvMEqK8UrjzWwHprB
+J1fDEyG9y7H9d/MSfemvAP/FnHEDOaZZnLWD4eJCOKt19vz7zgprPKx1EDkteyx5
+4FoIjgYCqJN2X0cRi+gAmZ+VtDP24BzX7Xdfo714ZwVwqvE0DDg9fIiba/oQZku3
+DPr06QiVAgMBAAECggEBAJf3mfGVcHImTquk/mEklQr+ArHQg+WTARZWdqmHqLdK
+wdqozm0/uHddKVB/rJ5hbRiB69BeODmLorMHU9KRpRKeYx0+P7QKyl3RmM9Hamwf
+w6vqDmvWm40xE2OzpQSy4AedFGgEQvUpUZ9+FK4TwnoZJcgqlBwQ9nttgbwx/gE0
+c4ERW1M8HYF/D7NOSrOWIJX7N4tngKZX6v0nHuXvWnr4Uw7xF05OKofO6lhpxefs
+VUMVzkwiKWudDUxPfd3Z3n9/9It8CQ5K9R0ZI242ADI6yw5F6U4WNqscnDZE04Oa
+5lFkdasf8DhEALUiK4UeGOIwfWFiVY6YtJi5VX5CYIECgYEA9E8+ldh3WZ6x29s+
+5sIzQhXrTOKqohnwbd4RJxL9LDO0FPbbOWJ42OrAYlFou4lcohv2VrGGKeIWxmHv
+/o5OZJDuyP45onJNTZpJKrcnpFSJ4HLP7moriVbn/t4T/R1fvD8MnMa5raINRhdq
+E/vTHxa33Sj9XrLlpOP4yZ43wLUCgYEA85xflUE70J9khAs3snvmVh0pvAqVD7TM
+HARLPNSYx76UVFiFwK1Nzf+aHVjtbMN3dKZ42x66IStqnyJyxgHvRl/KVerThqLe
+ieDcpq2CYcxdI60sTgvydpIChWiHchLlrLXC0Z/CTvDyo9veWR8XQcYNeenwZyqf
+Wr/NGLn7dGECgYAhCiJ9o1OotBR7li/whyzlcA9tS24mE/n28cRCE4hXlPpyp1vI
+a+/J7h1sbnQKgK4dYkizOrjZKzFHTPFm7JnfcdZJKlBjDrAzoXzpoPFkgOZQi1Zh
+eMxAe5dOWXw8i99pluE+xoVP3Q2MgBghcboAh1MAPs3dI7Z40TfRFGuXzQKBgADO
+fr6GxcTuEi4hv2B26o9Ub2PxAQdZSOe61+jup0baCbGxzVeS+1P4SbFZLwgSKZ4Y
+QwQuuN0NQMAgJBMlxH4OKSRZr7OdbHE2bmSa5HigbZqFo0Tq4zWjTCDW9MPa7inB
+PFDnX4RVZehG/Rh8ct5D4p2JucMNsBNj2TEAxKVhAoGAHqFq1xNiuQbpXMmae/8y
+orAOAFMX8SIi5IOadeyX/GnD6ieIqjgirwzfLwVgw1TkRicCHvTzaQmksZ+mUhIb
+ZFEqet5jNVaWqmR9IVSjOXuozQMxWu6h3bADSoWOj5+NG3uhWug15zvKTU3dT0CR
+OtDWySoudXolbLZcIAH0hAE=
-----END PRIVATE KEY-----
diff --git a/jstests/libs/client_email.pem.digest.sha1 b/jstests/libs/client_email.pem.digest.sha1
index 25425eadaec..e6f776ce0f4 100644
--- a/jstests/libs/client_email.pem.digest.sha1
+++ b/jstests/libs/client_email.pem.digest.sha1
@@ -1 +1 @@
-46FB1E4E0335413BBB52CA7B6C191F126AAC7915 \ No newline at end of file
+550153EE393EED986E0259197C4CCD85DDB37827 \ No newline at end of file
diff --git a/jstests/libs/client_email.pem.digest.sha256 b/jstests/libs/client_email.pem.digest.sha256
index 940469bf943..16a14c569a5 100644
--- a/jstests/libs/client_email.pem.digest.sha256
+++ b/jstests/libs/client_email.pem.digest.sha256
@@ -1 +1 @@
-6C4CBCB076E80495A9D5FE51F44A900585EE57F5C0333539BF524ADE90DAFE9B \ No newline at end of file
+9BEA3AF13D8DDA1AC6641430D5CA2CDBF12472A54EF36A47BCA76AFB1C14A787 \ No newline at end of file
diff --git a/jstests/libs/client_escape.pem b/jstests/libs/client_escape.pem
index c0f5ecce2cb..4d514812aa8 100644
--- a/jstests/libs/client_escape.pem
+++ b/jstests/libs/client_escape.pem
@@ -3,51 +3,51 @@
#
# Client certificate with reserved characters in subject name. Includes authorizations for queryable backup.
-----BEGIN CERTIFICATE-----
-MIIDhzCCAm+gAwIBAgIEIvPPBDANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDhzCCAm+gAwIBAgIET9HU2TANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTM0WhcNMjYwNDE4MTYxMTM0WjBVMQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ2WhcNMjYwOTA3MTYxNDQ2WjBVMQswCQYD
VQQGEwIsKzEMMAoGA1UECAwDIlw8MQswCQYDVQQHDAIgPjELMAkGA1UECgwCOyAx
DzANBgNVBAsMBkVzY2FwZTENMAsGA1UEAwwEVGVzdDCCASIwDQYJKoZIhvcNAQEB
-BQADggEPADCCAQoCggEBAOZ8Ar3Q50X/DxnlkT5TMafrTeDVitmUqC08FSfsbKcK
-iCqqbcXE0N4KY/pbt2EHNLECtK/KecGov2h/aHq2uozteA3Jqe1LjC660/j0f3J3
-bm/h9UdyjaygCyGaomt9gDUNN6YgN/tA+TX6h7vmN5Rtc5nfBX164+Ss3pv2iJ31
-6BQUtOITo9BQ2CKwylV3dbyCebWHJoycJYCD1VnyCt3n6B14D2w7Pen3bXNUdUUQ
-Sz73TWnjLFSMbNQOh+guxYsclDbpzX7iHLLTQy3I4o1298YFsOXltRMF4vwtYVpG
-l9kX/R6y9ZkkWeyFKoQWlcJIUk/W1Ze21VYPYNqWjkECAwEAAaNAMD4wPAYLKwYB
+BQADggEPADCCAQoCggEBANLltFz+IthamDbt5MZK6ugxokk5nBq+qZFeCHKRe4nY
+VVWBv4+EF18phoJh2BlohKEeEzG7yBvRQ2dXz5IniV97Coit5SUk8JNBfd69EoOR
+DX5eUraOlyIRj0WG0WmwxybTp7dc3OOhiHbDKQWAtyHlT6NNkeGWM6pNrHxKgRH0
+Ng9uOOAGN+KVHYxUWxAp3W08CXlQK3TjPEPwyPewB6q25s2mZpu9a7Y7OQ8/cSto
+bQWnudFfadH41XW4q7lg+igoQQPUl0bwUoot7Ij67OoAEu7M17Fnj4TnnoZq3scZ
+JkwOq6i8NSoL3nBTqfs9rntsnIWonYNvWVOkqc7NNb8CAwEAAaNAMD4wPAYLKwYB
BAGCjikCAQEELTErMA8MBmJhY2t1cAwFYWRtaW4wGAwPcmVhZEFueURhdGFiYXNl
-DAVhZG1pbjANBgkqhkiG9w0BAQsFAAOCAQEAuGNo62kkYp4sUTbYTYaQCHbdnLay
-/zRj8FJ/kizr8YMrDI5TIiSsKTVBfeXi2KxV32g9Esw82kzcsvOpEPsfG+ZdIxky
-QcJrO9GWDk04tUGXDGOh83QgFjTKFJEOuQNeohS/mHbFpmPqBccoSuPovP0CYBzR
-tGSxoEz3jYrn+zeZFd70OUGKzykUA1om4ajqCJYAABp9Fj1fxQ17iv76goLbrNtp
-JiNmLVqJZXz3ITJqj29Ck4RqT45jarNelj6+gurwLyH/xT6iTa0r5pklY6esduPG
-FnP9fsBQaCGDLJvGWMMwKJpr/ymBcRNM7IkNqmCmHqrchQNcmhSbUER4hw==
+DAVhZG1pbjANBgkqhkiG9w0BAQsFAAOCAQEA0pydyYl1AjdJkLVPcc0jUXT+jo34
+9Frcddfr1BJjWLJGNhHtkOMhv7BMhPtQwYlaIjZU61FQIooZnsBvtj9X7vUwja3O
+OSJcWTQAvLsBGDpuZuRCOjkWIQGMFVONUrZxKXGQhoQTeP5j0zhNQwvywoGTfiIR
+WHpS+BrxPrEOFlZKDDvKKReelWJGz0IpGhhHCt6GR3qGtGKmo18D3wmALBqaAaD4
+iTtKLBaEikBu/YM6t6/S2yMgfnn6O+3wg39VSz7Zh7Euw6ZV3v7qzuLFJfPfkDML
+Q57r7QphQq07K6eEkHrFMbD+4H43oZcWA6QqR/8YZYpXirYyl/sec9vhug==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDmfAK90OdF/w8Z
-5ZE+UzGn603g1YrZlKgtPBUn7GynCogqqm3FxNDeCmP6W7dhBzSxArSvynnBqL9o
-f2h6trqM7XgNyantS4wuutP49H9yd25v4fVHco2soAshmqJrfYA1DTemIDf7QPk1
-+oe75jeUbXOZ3wV9euPkrN6b9oid9egUFLTiE6PQUNgisMpVd3W8gnm1hyaMnCWA
-g9VZ8grd5+gdeA9sOz3p921zVHVFEEs+901p4yxUjGzUDofoLsWLHJQ26c1+4hyy
-00MtyOKNdvfGBbDl5bUTBeL8LWFaRpfZF/0esvWZJFnshSqEFpXCSFJP1tWXttVW
-D2Dalo5BAgMBAAECggEAMm80913A2dl977QDFBEG1uB/xmDb9RAZO+q/k2CiBuxg
-TvvDsQjIDqpV5ckPh9EYl9pIeQYUngqjtcVZcq7NA/0LrfKwtx72shwKOdogkEbv
-mNZoQoXf2AQeY3BPtbc86H73rCe1MErvrX7gmD6Ab3+C0gsSC7rqJtYoERdBnlSw
-Yio3vMJrrTLVdAPuI/d0U7Gf/M8NoFRlvblMG6XL8yA5+5X/iF1Jn9d6tceMtBa9
-p5WTxKOG4+shNTEfb3s1botGn0fP+dNKOV86VIVX/BxQUM2WUs8C3cQNWb7B/xjO
-lQiNYrj+DDTvqIAtZNkTHDFFYAFUtMiIuLgdJIccBQKBgQDq/PRrOOiafUSUgBJ5
-dmvMIeV25kEs0FBoOW5jFTQX/N2h8+/gxu1It9N/K33J9WvoimO00JGGV6B5WCBA
-z6CtNJVLkY78o++CtX5R4e4kRccOgRaQEOFihFF7FGkSLRINWpuqMi0glRu2z1Gk
-tcoYcxB3eHj9SY5JTSPQxqKZfQKBgQD7F/acf/XPRki6YmDeg4C1MPPoUvcwtwZd
-H9QHcXu7eqom9i3EoTX72iCi5Qy38oJBDxZJneNXNiOT5yOsRTY4MGK2aqSqj9oK
-tCyCqKxceVXDieLd3XWBTObuhCH6sr/Tk01fRsopaa3NuLunT+mjmZs7PxHSW9rb
-vrcuS5mDFQKBgQDLhk9D1sRPmhOd8tcNcG2pHeqaco8ce0hJHQTouGKoLBDhxl+K
-9YBqrRx3VnnaQ8A0Zjg5UTPZgWex8Yvt1ma53YM5Mlb/phU5xmwkC2Sw8eaYP2IF
-YTl0lFnmGiVu4q5x9npAjLjdMYgRa7qwx+rEBlTKxQM1jVG5VyCgIIqQGQKBgD2I
-8OIHpfkHE3nB9FVzys4c0hmEg5nHsOKPk0nDsPwQIrTrrem7TFyNZ2QkWAqYfv1s
-shyWegl8dhmgEqj8ST5Z9UcZOYOnP1tSLnpS1fLPtYn3N8cBp/NpIksfzKgAuGwk
-dFi+I3skr/hzpmFpfyud0GIjob14z1j9Ey1gT53FAoGALQfFQj/3D3WqGGS4cdQd
-U6AqJUIKszP7Q9zSzsHZHmlJHvfhZQMH85G+V0bKefBABtIQ6YZf7W7pbkjY4Iai
-M4f7XBnPT4fKsC4uRARnKNwOfCO2fKnM2O24GHJxRfSlIe6aK3GgVqfoBY3/QKVR
-BC5klDGcA0+Q5GyYoXPwl+g=
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDS5bRc/iLYWpg2
+7eTGSuroMaJJOZwavqmRXghykXuJ2FVVgb+PhBdfKYaCYdgZaIShHhMxu8gb0UNn
+V8+SJ4lfewqIreUlJPCTQX3evRKDkQ1+XlK2jpciEY9FhtFpsMcm06e3XNzjoYh2
+wykFgLch5U+jTZHhljOqTax8SoER9DYPbjjgBjfilR2MVFsQKd1tPAl5UCt04zxD
+8Mj3sAeqtubNpmabvWu2OzkPP3EraG0Fp7nRX2nR+NV1uKu5YPooKEED1JdG8FKK
+LeyI+uzqABLuzNexZ4+E556Gat7HGSZMDquovDUqC95wU6n7Pa57bJyFqJ2Db1lT
+pKnOzTW/AgMBAAECggEAUKLnfY7l/9dTz9zR1kea3cDsjhbq6wbvitdrX3Lky2Xd
+6t27QsJ8tTQJbBzBJaXi4D/Bkwh7kLdIkGDwyq83RTykYHIs5TDkk0k9OUcNpyR1
+BlZGRerrOmmAYFMWCtU+sEfJHsDw7FA8/zvLmYEHhHxLIONt3dUyV/Fu++74vsXw
+90rBqnNypgV/HSeF6ERNMxct1w971N0fm1/OfQDmt+XFZm0HEB2AE9QjFt+Goz0z
+ShK9a80WFBipuCss/axJNdhnQPz6SiMOl2ka+XAHMc4WTbLR+HaBL2IsoSSWDLyt
+7DFBiJ4Mvurnvj1zu88nevcTqYEPFx6gUup8Yut8AQKBgQD9IRmJ4hPoi4FdgTMU
+8dSZVPvKCpLlKC2As20Q8H86iY+ds3goOjJsve4V6eWJJELinc496gpzTuhae8DZ
++Y2ZuU00HZ5nhQmJYGDN91yiFvheV7jW3bJ9nOaOzF/VyniC1o5lwSACKAJjdIBP
+nKn5fSqg/mgkDZQf5fyRKURRAQKBgQDVSf6HqtX1a/UxHF5bRLQO6jZjx5uNPPJU
+uN/5MyW6yxYb4gcJ6zuC3oNgX0A6QuSpaMoFjXGXGZ/mDiA5ISyJF7G0Ol8ErJOY
+5Y85ou9XiP1djKqdgu6xht/Gz00PomPDWGnXQ3V8aZKTjWqDfMRs8lcAUvUc61i/
+WSeKoC7GvwKBgQCEszaFP1z6ezAdid7yqviuTYwWVka+FbsNDoMt7zZzxKvim7Rx
+Olk3ArbvDAiGRdk+nkYB1VEXNBXBYcEvRJGENk2P9bsWP/tI5pq5P2VzoCEirFA9
+bEnnajrAP8o59QQKa1qJY55ZIwplgyzFD7dYENMpRVXpGKk/s70diInFAQKBgBfZ
+TjydPY9Tovb61RIffIKubaZ6i0ofpnkSsviKX42jZ7V2cJMLWnwnpUkBXY0mLatD
+rFMynaDnnJl8ut2od/JcU+JzJGzBXz+Za4pmTZzcFHiBYhJ6sXXoPt1cEKHO5pjR
+KgSH5nsi0uDszxwkt1H3RwMiQ4YYSrQao/E8N/7BAoGAYF3PA0Kpkz1UugMONR1O
+m+8Muvfi13s8/Y2DnIQUe91JWfoVEvqyDkuboJTuFDYw1er0yk0RyssEVNj3hpUW
+lYd19zfYcFbvdnflFIPDyYHPLjELAcSs1RYATd/fn5t0JPGhewpuwjVL4GxRFMdo
+mXqG2B9fBulemfeSpl7mcFY=
-----END PRIVATE KEY-----
diff --git a/jstests/libs/client_escape.pem.digest.sha1 b/jstests/libs/client_escape.pem.digest.sha1
index b00660f31cb..0a034e38e5d 100644
--- a/jstests/libs/client_escape.pem.digest.sha1
+++ b/jstests/libs/client_escape.pem.digest.sha1
@@ -1 +1 @@
-81790F20B34BA72185CA70561BB808DAAFC5C374 \ No newline at end of file
+0AA7F647A00B914C579BA7D9B658EB9672E64E93 \ No newline at end of file
diff --git a/jstests/libs/client_escape.pem.digest.sha256 b/jstests/libs/client_escape.pem.digest.sha256
index 53605cd3052..e7dcc81d937 100644
--- a/jstests/libs/client_escape.pem.digest.sha256
+++ b/jstests/libs/client_escape.pem.digest.sha256
@@ -1 +1 @@
-183B1AD3697B82AC08D2939D0ADA389A9CBE3DDEF1A4EEFCC2607C380EE58162 \ No newline at end of file
+ED1435D42E25B629074BB444427D51BA355BA15934953D1DBE7EA049F2197E5B \ No newline at end of file
diff --git a/jstests/libs/client_privatekey.pem b/jstests/libs/client_privatekey.pem
index 507d2c05a24..9c6f2a781f4 100644
--- a/jstests/libs/client_privatekey.pem
+++ b/jstests/libs/client_privatekey.pem
@@ -3,53 +3,53 @@
#
# General purpose client certificate with roles.
-----BEGIN CERTIFICATE-----
-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
+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
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTM1WhcNMjYwNDE4MTYxMTM1WjCBrTELMAkG
+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
-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
+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
-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
+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
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC5dsZN/jygrKvH
-aMTxtBksVI6WH8gESMnN/1BkueDoQg7scJqcJgD8NvqvAdJqXWJXZHFpPyeXnLDR
-UwbpP8rzIS8hTRpbbTOdRH7iKSguSN6DcoZMvMfnZbour/TPfjxnx46xJiWDKhqZ
-wDDeZOLGQUPZqcU8WafBUS9ZG7fJUrGZAis045imTwJy6pGvxTQkBYqRhr1hYlvW
-K7m9vAHkRe+4Wf3fJAQ/5g2/qYygJj5i//Hhww1T4WA6qFLHjkIcqer6Awo/E/G6
-fBxW+tRgxQYhazQEeAaNWwtwZVkSXUEjh+433a7dwfDDDC4p9TWLBwQV9KMjk5xX
-7hB3yx1hAgMBAAECgf8CyM7EwddgEN+qIqFtdn5URzPxgWmdE3WCYt/TZ9Vj5VbD
-NfqBGmjhnozXXDDvb6DagHzgpyV4yAbxqTd3z3l+fR7KH0MRB6N8zFqfMWZs6TQ1
-H4HAdqNTYGDbr6wlUk9fjRKBYA1cFW3SGf/DcNoqdSW3tiESrlA/K3EaDXX5b3LQ
-LaLIOvl+i5GpWruatMTwwBResApjf+RZZh7IGrS4Iv2IXAt9UnX4RuWKUvy0Fhxi
-dqABOjdnTRYhLypX/g2iZ4hYc1iA0WCptsvNZTzyJKeCkMa35la6okQV76ge2npV
-XARHYT6Hg7wRzuScEf9fMm479Ax1zoQetQmWUocCgYEA9Y9hiextlpfUhA+IbPlx
-3KctNhmXO8ZJ17U8yhQua8Z2noimd3iwxuYqXNsrxggFCoY5Fle5eSYDY2cV/4Jc
-uVBmautz3k4k/zeDXG0n7vzMjF+xwxcLq1TByCohazY1BnHyR6jMe2JW0+bJqW1H
-8P4AMmlXxwfA0Rj43T/uUa8CgYEAwVlSRxLM2t68672X8EpeyYVLZFkERbBOJeqS
-cUJ1hO9w9CmNDpoINQGSH/cWWsm7MWvYt6VcEFYTeIZV+EMXw/gfe9szt5lWbOR6
-oubR4yz5M6xaAtqiv0yWO2ErtZs6kdJJg3JMNyyd0UjBerxt8vUixx6lmo29f7tb
-EtPele8CgYEAmv19zgUpglSgsR3wuP+Uy3XFRpFOcE8OipT9InssdaAVfKi5kUzf
-Hxtlf6hib6LeM69WVvDVw06n8tS9AMGybtD9Y9zrDFR8a44JXowTGXf8T1mTJJTm
-K6TajtFwuG/FdiTzjCFRt0rxjNvtSwAL2WMokqkE2z3ciN3fLh7M+EcCgYEAmv43
-brIrdejIGVJK0l1LztADt9WEDzld7Bc2fYSBIKexLImCggoIOjWgJe+1A+JjJSMG
-/3CXdKELyrolgHaIPphQ5MC7nJpXJcOia6QM7MfInRu0rEUH4cJLTB6BI3vkX7Dr
-LWwanMAvYu2n6/PRT8oiruxqZJLrLdHLGDSvYhECgYEAigquEi7ZNU4b0b4w22gp
-JAuFu1/2/CdIhfuTAyyqvoiPnJvz8vZAiGsuCGU39oaTeV7a5EalqmvOIycWppat
-q27mq+e2h2zgOQ5L39QRq7tALtWhj6tE7VpsSoNmyoKnDjSn0fwT24c532j55/Ns
-VyXYm7wvEhaaKbvDF95ubTs=
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDHeKt3CeMepkB+
+Dr1HOkxiM0BxPXcM+LFQ9Erm/P+UiXtYRamjwJnM2DGnLmkD3nyAdu335MaCywv1
+3A/alx9ZLJWOSel16qVKPwwn8dn0rcoXeJ2ftAQEZOCXqgrLgU+1ZkT1GYCw665S
+2PT/1j0Uq25d1lTSipyjTAkXaVlDjuqFLfV40h+61NCiqkl3BVf62afS5CCZC5iB
+ESUAjn49XmssvML/jMAVqqrIG5cIuqAAotsYQJNV8HxFW6uP1D8CqHrMfAncny0l
+l1SDJhrAzcESjaMgPVHmOlnB2HSXDpwhiHn8JCQF447JYA8doVkBGqD5m/Jua4F2
+nGTIf6bJAgMBAAECggEBAMKSM3cnPtLryqbry7fJ5y423hpXoWQWxie4U8Pjb469
+WIKvWR0xRxTooe54t9kdUgahe9i94OE+HImTQiewF9UNR0kHUeJCoz68Jyhjon4o
+c6PXdLGOkAiVOfrW1DbUCSNiAcuvN7fb/Sw1Ey7nFKev3TVNV2oT6VzkU03x5i+d
+ZLvf0u6ojO+dfIBT8YXOShcHYgAe/0ls4EQaXgcatmJZCjJVAA6CPb36KM2MJR92
+YhyhPI4maEHNKqQf+bqU4ghboPqQL373u7IND924ENy/Z1740Z/wXZ7MVoHS/N6X
+TszXrxavfQrscYBICkQJF/7JwLZ1mVFEwEPvV/qbM7ECgYEA5fgraHqtzVYjQWGr
+Gu6vr+PM8QQIF3pmRW22sZ0DHd6Z0NBrSoqXDv/Uurv+Pj1bCirv6EC7jNI/346y
+6XXSzWuVShwnLv3MpEk/Qj9WGlXL+CgKpM4zZPJtlmd26h4dXKYBZNWtIW9yuU1H
+Ic6IQMFkJDZN9xESQNfEkseB5JUCgYEA3gzB5+HqbvYU7KlDD05SOJoCV5bkRXmQ
+miQHobpSCX6uxJRMHGG+n7mAtZgEt1DY/EeRSA2zmt3mKt/fKzouDVjKDa0UP8C7
+LWSsKNsEakNy461VSXN9LMChMTKcE6/GtbuZS7DkeNhLPs9bsWV2TAIlytTDZpVe
+Rqkezj5omGUCgYBlQ0QJ+4swka9wiMtJTrT55HtH3ZiajgEerVL3HsZSjsR4WG4G
+IsSljC1mFIW9blL6RTHiuS5csfACRtmtR36NicPxIDh4zrUf2kkKqM0HR6RLH4ag
+T1P+LWnoAqMwMBaJx2dxuU1FHcgMpGSgFEuXCBFKiMcH9fJtrxUV9NfTiQKBgCXf
+cytDwyKN4l/DNubjau6whfm+iMy4wUspHgwdpWRtMQ3iZWDp4wOHNkbC2PsTVQ8i
+fcsWWy3s7xcc/Al5cOVh4YSXor6E9uf1JdAKGySswGnI5KUUh6Mcb+HeSfSppHDW
+wHzCfRWHfr4FzBPjxFuOejewNmvGyj+vFMwEpP5pAoGAHNosMo/4nCG2u7VQ9scN
+aR6QypRQwlVxrEI1BuvrLjpGbYFw6TSHXgr0WsFVJN5Dquxw8n5XthyWu+KXnyX8
+Bz0tmfeV7OzQMWxbGRuJltKGIG+wMQ7aNOROp2rmx9DogT060J4aL6XrLgQQ2fQn
+SyYfR5UEh+hc6hTFhzyT+fs=
-----END PRIVATE KEY-----
diff --git a/jstests/libs/client_privatekey.pem.digest.sha1 b/jstests/libs/client_privatekey.pem.digest.sha1
index 6c58bed64a2..371372f1d66 100644
--- a/jstests/libs/client_privatekey.pem.digest.sha1
+++ b/jstests/libs/client_privatekey.pem.digest.sha1
@@ -1 +1 @@
-C843B656983D140C98497882ED84D52FA26E627F \ No newline at end of file
+6C6C0BFD424E1E597117929F4DF68EB970F334FA \ No newline at end of file
diff --git a/jstests/libs/client_privatekey.pem.digest.sha256 b/jstests/libs/client_privatekey.pem.digest.sha256
index 886d02bd954..74551d8064b 100644
--- a/jstests/libs/client_privatekey.pem.digest.sha256
+++ b/jstests/libs/client_privatekey.pem.digest.sha256
@@ -1 +1 @@
-E16097E13A23E3AAF2B29872D67F94CCB0EC4B180437C4173E495917A9C19367 \ No newline at end of file
+F38BB311A4DEC8670D596D117AC84D6A6FE90428B6F6D881255FD58B05199427 \ No newline at end of file
diff --git a/jstests/libs/client_revoked.pem b/jstests/libs/client_revoked.pem
index bc4bbe7d551..17303642360 100644
--- a/jstests/libs/client_revoked.pem
+++ b/jstests/libs/client_revoked.pem
@@ -6,49 +6,49 @@
MIIDsTCCApmgAwIBAgIBBDANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJVUzER
MA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAOBgNV
BAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVsIFRl
-c3QgQ0EwHhcNMjQwMTE1MTYxMTM1WhcNMjYwNDE4MTYxMTM1WjB0MQswCQYDVQQG
+c3QgQ0EwHhcNMjQwNjA1MTYxNDQ2WhcNMjYwOTA3MTYxNDQ2WjB0MQswCQYDVQQG
EwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkx
EDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOY2xp
-ZW50X3Jldm9rZWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCI6gz5
-HbkRmNbBUVlr6gJSRaqZbRYlgt9Q57T2N26shpCBWaHNA/urbvszwbvLmt4OSqnp
-p2NdCcb/svgKs8gpE0B3YLqMvewfLR/VQyeII7cPVtfe1vSJ8QL0oGEZmKP7tN8C
-ZlkAloeUF7MamvQ50rTeFbVArhQOvMFpHMkerNLHmTWQSbbnP1Z9uoTt7BdUYtq4
-xZ5rfTnBFkqtTkoGnQKhaxevkughi6HXe5V1Thd95N/YOqr07jQIXpBHmnEhUSMC
-Z3KhwnPvp7DfEm8aM0w3DKwwbTCw71Eu6OTKg1F1aOctAZ8wNJ5+NYgzjUfWOhTt
-P+CKraMcPzLERqyBAgMBAAGjTjBMMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMBMG
-A1UdJQQMMAoGCCsGAQUFBwMCMB0GA1UdDgQWBBRu/zh2vVaApMZ+5i+6iCMxfun6
-tzANBgkqhkiG9w0BAQsFAAOCAQEAvR8BoKAJx+Tqs1K5LJxAeLfI9euqvMEPYQsN
-li2dCzfm7gfRZC1lhaibL3W3jK7eaSfVjOAR5k2uAz1U2vp63N0xE8wiiY3ZbBeD
-D1wI7W7rgN9t0KV9audGL14NoXU9I5nCDRDYCPpjoIXj4ZUBOoACkdLJ/KG0bSpQ
-WeJUHZ2DqKn5+ZG/48/ePn7bF2Xr0JSihcZAICeYnBNUVGeGTIfjcErvtFlGIOQj
-g2xkg4Ou5VpC9+10UKSKFlZBizX70WqWuRv8yj0/oshduhENsFaf4AwddAfc6dgH
-poDsIErbz4+uZMcX0AUX4sL0jN2qu8KXECOPy4eiL2tCT8K0uA==
+ZW50X3Jldm9rZWQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGWbSw
+8MpSZi+dQZ2YoKnsjb/Uhy9tnMPXoLmXFFyOtb1AgKEKIEgO17aX2eOyylQO3LIm
+8RRyONK3azMOh6zhvQN/SBFPDsrKvng13jWOSwuLJABuyKJ99HLs6tMD4zlraN8r
+mysusygC83CZXp51MJ8KA1PWDgcEduCk7UE/4FOSQQ+mAEvCH7o7xDDQQFSNBtND
+qq23dkXd2mBoHihH1u5Eb4WIVsiAYdwfobbKdkr4Y8QXdU0VTp+ouxIEpXEGThZE
+rvH5+jD1JldYhSfDdsE3KrzjnlIWD6Hv6/dELoP0Dxlp/TECHkBcBURv3pWBK5ZB
+Wz6PwoNmWwTrThz1AgMBAAGjTjBMMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMBMG
+A1UdJQQMMAoGCCsGAQUFBwMCMB0GA1UdDgQWBBRynFHZIoa9FvS5zGuQ8DaovM98
+4TANBgkqhkiG9w0BAQsFAAOCAQEAgoagnHpQ/urCQklmYttTKb52UGCjai3T6v4c
+CpexQU94K+hW26t537THG3I9tEW2YjELNFzLOrm/1rKq/RdsmebwGRqU1R2qJcCq
+i+2MhxbHoQMP32wJa/SgVymLC6zPXEVUlrgB94RBJE+qW94P9SpcLMGFhoJgu108
+0OSKMS/KEmhZJ6QN7HkXYJpz1CDfWT2RZ4jbPSMgkBgeFG9/vrby06BLBJzwwmXy
+7GzRKuO9vdWGEhYbR21qGXQIR5itoeeFVakiqA+AYN5rKzD3PfS1P2Bn50PKUJhY
+noH2u/z5JJjdTKe69qlIAB3OFcYDJg+IJpBIAmFc0mq/W8nt6A==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCI6gz5HbkRmNbB
-UVlr6gJSRaqZbRYlgt9Q57T2N26shpCBWaHNA/urbvszwbvLmt4OSqnpp2NdCcb/
-svgKs8gpE0B3YLqMvewfLR/VQyeII7cPVtfe1vSJ8QL0oGEZmKP7tN8CZlkAloeU
-F7MamvQ50rTeFbVArhQOvMFpHMkerNLHmTWQSbbnP1Z9uoTt7BdUYtq4xZ5rfTnB
-FkqtTkoGnQKhaxevkughi6HXe5V1Thd95N/YOqr07jQIXpBHmnEhUSMCZ3KhwnPv
-p7DfEm8aM0w3DKwwbTCw71Eu6OTKg1F1aOctAZ8wNJ5+NYgzjUfWOhTtP+CKraMc
-PzLERqyBAgMBAAECggEADIRmY3uezP+tyZ6F9/5c0Df/jveYzdzjTQakBhsfBo2m
-ZjcDOoa90mhq9apFgKmz2bdkhaC4rju7umqasALL/spca1WX9JBUBy0lUwZo1bLb
-NH8ubPh2wqo6yJHlkrUgb92TQmlIQ4wfkM/iX2ExiRxNDh1KtQM9QPQrlBAuSHwm
-7MEOCTzgyNOlIuW9B3uhpjyYuLWlP7koDZEmIQ4HTf1/Tzz3ZB3xAq63qqiAYz1a
-a6gfXZZ03XXoxKaYd3l/8uJEaeKixgmW6BcN7ioSRm1VAqdF01gyfoK8E9Id8yPZ
-BJwC3uP/rw1ALxU8+5da6c467+lV+ctGzxjhx9U6GQKBgQC80hxsqwUXLWhTR6IQ
-oFsbK6rySX6GivEP8fFHL8BG3Fy3whTiRF6U0ruxF/o7zQUmn5/RAt7LEv+HJFwX
-6KAzCtLcq1VLiuAfV9TxxrPd+HDiLsS02RufM13B5LKt/WwOR0/TWjC2xn5wdzpx
-vxJ1XnEe5D/WNbMkMXxK5/+XGQKBgQC5oEVMLlbMNLlILjDwiqh5NWRqzQkcH5Km
-uHxVHZ3kJRsSBTUJbw6SP8Spap3wADzHRhUIWfZVB+uZl4I44HCMstSMPpjo9pl8
-BvCjUw3M/zBz/7aMT+DARbMTIrP3pr9QcsuWuvxWAlPUbTeudgvUZlX6xDGc77Yy
-3p5xq5n1qQKBgFBcS+Sj1ILMvH3VGtBgruWdbB+5z7OLJpVWrw1Q8VA3MO60FxdF
-acuE9ISmY8VXuD176hSWWCOtbjsh6l/yjVur25o3ARIphMFSLDrKCnsJ5WEd7nHZ
-hLv4rIp8vt714CsjhoG4/MqNJ/rNg34th7mT/Cjdk52jNR7OQMvQeSLhAoGBAJNe
-eGW4zFQm74oskdIGYyaHiwd3bGoVbtpJ0PvKHZYJF2rBE5A/yTO2yK0v5d+qcJZM
-P1p4AacUOKmhrVL2bKRnPXNyJvec/9GFuPoRb/12A8O0GftfVzGOpFLm1DYi/fQi
-jxtFrBukkWUuqGwrb8zayhviMvlDHkVYlDXuZLaxAoGBAJsvS6dlL9qVrsz9AW+r
-2sJrYRy3JqOLkaUkF50yq28yDdG/clroJUsQis5x1n8EdL+5D4eLP3FN3S9HEAJw
-QOzlgez7QGhj0CYJKOqwEPsCFOaTKIZkusBR77k01WG+z0omWxA4Eug79w8qIqXv
-U0B8Ji4lzvwY2m38gZpb9M8i
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDGWbSw8MpSZi+d
+QZ2YoKnsjb/Uhy9tnMPXoLmXFFyOtb1AgKEKIEgO17aX2eOyylQO3LIm8RRyONK3
+azMOh6zhvQN/SBFPDsrKvng13jWOSwuLJABuyKJ99HLs6tMD4zlraN8rmysusygC
+83CZXp51MJ8KA1PWDgcEduCk7UE/4FOSQQ+mAEvCH7o7xDDQQFSNBtNDqq23dkXd
+2mBoHihH1u5Eb4WIVsiAYdwfobbKdkr4Y8QXdU0VTp+ouxIEpXEGThZErvH5+jD1
+JldYhSfDdsE3KrzjnlIWD6Hv6/dELoP0Dxlp/TECHkBcBURv3pWBK5ZBWz6PwoNm
+WwTrThz1AgMBAAECggEAArAEesFIfIVV79OLxx2mL8Zb6w1J3zpYjPtoiFuGRYjA
+37bed7yoPUs+9h/Frg5/xRPIdi6eEE4kzMdvEatU9FoTSg437dJNfSHHjzNLlnn9
+1gzO1LFzQjGlvQARi+PwSzxIida4ZxGWYTPbOrjFfOEDxqb049mczrqtoI52a98g
+JX8U5CfxJzpyeohXUN7mrUzQGZWH0pKBv++IVw4wVpyFAe8quxzd7LhiHac8nY9F
+k+niF2fNoHz/+tZJ3KBZsxjY9nT0Ub3TZ/IM49ANjHHEzLv4beALyvNwVSY6zQQX
+W8OTiyPue9w/dOjrLZ/s4DWXXwF2/1Do5afPE6EkAQKBgQDs9R4+pUahBqy6/eoM
+6am1ytdaVDA8zC73P6DXxMBf+xKBOvOaC0dn60N1Dyr0lHi5TohqcsUtGlE98DUl
+JZ8LZHHkGthen+TNsPnvqt+5chiodk+74JTNgJjKgx/WWbjzyWY2O+Pll0ZM6Xbz
+mNgYY6Thpf0Fcs67g9EO5v5zYQKBgQDWSlTd6ETSLboAHMA867cJ8ZyeTGnkNGin
+3CAVutp/a6e0+nFZiLUh2su2C3YaxirKZyEdTs72YgQqapuiOqO1W+/IRh1FUD1q
+0+XSYmthfWJZwvCUFVnB/Xgzgff2d3abvWrRGX5NyJ1WSO8nvxFMpOMUJYFktTH9
+V/T+QDZmFQKBgQDbskxvctewVrrxyJgnjsGd3sqaYnIy/HETJrhfNXnTw7qdfOX9
+TjXPYO6zavO9vqbL0MdkQrMUJVFr5vmvTllOu7to7Ybs/LysBUlGcBxsGSBJmSBG
+JmxwuKlxIe/z0k5MIdAVuqOK7B3vE4sJQg4hVsm5uSeF1LNeYlIDyiHjIQKBgQCO
+j8UGHJAsg99KU9ZQsUCEjQj1B0ErYPJ/OiLeUgEq5CQecr8WIazfaQA9jEJ2bX/q
+R9Hv/Y4SvAKpdWM0+m4PKarMQlkW09sIRxCOdouZwCC+NsJ2wf2E4WwmWEDu52sx
+EUMO+Tbd6KlDziHM/4AyzT+FF66NoT4wnWOQAoguQQKBgGN2gf77TuTgeCfttkLA
+oxM56tyH1CZnHeJXHIxLdSyqktNCTXpAN5Fc+iTkfnoKTvdPRp9uJz59RFcGQFsX
+lrgSreguRc8qS9daHf4v5fFOEnp3IqiwwWPUhVqRFnTNy+gUbqfPCjozHSP7IA+P
+PMOrgkie4zWo3pzXTxQ26VFy
-----END PRIVATE KEY-----
diff --git a/jstests/libs/client_revoked.pem.digest.sha1 b/jstests/libs/client_revoked.pem.digest.sha1
index d7f4a445ade..ab0b6bf945f 100644
--- a/jstests/libs/client_revoked.pem.digest.sha1
+++ b/jstests/libs/client_revoked.pem.digest.sha1
@@ -1 +1 @@
-E2052CA41E07FB56E40D17ABFB926E5E21C2E6DF \ No newline at end of file
+0D9B961640A8668868B732117F192E880B2B49DF \ No newline at end of file
diff --git a/jstests/libs/client_revoked.pem.digest.sha256 b/jstests/libs/client_revoked.pem.digest.sha256
index 49c85bfb9b5..d030b69ce11 100644
--- a/jstests/libs/client_revoked.pem.digest.sha256
+++ b/jstests/libs/client_revoked.pem.digest.sha256
@@ -1 +1 @@
-FDD558033A73F224A6A423166406193F52E8A2E43B383DBFB60CEA20CD756EC1 \ No newline at end of file
+E98D6794E78C4000E48176E4D0D964C846E9B9896FFC5F7284CD6D6477C8F170 \ No newline at end of file
diff --git a/jstests/libs/client_roles.pem b/jstests/libs/client_roles.pem
index 27039d2e387..655172209bc 100644
--- a/jstests/libs/client_roles.pem
+++ b/jstests/libs/client_roles.pem
@@ -3,52 +3,52 @@
#
# General purpose client certificate with roles.
-----BEGIN CERTIFICATE-----
-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
+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
-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
+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
-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
+AAOCAQ8AMIIBCgKCAQEAu97rgT0+8f1SFjtsAXhF3y2TXqO7wuPCx6gprNGp4AG6
+YMwVRCGYIUkDZjJdVdz0GRW5AAFdaesa0shU+i5VOi8WDIPjG7qlesi28646kC2v
+/VMKIpiQkLOqxXn93OQywVrlgX9FUeH4UfaPHY8WaqIhmLt0XKIPVcY+qWoUt97n
+ohPIPfS4I8BcjOtlr37lxTzKC+6R2MP0Gp3Bv5ZtPlF2PaFiPm8T0XHKJ5wxzec9
+0faWc9uPaENhrf8GeZscScQ4MRDAZ7iDOJksYzgbj23OTXHQsWOr4YD3jqF2TJdI
+vnopfdkj+n4zeswPx4Ge04Ddu8AMeFIMi9+vn47svQIDAQABo0AwPjA8BgsrBgEE
AYKOKQIBAQQtMSswDwwGYmFja3VwDAVhZG1pbjAYDA9yZWFkQW55RGF0YWJhc2UM
-BWFkbWluMA0GCSqGSIb3DQEBCwUAA4IBAQAbbSFV8HLOAR+YATIB9e7N0zeZ8US2
-INlr/tFIlfUGg30OPEP3wfTbA+nv9u8o+a0VZ8OeQ9nv41aGRTAnQKBQjCd/CYPD
-fLrPMTQWwFVkoCm4Wsa25u1Zu41YNbb07H0/wultaJtbcRAywxQuEPd9AzlcCNQv
-oFl1qiw8uG6Foq+4qNspqLI2GLu9pNniSBY+6OHsr2Y86Pt9cq9FsoycS1ZiaRI7
-l+R6PmJKmlkc677gyO0nkUd+2hZuxjiwF606gYI5LSnfu5y30irnVsWVMZrJKlhO
-07nmNizn/HCJyzghpO2hmmXk0A6ar0TqLd9ZUItmqLugo6YDJNM94nBY
+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
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC0t/w212/gQ0Ex
-KacSlwHi0yZ7N1owLQzCGqsZxMttROw4sFs9cawj6Vmjktuvx/Bl6/Y7H0wRSza6
-VGh7WqnBHDP9ejjIsBqt9/+AIPC743+/d2N/gkzyhWzujnJAq0ojQ12NKpeCgysO
-WJudadi89iYzHOvrtGqi2+Mu0wXze8IVobLSYzm+7xm/J8VbLQVuOzlXMu5IrtUJ
-OXWmQKx4xIWE8qGQ3Vnmx9K0v3ewr5YVSKDHFE432tcOrl/pVAHHpvtZoz8zMykD
-WYs7WG5/vXIGD1amArntHrhWv4gNmIquYZ/5mEtgIrzIubotS2Bk4DLlZBhmrUpo
-JJu0C/hbAgMBAAECggEALH7AUqBoo0br3jbrM+CKTla+use+JO5ynbgDOK0DiTvX
-DX4eeNpsD8t8jpGyFW2c+vtF/PiPuhJSvz3ZG8YO1cUj590X7hGt//d3qQxzOU+i
-PHogvVxPpcbEM1hPOSzzbAtCFWfPNgslprqaVf+hpaTVcvBEBhy9xKtvHDBI3tHH
-p35hyG11J7IKeL/uYku08NmvWEBv5yZSKMV9aqIdRcSjy3KcUEFETbGV7ioHAI/p
-D9zJLRnuml6vwCh7hz/u9QNgSFXk+tN109jn9zIGxdtBLm285m8NQTTH6hSQ1/gv
-2WNK9zdBcqrGARy7hHMrsuCSFin6YvJ2AwAXvl3TAQKBgQDJHGw5mhBicaGDj1WU
-Ab4Qk1NX51sim2cE5m7zQPpBgVoyn5s505O6P4HpgK8iyzz8l4KY4/NEvd3Yw1JG
-qwPi+hBa/u+f8qqWpeTXMU6tOEqdooX+jhpjie74mQXJOK49yHD/1IarGFRo5RCW
-LY+Q7XyE9Ya7U2Zn2EJaOUyxcQKBgQDmCsFSBS+44tQ3NJsfawrT6QQN1B04Evj5
-ZlGVDRKCMeVJHx2o7nHJC9QBUoaKSfyJgLoVcBbTFgRyswz33g1C5aqYjaA+6FD4
-SzMGSFMlzXH02psPbaTBwjfaqp3GwXrd0TOyoq+BaHwSdpeNUyRDoVUhtYscI/Qe
-AF204BGgiwKBgCzwAO7OEiMtKN3wxTqRORsTEGhv9dlByD88DkakmkbQ1IrDRzgg
-or3XOvwmGPw5VaNLZ48qQE13735kBppr1C5/me/7Tyf6XUvUPdIn3mCuV13p1u8O
-aa8cPx2lc7mGxMhhZX6EyqKoiRP3O0GTZKUJq+05v6VT+Wny1MC8VPrBAoGBANiX
-Xcek/Ha+kwLbdAaT2WEGbvu6MDygmGzxqnSFF10gL3q2Yk2xG88oZNdN5UEFQlIQ
-sqQGombivxNjhB1IpAHNjd8O0ccJI1t0KjmLFUZtdhMNVJulJ1ALVl168Qy3FMEO
-/Pb/d/GG9/LGWBEHLAjFOQuBC9ZV/73TqGbp5Y7bAoGAY6/RSbu0gu13TCR4zy4B
-FqUvHf6mfe/UOOjRAmMxFd9NQ937IS2CHopKlf4K50vfjX7e4gPNSMuq+3qMhlz0
-mpEdLleMo6QyICP8pJ+EO+jSCCFkeRTkLtknL6KC/YDXeJAHcj6qFJy2iBHYkvhF
-raW562BAGl3TaAlj6XIMTU4=
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC73uuBPT7x/VIW
+O2wBeEXfLZNeo7vC48LHqCms0angAbpgzBVEIZghSQNmMl1V3PQZFbkAAV1p6xrS
+yFT6LlU6LxYMg+MbuqV6yLbzrjqQLa/9UwoimJCQs6rFef3c5DLBWuWBf0VR4fhR
+9o8djxZqoiGYu3Rcog9Vxj6pahS33ueiE8g99LgjwFyM62WvfuXFPMoL7pHYw/Qa
+ncG/lm0+UXY9oWI+bxPRcconnDHN5z3R9pZz249oQ2Gt/wZ5mxxJxDgxEMBnuIM4
+mSxjOBuPbc5NcdCxY6vhgPeOoXZMl0i+eil92SP6fjN6zA/HgZ7TgN27wAx4UgyL
+36+fjuy9AgMBAAECggEBAJoUMIe1KEulG86Z+3GVJ5DrOwMSO+qRi2zd8RgIeE78
+e9PpbMOM3czmqcAGLGBAL33nP+vOMsOsizo2DOOGXmWyul2XSQqz4AW8Wbeuu98F
+aWHU2eoXv/C9OaBt9ZNVIH9Nwg6bx8lpD5SBJ0zxzku0HuO5UayrSPJq/XdKRiWp
+Y8iDOmXqhs9vx81MQHhI6v4qo6jowRy/0Y3M68FYPOYVsjENrEBmVAb9mDy2YIp0
+Ii+e9iyBbwI3LvDtDFNZS2rCpUL6PmcfkSrDhplmaJfx1Hv4YlB4IWDeuNrYf1gJ
+p2qoOlw3OudFKM0uxwAGi1wQMktJSky0F2+nJGvz5k0CgYEA9VR4nzMICVK/Z5yT
+wcl3CoXDbTTHe2asiwcMYjfxjeHtBivqq0o6dSS84/n9+lddG4AS6gD0m6WFkI/T
+jF5/KvY3UWjvUlVVFA/0tPvS6ojJMLlqHWqGknsVg1Rm60kG4Bi8XDgv01yIxxwy
+eLQEdn3C08McXnJ3f1O1j9+8MMcCgYEAxAqxPdAadJhcWvWXPXS79qEcLrk/1eMf
+2oVAMl8qEyVqldhDt99w/y7vYaZNPKo355hBY5a+pDjoWAfYpQDViy5wD+k4fXHU
+9zCVaMNdzx+PdigmyBAOGu8Ibigm4YY5Y4kOaKKXhS2C9iJZ/sxcuuP+G4UpG+q0
+FMlUYAr/ulsCgYAp+nBBXWwMnFogEoy95gk2hbjw4M0ZcnInv+cAj24HxxbVrYIU
+GTlzffvMTqSEx5oo8HtMCynP0DzQhau/IxRDd6nzhi8dOXi7XBeVOFnYw9sZOUDN
+E8M/IUyHElQiAnbotZLVfM/CLN1CpLKGMNdqpw5FSed6yb9kzCAPJEuBVQKBgAw9
+jquJXt2A1eNoCjVwIHxZuuS/9Fhqggam40dB4eKoJ2uLwU6tyORmDdRPCeuLxUnU
+m+CX/PdMBlXYx5Il5y91itGzgi9y+BUnF20fJbBVDCQYhbNgLUFJQ4F9SFA0jUjF
+ufyWildqbA7qPixGnlOdALS/L73qfav+liIZDbaZAoGBAPQ3AMIfd3GosmgfGqJ1
+EGM0sEN5V7bB2HtTRokQjwu1wVzBexBl/0EtsgSZnvVSoHWM7xlZLwYy9jil+pp8
+iST52CMoqQimOGSjHbmXQ5V68Oia/c+Hy2vfoyEn7+4SAv1q3uf2+JSf2G4ci/o2
+fgk9cG8GRZTMhHwhbsmB4/o6
-----END PRIVATE KEY-----
diff --git a/jstests/libs/client_roles.pem.digest.sha1 b/jstests/libs/client_roles.pem.digest.sha1
index a5731bcadc4..ceea851919f 100644
--- a/jstests/libs/client_roles.pem.digest.sha1
+++ b/jstests/libs/client_roles.pem.digest.sha1
@@ -1 +1 @@
-CAC271640C5D203BB73EFDD4D1D9CB20F1B8111A \ No newline at end of file
+F846D8938D54CB1CD3D1CEA8573F63C22F3A13BA \ No newline at end of file
diff --git a/jstests/libs/client_roles.pem.digest.sha256 b/jstests/libs/client_roles.pem.digest.sha256
index 5d04767a8f3..f56b8514c30 100644
--- a/jstests/libs/client_roles.pem.digest.sha256
+++ b/jstests/libs/client_roles.pem.digest.sha256
@@ -1 +1 @@
-0CF784AA0B8E55FD9D66F1BC738AEC1EA8D83756D4976C070CA8D4DE775180D1 \ No newline at end of file
+D35F2BCEEBAC5960BBA68F8DB849CEF03AA638702C7D73E2C521DBEAE7905D37 \ No newline at end of file
diff --git a/jstests/libs/client_title.pem b/jstests/libs/client_title.pem
index 5b9231f359c..7ee120dcca3 100644
--- a/jstests/libs/client_title.pem
+++ b/jstests/libs/client_title.pem
@@ -3,53 +3,53 @@
#
# General purpose client certificate with roles.
-----BEGIN CERTIFICATE-----
-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
+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
-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
+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
-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
+ggEPADCCAQoCggEBAMYTFvYCjgLOherH1caBYotkf5gxI0IypTrOKHzMXG7B6hoo
+uGtCvgB6oQ0PBzLpzJVoiw6M3LIeWyCANJlMLfGmV8HFsl9hGH5k8YRFk67ZQ4CP
+CX/zLxAN2J5bLiQF2bHp2rjYSeTG3wEiWQlbRQ+WjJq9hogGpkL8sw7uFWN+9h7e
+0u4Lmo94Kvk7BMsNUh3kDaBTcnUZA8bsMmSvj2t/ve+mq6NdcBw7VwwOazm8J2l4
+LdEN9KQuVMiRdLcGz85FeNgdKhA+a2Rc0iYoPUsHLiFmwLNJ1Xq5g8OrC6RS6Q/G
+CGa7It7hx/hbE24OP4Bbq+npIK+RKOFE1oMsG8MCAwEAAaNAMD4wPAYLKwYBBAGC
jikCAQEELTErMA8MBmJhY2t1cAwFYWRtaW4wGAwPcmVhZEFueURhdGFiYXNlDAVh
-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
+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
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCzMSg1WCRiFmD9
-wZeztqTfIChqRGg8yN4v7OIf4clAcc7tpDwd4RqT3b3ys1jzmBNmbQLWSrGxRALh
-iz0Gcn1qtVdgFlHDWTk7FAmBBRnAnZQAbXzvkLwK9bncCoub6KHNg5snNorsS+KQ
-GMnkEW/PPIIWDGaTJ33MARMmEHSf1ZIAIM5T1sRtQKEMQ6DAP+jonR2LJoqtluXP
-w0RlQ7B7aNldSRZiPHawM93TJedDvw7IicuWHqrEQGHQB7wcl7Xi+TfRp/jg8sUV
-2wqm8SF4v8RWq4GdRE2PzPRA3hZrZG0NWna4hZw80OhaBM0h4znNd2DXGPkNQOm8
-qP4lDjIvAgMBAAECggEAHBOFLcqINNg1zTyyhMWG0rEKtA/Q10lPyumOSpmJe2/5
-kLGNe88D54w0UV05gD1hOMi2y5W7fr9dxjIXVzXEId6U+Ki2memWdoO+s3j1noDy
-Khj9nNmsJPl4bBo44q5R/83xlvTMUpbXQmWn6HS09J8R8NtzjPYAl2DJu8qTQ2Gj
-IItVH2C8mZK0p3HYqCnWGfnsQuXRW3xk8mFdbDjqP50W6V8MufLAmsdnFFAkG/Xi
-ySufSzkPKWVWcO46AQ2HAduCzHoOLznXLXJpZEZ7AtCuOEnC7ZPhhDDfWlQiDyGD
-QudMb9vgbbg/2WK2P3+KJo+f0QxD1J/QSRgJvjN5uQKBgQC+dey2zphRv8aFXeSg
-tLnmdmmr9RXA0pxN6PnLp8a3FasGEOP+IZPvUfWdhFS1tBffcg26/LHEbcANEISB
-5yJKv47pmjm3S2k/ssoYYz+/fDIwckYkAwLS5x8DDu+6c4A3WS8wBsI3Bi1dSIER
-NeqaIRE2IvAGdvE6sb55GCbcaQKBgQDw2o5MlH4VerK7e4zOwcdlXOwMiNAf5VTO
-dI9DeUg1lEdN+6IVxaOEM3/cEago5S164E2oSyJsJEDvwozKNqrBjPvFknfs3OaD
-vzHu/m0nKvgUlbP0OZExQupcRFrsIq7cZ4fluQwys5yPmjhXLzOuPiyK8a/JsPVf
-9w0Auaem1wKBgQCBiTi22GoWZ4VAnaxqdKBfEzgpoOXroBJ4lrSWA4UObmlEFebK
-p9Gymh6fxCnM7zCxYyPdghHxk+dju1Ez/JyBFCnBzYfllx99GD+FOLNZq8GC26XC
-xl18TX71GIqJWBbjDgAe/OnIfKYL5M0LhI0LyOOo2zg+XVUR42O1fmynyQKBgQDK
-PzxuoeKeNsIPHNhIZgAB5d1xSRE7N1/XXZlPl3BDTZfyq/KXRbbhND2RlmIWtRtT
-qzaKs0zccjT1H/EJfI42qSRh63Q4ueX3i31qqssNsM9QucS6t/xr2Tzi7aNL1nPv
-MCC1joXnrVsyWtYkn8ZN8neE1R4/xxDE3LdWfI+DUQKBgQCbDCXxeLcHS7GHBXLx
-OLOEN+K3PrwYALBrV+C+7A7iMVH4JJNFx+vg1T5sc3Ov2mKSCVpRR7AZaVpYGFE6
-URAERi9lWDR0yq2EhVJzoPsO3PPyIk4Qb1qPahXmpnwWirMD5eyD76jNUEv6zyZ7
-dTlqQvFIWZKXeMLsXFH1eA/gmA==
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDGExb2Ao4CzoXq
+x9XGgWKLZH+YMSNCMqU6zih8zFxuweoaKLhrQr4AeqENDwcy6cyVaIsOjNyyHlsg
+gDSZTC3xplfBxbJfYRh+ZPGERZOu2UOAjwl/8y8QDdieWy4kBdmx6dq42Enkxt8B
+IlkJW0UPloyavYaIBqZC/LMO7hVjfvYe3tLuC5qPeCr5OwTLDVId5A2gU3J1GQPG
+7DJkr49rf73vpqujXXAcO1cMDms5vCdpeC3RDfSkLlTIkXS3Bs/ORXjYHSoQPmtk
+XNImKD1LBy4hZsCzSdV6uYPDqwukUukPxghmuyLe4cf4WxNuDj+AW6vp6SCvkSjh
+RNaDLBvDAgMBAAECggEAY1dNq8KqQMQdrBvfnrhjmS+lQspaOag28GBXNAg2z6HX
+7JjBraICszDNt0PzQ1i5L7IIFBsX0QmigJFsT/pCDLF10Ax8IpQK+dFcxA81O3th
+/IdAp3hrAS1AmGN4p757aVy1QwHPRbtsOyBj8WpiH6hNCorFf1F+b5hXocRM2+H8
+itaFEQ5IVV1in4n/oOVzo0UMXKXSR8IUxU4ENDNUrC+e/p2h3R+QM+Rz+AUNJt2c
+Ie4wwC4MYOJk+yBij9mqr4mKjN23jWEWVRW5mwjcV1QMipURNhw8wohx8rUxI/Z0
+wdHZH4m1Z8AKmF5LMfAVO/jBWoWKbaiQeXgdAPVxAQKBgQD/5bfunjLLbffElpin
+ShdSgnOW40RDWOBEsG2Xhop8wl04Koa/Ufqr0eFlhm3pUQrqpGk+4NMkIw2aL4us
+w9WVMo4scZhcYG+BVQxF9wfyLENgZkXEV9Ny5fBR0OupLV8yoO/aahv2hlacgNZc
+H/Q1V1ChLGYf9xNiwQB5dd1AQwKBgQDGJ26/zYD1q8vW4gSbpiKBa5Dd6EK6lQK2
+ql5ZTXIuEnjRUQpEclXpx9uZfiRfg/8rR8ckOXFyR5yRJq9E1i2qWSNg8X6bvQc0
+OHP42dyjwHNxZrhfUQW5vHl35T/BeaxfSQzJA4YQRccVgAg4acOn+mfc2Stj88r+
+7WFXPb++gQKBgCbn2ishSj+7nGv7KYJltV4KD2DldL94h8Bpwn/DKNMHCf08GfiE
+kkQFSOuSoKtUcwBxtr6kl/VqjureR7IgpBxm7066hpuk3c8gCxmoEUE0kZnacskD
+QVa6tur5hJrYFx0vcsgWUeINUqXAwNaI1Sw29j9K7Mv3WK8vAM92qAjZAoGBAIr6
+8VSZwI+O1UN79xtsZNs9JLhfxR20kdiomdAs356s2gyFuJvVTajQwpdfwAc2P2yN
+xYEEwSsUSx4Lcfbn+dN2/bdq6hA1fq4DwmOR+ozn2JB7KWnBHDDvnoqXQiZjPqD+
+TXdXf1o+dqn/yMQ4ekCBAwQFVcefIIu41wMnjisBAoGADWtlZnZwNU1t0l3bJPv3
+GVcwVH/tJRBiRidW/iEMP7F/EU7lKgKRsn8/fy1nzb8MFaGL0q9VQxQ0npsoeYTX
+xD8cmmTfYR8IvfdNqt1jHgz96RgN910QXdW1LSuN7URPPX+XAmfihebO3QrwTGx0
+H6HUEQili7pN1tCBpiOFVHw=
-----END PRIVATE KEY-----
diff --git a/jstests/libs/client_title.pem.digest.sha1 b/jstests/libs/client_title.pem.digest.sha1
index 3da3b0e2c22..45eaa14532c 100644
--- a/jstests/libs/client_title.pem.digest.sha1
+++ b/jstests/libs/client_title.pem.digest.sha1
@@ -1 +1 @@
-801CA31DEA8D62963EEC7D118D4B96FD3D6C1E08 \ No newline at end of file
+62C0C96F50B8472335EC6D994A367B6169917EBE \ No newline at end of file
diff --git a/jstests/libs/client_title.pem.digest.sha256 b/jstests/libs/client_title.pem.digest.sha256
index 3476e58d5ed..507af2c96f1 100644
--- a/jstests/libs/client_title.pem.digest.sha256
+++ b/jstests/libs/client_title.pem.digest.sha256
@@ -1 +1 @@
-E3C637F85BD98B44E5B95C5C1807234B199B9C99E3C287B2C584FB20DFBD949A \ No newline at end of file
+A98D7EADFE164883046BFCAEC67801425AC1F32FF2BCB34B6C6ABBDA89DAD428 \ No newline at end of file
diff --git a/jstests/libs/client_utf8.pem b/jstests/libs/client_utf8.pem
index c2340d15bb6..3f0f98c94e1 100644
--- a/jstests/libs/client_utf8.pem
+++ b/jstests/libs/client_utf8.pem
@@ -3,52 +3,52 @@
#
# Client certificate with non latin-1 unicode characters.
-----BEGIN CERTIFICATE-----
-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
+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
-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
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ2WhcNMjYwOTA3MTYxNDQ2WjB4MQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxFTATBgNVBAsMDEtlcm5lbCBVc2VyczEVMBMG
A1UEAwwM0JrQsNC70L7Rj9C9MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-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
+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
-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
+SIb3DQEBCwUAA4IBAQApWKKxO25Opejg/XAuet6YnNjTiWDs7LcDeMf4X5pNEckV
+v7GlI2pwcKWMtU/PEPt6rC3qeKysuIwchtpnTeMHeNCLW9bl7jbosiiupe0kdPM8
+Ivvp/bGG5v0pK9ZrJ6g7sjw4uLcaWna9YD84XZVteEAlj+Ea2WTbg7FGQAY/UB/e
+YeAYe9i0hkC65zyOD3dZqQk28XYLDU+58EbxqfOUED0LYyZjDpHpKNlih9DHS8kn
+b9oqoJXyg3i6gAyrfFOpYCrk0vGQLMW0GPm/9p5KLYct447bLEmuY21wA5mTHZTl
+vWuCOq9w7hTCxYwL5eI/nWEc01xZ4rvlQoyvKAJF
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC+VcAYIFQ8aZHv
-WY0XvuOY3vAY6L4fLRGwZ3LNCDwi+39uoHwWjQQH1FcdQdqXL0GuHD8ko0ImKTYC
-BrCuIYcH/hv9DHsrHXG8qspL8MLkVYcQYpDKtc+UDK7WUySuC2KBp2Ncbz9No7UN
-jEenKE/ojrgef278UyVmcJip/KipgvHdvWhVhg0fh8f9P66yn19xTfM5cFQf2qIv
-Q1a9+feliWjog2EfwJWi/cPAVZVREo7vJXa9Ijx9j9tocJtNEgFwmX922m6ybgI9
-thN66cuCO+o7gU/2IK/1DpL/+G8YBdedKHy+xSxZR3eQU/rrB6rncdpX9b2/pORd
-8lK+sUlxAgMBAAECggEAB8cNQG8hwg42TmeEYnIEbty9RudLzY5T6Ldxc3tgqbVJ
-McYRDALbJU7B+IoWWpMtxeWVlvOs4k5QzKhlU9g+4k656g82gT6ExUbdWVkPPbFZ
-AYxlikL/pncWNd/T4eDJN68VWlOZbJzB6znOO8Bj84bRcz2V1W24W4VCV7/hTHvh
-Rq7hlgBAx5s2DDoK2vMLoATCv6aTk0xstCCWkLJGpC6YGTCgxoOYBmAVmUNW3Flf
-NIm2z6UNUlBgajCbBWesewgPbf4x6L7Ib6O6eBYHlNVGw80Fg5KVcclJ7U5XpJaW
-ZGDaBb211edb9KHS/DKai8VOovV4eNRpNeKDukadGQKBgQDXjDs6L2NaO30j/ES0
-JIqAx6nOXhgiyn49jsbHAgB2WNKP1/TnXWM7AoyULOreIC+tfNM/LR530UqUI2pl
-L+qMSJ4XMy+CwXG4jbfoQ6zKq5k10hQZLZc4CuKld8bFI9MXhDV+6xUQrDILGhUs
-COptKQN4as8dZ4gOyFPWZsP3/wKBgQDiDjIMCIRSKdNrqELDBA29rTyjYjI4a1jz
-lRVBCI91l+yLdpTJwfJtv5hhurY5CXq54R87cpW+O7Cn9NG103sEerbrCA2Vb0tT
-lr2JfSpMd1ebQ2aWgu93HVb48kb8dTpN3cDcsd+QJWrl3ePW6To7CA1pW3Sva1aR
-r0O1btY+jwKBgDcTpAaoGTDzRnStfziwpZtmaWNL88rgBwXft7ceMdQLujH7Mp7z
-4+kuK5GpMJJ1kvk3jhr0gnaHShE0Q3l7luklnQ+8ioVUvKQ1wipdMIfQ9SMlfPE6
-DwvI7ETvqCCzmLrHk4vMseNCvL7NeV95H72o3zQjxqxyyfdNBO8h7y0tAoGASqY5
-bLPbTm61fJXCBjhueTaeEa45u1vnsfiHXkR/a2vSF3P/Smkbr5ZXsd5AkrFIr91h
-vPXn8Tww6CX2or7FnwMPKKouIizwiRf8W0zUDRBUA9fMJuPyRDmSIP+Q5YmoyVHz
-gG3Uz/srQ+F0feHi8t+D3kjvTYZ6vf1MtLt3UI0CgYB5K8z94UIWprpk0ORN1ff0
-L4thSx7jl+Mx0OfNFA98aShZYOTwmKJromB1HCEUQuWWS/Hp0crHLBYUxiis1Ewf
-FGsT6j+UCS2yyZjKOwO3FRKJE0HKFIccHWCZqiuB/E59ci8m49zbC40CBW2i/0N8
-CAfAXqBfyiKvvWUjTuZVfw==
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCwiQCRahHlKI8n
+oc9H8PZAhhQIVvFT4nyh7os7MilR/06Ahv5k4wuHENa3fGFJFayAZO1S2/fnqmNq
+BaDoNIso/aoJdXjn4TVaJ01stoX3EyU1BSIPtSe5dAX66pZ91bumEcE6AbbXd3i5
+eV8qVJXwNhDmR8HYk0tif66bZlVXW47ibETefc/N8mMGtJEkS1cI16VWJ9aJJmo1
+ZPp0lYEdvySEBGDNajKmArZsORK/hD5n+K8llyhR6PHBHra3JJU0b+o0Ynx4pFsJ
+24Sh30y46GVSBwBjQfnrNH4kly4ZSP6TYRJXQKQzaojGLAFGtXPL4wbQs8N759Is
+ifgEk3IdAgMBAAECggEAbYnE8XXIftHI6gWMEY6hre3EFlykR7GcNfpHKEb6vqdV
+NYkN5tm+uGMpaBbkYq3xKIX3gFd/Hp9qKkotyod35cpoLJBYokDqkvMaJp+mxmV5
+y8lQlkCI0pj8cPIIyTHKysPviqevpUi7fxKhiymLE87oc4sI6/KRbx/c3w4DXD0q
+H2P/Emt6g4eSZiD/FbXYigi0otS2/a8p803fs6LROeg3/31fUKi9wUQ+MtuO8rzF
+WefNlwIjAVl/nYfTDJsiVn7KUe4lCRHRM04q4ytO1QkkUx3q9/P4OJwpp/QqohJg
+jLyjtv8J3lzII+iK5rNQkX2PDeUpo7yMWQbFhPcBgQKBgQDjnP+y36wQWd2R2Rfp
+ECpgB8VcuHId/28+JOlaS1IJifikpoUm7dq6M4rAxcXXYkKAjwl94BkRyYB4wxrg
+sN9hM0T+S/pwr5UrMWJKhLCQFCH6o9levDvoW7wBYeLNhk9OounWUfK2FKeqU/7e
+IyXraelKGaHll9LeBhDh6Qx7/QKBgQDGjTv63ej9nRN2zECEQPIbaTBCAkT3VNpC
+I6Jq38zJyJWNxgG5MKZ9bTy3raDa/ky2vFcGUc04aUsZSlFqiP+KDTW4HI3Zinpw
+XAZi3i8SDoFmDTrlK7efC2eTjiVbI8Y+fx+OcQz7Y2Hy8hFx/IwOV6zxdGHDi6s9
+6L8WTEzYoQKBgQDGpeXvyhBUcOnUeWDJ0ob5Kq8QHhXSonUHCpXybRwbISQ1JvO8
+pwgnTAaD+deSA7rAkpWZGzUl9fO+8aCKizNZlLJZMhxPrp4EhWQgXy/tfvSs18VF
+TgkG4NDzb+fOsbKTkdF9cCXgzaQLHqWoX4qfq96kAjzusROjHC4tzAROTQKBgCE5
+yzq83dtq6LHtljJLh/hMTvYM2SumeGuu+OP3lZaCyXwTEYDDAmlk2U9Hb+6VtZKy
+y8FT+QqinB2cUSmJyXF5qm6n4Jjx0nFxBOSQl8HmyYKhXiSxfyXPS8Lme5vXzbnx
+nf9BLdH3nJGCLqcrguh3hYpWVnHZsotGoouBsy5hAoGAM/DXLQlOprbQkdjYZVIh
+lL7cS7VcLcnNJqFhNScq6Hxt/Pvqb6QuPAICBWmi4ITdMAcLetm0NrqgzyRJ+C3c
+a0CEegtU3ZsxDGcb6RZKqrePEnWIC69kF4TrMlvdG0O6vXCiCmDuvxmaMgIiitj3
+EAxQQ7zHlUcnzwe8iIgkunI=
-----END PRIVATE KEY-----
diff --git a/jstests/libs/client_utf8.pem.digest.sha1 b/jstests/libs/client_utf8.pem.digest.sha1
index 097e9cbf653..8b8e563c066 100644
--- a/jstests/libs/client_utf8.pem.digest.sha1
+++ b/jstests/libs/client_utf8.pem.digest.sha1
@@ -1 +1 @@
-4068EF4A7B15F16FED299FF86628E8D8524F4036 \ No newline at end of file
+E0DA3B5DAF2089DA136BABED2C0C3E917AF56C46 \ No newline at end of file
diff --git a/jstests/libs/client_utf8.pem.digest.sha256 b/jstests/libs/client_utf8.pem.digest.sha256
index 4f0273d0d85..1ad85011883 100644
--- a/jstests/libs/client_utf8.pem.digest.sha256
+++ b/jstests/libs/client_utf8.pem.digest.sha256
@@ -1 +1 @@
-3A9C9A96D85A0FE9B1B74965EE8B2B8DF383ED0017ADB58A30A7F6ADD05081F9 \ No newline at end of file
+46EAE75339F9E602F59DC0C7C0B2C2B46CAFF0FCB2EBBA2D4CDE99C1DF829DDB \ No newline at end of file
diff --git a/jstests/libs/cluster_cert.pem b/jstests/libs/cluster_cert.pem
index d1c265435a8..aea39ec3d3c 100644
--- a/jstests/libs/cluster_cert.pem
+++ b/jstests/libs/cluster_cert.pem
@@ -3,51 +3,51 @@
#
# Alternate cert for use in intra-cluster communication.
-----BEGIN CERTIFICATE-----
-MIIDYTCCAkmgAwIBAgIEOB4djTANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDYTCCAkmgAwIBAgIEN5Ix6jANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTM2WhcNMjYwNDE4MTYxMTM2WjBxMQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ2WhcNMjYwOTA3MTYxNDQ2WjBxMQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEUMBIGA1UEAwwL
-Y2x1c3RlcnRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCc2WSB
-/GipZ93+iGzLRE4tzWcYhy+WYjO9oX8Els3ZkrKXtU7ywyYhRgU/UIdaNXJBmheX
-teHoDFWMIEc5El9MDRkfXCru3VFcrCLfNU6EUMURBFs0O56OPMb2vZflvgJPT/1X
-LJaxeROLKEPadMZthx8mFFHS5AK62qzsZ+RutN8fNZtE7537JMkjPt6JMSjBwZf9
-jB7gyDnUByvxq+MgQ6ebUBDKTS/SfN8/tna8gDy90SPnBvhdk9lNQDQuz5cYNSE7
-3MDJQWzD5jGlOlxB9POJcn82328UZNvLumviCebPmIIG9/M6Zlrn1BJo9WqVu6f1
-CNomwBMXTCetD3j9AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAOImTJ8B9rtFuEgV
-NLdW1bW/so2lVZ1ktvz6750kKA7UiOOwKxkNUUas+FguYu0vd5P1NQfh1cZ2sFXo
-zTsVxXucnLVBIb8C77LuEje65Bl1hU56fS7t0V7d5kTpvR+NMiwo+l+EHwTqNinW
-DD5Q3lC0+hVBI00h+t3gg0gWd1W+4hEZY8u/0yf0Yr17hYnuaBD4I00FoTOqfrH2
-28P954HfNkU2YzA0TodJND9Qluaw/wYngROK40ZIZzb916/1rjsJctvu0FYEOcVI
-w4LEU7hGcKmrZ6j8qk5uI4nclUoBsVBKIDZDh+tGTRiG4p83CJ7OivjkjRymJiLD
-MjmTskQ=
+Y2x1c3RlcnRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDiaMpU
+PiWADUBZvwUnfJC6NqetG1WtDbLN6ANplyWfW8vg9+5cCunDZu8aZwi4hDpazdqy
+7DvxHV2EfbXZsKA44cuWwU5moTWZZ+kJynzdG/xB1+gGr1rX7uH7nLTjcxInAM97
+ykWSEIM1yS+EBzBjgPDVW6xllDqLpSXT98kvQXidjszrmMHt3sLxdAlOrC/FAVmK
+b7GD21FHEbI+sOrA5GdFHFZm7IIXXBRN9s4Ee2hd02rjD/AAF7DUaDVRLtstDXBQ
+ZsCcME6AE2sevn1bUFkUPBEX9+I59pnsJnvuv3aS7VHmevotFqCc1+ZG+PttRUY1
+ewFrRyRhrAyczovLAgMBAAEwDQYJKoZIhvcNAQELBQADggEBADvBoEzk1hIywU+E
+DPHleSnxnLDcRvj3ScK1Isz1n0imhkfgxWMVvHvu2HIKRo3T9e/+tgO7GjtIrUaa
+wXzYR4y10+r3IAQGnkIDJmBIu6Ux6u7i1cZNxTE8046fe2vPzyiqW5g9I7jcN76+
+GbS+ndDK19zNpglM1uvBmGz07CXWOKPAMAuCkJ4+78mEfSTrbwBAMbS4AHVsfMS8
+UZGuinUH5fnqPE2BZcrl3YMfRWW9WHohe5ogSMjYk/YrVo/svdnmVOCNRCRgx4hb
+B+/apOi7OyD3zqmXRzLj+2DQAptpWz3fBFfLBBywhFcz5vhx8OW+wgkicPlekr2y
+ByE5ZhE=
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCc2WSB/GipZ93+
-iGzLRE4tzWcYhy+WYjO9oX8Els3ZkrKXtU7ywyYhRgU/UIdaNXJBmheXteHoDFWM
-IEc5El9MDRkfXCru3VFcrCLfNU6EUMURBFs0O56OPMb2vZflvgJPT/1XLJaxeROL
-KEPadMZthx8mFFHS5AK62qzsZ+RutN8fNZtE7537JMkjPt6JMSjBwZf9jB7gyDnU
-Byvxq+MgQ6ebUBDKTS/SfN8/tna8gDy90SPnBvhdk9lNQDQuz5cYNSE73MDJQWzD
-5jGlOlxB9POJcn82328UZNvLumviCebPmIIG9/M6Zlrn1BJo9WqVu6f1CNomwBMX
-TCetD3j9AgMBAAECggEABd5MWGCtOcldEOzhxSklE6mftdc4/JNoBCxKqE1MHlvS
-usJZ1dNfVddc0uWcas+dGr89KrvvW9M6UCfVAlmhnyLOUdIM+SrmpGT8WQWRjnnH
-Jb/X+bhRUlkLyKeHS100kOsZO227paA2DvrOrxm3YtmvXKld9ln5kCwmVCH+9fVX
-YhDc8FGYGDQ/LZLfm3iIN3yqox8ccYl/70jlL+rWzPUdcqVPPWvTlg8EYvV12ENT
-JPxjEbV5fe9p5aPVIX5newlu9eT26hU16OtqI08IL6wWkhII6eRrqQlytmMChVOy
-+2EINKf2lI/4aIEbE/eb5GXq2VYNPustRCrPD066MQKBgQDdZBH0KPzGClmMnTUo
-O442gdqmgU68DRnCMupAr2QJg3OMaiQcEszfoUmIveqXbCfbkdQ6pXQxYoe69Vzu
-gfgmyDvwhtB+B/W1dzB3rDnjWfOLx8fzqS8a7Q+kNFv2Dt/rem6QSiYWlK1Ley1u
-aEhdZ/nd4yVQ3O/2p7e+It/jewKBgQC1Xmb+RJxad6YiBghWAZ2MxDHkj69w9U5C
-7XNREqtghkU0sRe2n8thHiLLpsWGLmVjOjxiJYlBZ4iWFvnzrvpqu5+chd1nL/OZ
-bSVUNQRImQwHepud77CVkUrNiJKRWj2T3A2W8CtP2ulnEx9gPIhQ1QhyB8Wdpnrl
-y92Tf48P5wKBgFU2dDafJBPx3d/ijphKvAU82/TkpnJ5NGXsBQAawg1rXCk6nWV0
-0whsYwpP1yCrT3gS3DYqgtuTShzq3fcrbWE4BuIgcdVgqPFMzAnz72ATuksd/VdK
-0kex4ShZwt+lgAh52l6NO7XLShxYb/ckCl5xa9o82JsUPwSYL3/umnBLAoGAMwUv
-a+/ZHAn0jjWsOqWRsHuwnV9eNySKs4Ego3nhA/JBnaUDyrgA+n0DxM5RWoHKu7My
-MVnl1qRNZAtqnQZoI4ZMTDfMJK70lACEM8AGSHXlUGVJSZCX2DtbE56LvJ/qGqIY
-oJFHXdtzNS/H78aXgkWrboiJKuQeRm6nEksb75kCgYB6cHJARDQStkq6ObVxzz+V
-E6Gu60OmvBWZyKsnca7toGNT4GSFtTH1uyipfjhBti2Lkw+q/LrmK9WiEk5xjvpC
-iwnzSBfnrUuzEyzIRanwocD9X2NxzYQsj70rChf5YUq6M3xcHSyW/zyJLK1dowPw
-WdS84EKlNEjPDDavjEGgYA==
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDiaMpUPiWADUBZ
+vwUnfJC6NqetG1WtDbLN6ANplyWfW8vg9+5cCunDZu8aZwi4hDpazdqy7DvxHV2E
+fbXZsKA44cuWwU5moTWZZ+kJynzdG/xB1+gGr1rX7uH7nLTjcxInAM97ykWSEIM1
+yS+EBzBjgPDVW6xllDqLpSXT98kvQXidjszrmMHt3sLxdAlOrC/FAVmKb7GD21FH
+EbI+sOrA5GdFHFZm7IIXXBRN9s4Ee2hd02rjD/AAF7DUaDVRLtstDXBQZsCcME6A
+E2sevn1bUFkUPBEX9+I59pnsJnvuv3aS7VHmevotFqCc1+ZG+PttRUY1ewFrRyRh
+rAyczovLAgMBAAECggEAA9dzV2qWiE2xQdST6c+bRQ2YWr+T/JO27Pd611fRM5sD
+IpYSXU1yGfatJ+2HoFneA5xqkY6glb7Bz3WymDb/APgT1EMDaYpitm+k7J2a8MWA
+yj03mqVvDSroerR1/UX+kNraqmcMNyZAk7EONVdJ4uZVL8mWa0LQm3353lbd+wdB
+LgBCxJJbVC6ql/nD+DdeJIF70PumULiFTUDuXDu9/XRtLc/Il4cVnMGOxeQP0N2t
+93Q9WNWx3166SgNH2y2UtVuMaNHib/3Q/1t557RcOY4icme73M1TAS/u7Reo1ycT
+rJQKXr3EMLRtKdNe9K18ktqNvo3P2nZoMyPAIPknwQKBgQD+U6ylRfNo2826w+VW
+mCGtcNuSsExEqO8MiHue3itHT6h1rPiHBrXc2EqiS2j/DgIb4/MuvONSYGfTyWzW
+Kkqq6fgBPr8QwOVndiHieaINmN2M/3m3zn4ZuiIfs2+I6MckGEtfXp5xBJKTeGyT
+XHhfg3zoPnMwotZaPCAGP8XbvQKBgQDj5hk6yyRzMOqjMhQ8YuUhqst1P45oKmKY
+InJAOzQXMg8izj/NsVLuCAHmKmtX9TVscgBH330HRyVaHB3vKVK335JDtB6mN1IK
+rqtB7VZ3mzqfwWEi1Sx5pdRzihOC85JgXxKI6XEKblwGLYE+pVX2FFfiUHTYFjGO
+2vfvLNp6JwKBgGPAnAHDGwKw29N6THSXfPYTQvwZDAEOJZzL13jreRwiQVfOfTgw
+yJoTd8qKO2d2rhsUYGifi6XezDqEUZz6v4ij9jM+0iAXGKNo8UdsH8SnhZZtCeev
+JUSf/gxjC8cuThV5Ne71JL39ZiRTYnq2FTyZTR+mhvW3mM2RsZnh35AdAoGBALRX
+gH2TBWwWOIcd+P90Lue+dTR6L+HkMJM9JvYHI4h7d5jOZ5UJDpwIQCB4TuuSwkzn
+xasagqEAvuEYwONh6vBQfjkPTvWvbz++ywznmHYbo3+KEqjy0jgNbxpjGF+XCa0z
+bsJjIK3lePL2jYEaavTJUmZnzp60qVDnnC1rbBQfAoGBAPR+za57N1CM2J2fJiVf
+n0mrQAcfJPqFJoXe2N9AKcowoS5enQKoRIpxawiutG10PygfT6GQauvAKpHmiHf/
+lcPhQHdNbFOPOMqBkzwtNOAWgiDsrfpgJ+jowpma0S2OMG3Du9WBqRefyAtiFGWV
+N/7RZFSb+N/I+0ayCRGgVeZ5
-----END PRIVATE KEY-----
diff --git a/jstests/libs/cluster_cert.pem.digest.sha1 b/jstests/libs/cluster_cert.pem.digest.sha1
index 98ceb1ee30c..bd819d55cb2 100644
--- a/jstests/libs/cluster_cert.pem.digest.sha1
+++ b/jstests/libs/cluster_cert.pem.digest.sha1
@@ -1 +1 @@
-422CCCF09E6157C5D604CC7583A85991E7223ACF \ No newline at end of file
+C6D56AAFA38F7F566CAB7805CF7E759F6481ED9C \ No newline at end of file
diff --git a/jstests/libs/cluster_cert.pem.digest.sha256 b/jstests/libs/cluster_cert.pem.digest.sha256
index 531a57e65ec..70f1f7d5832 100644
--- a/jstests/libs/cluster_cert.pem.digest.sha256
+++ b/jstests/libs/cluster_cert.pem.digest.sha256
@@ -1 +1 @@
-8A158D604AF19708EB94CE9C4851D94F76F19062A0C5DB99777D366DDE3D0032 \ No newline at end of file
+E59DD887E1E6A1E0EAE1FB446C2B6807C781B57FEFB90E61FFF2C61660A1C7F3 \ No newline at end of file
diff --git a/jstests/libs/clustered_collections/clustered_collection_bounded_scan_common.js b/jstests/libs/clustered_collections/clustered_collection_bounded_scan_common.js
index f9495c913c5..ff52e8f7a22 100644
--- a/jstests/libs/clustered_collections/clustered_collection_bounded_scan_common.js
+++ b/jstests/libs/clustered_collections/clustered_collection_bounded_scan_common.js
@@ -20,10 +20,44 @@ const testClusteredCollectionBoundedScan = function(coll, clusterKey) {
for (let i = 0; i < batchSize; i++) {
bulk.insert({[clusterKeyFieldName]: i, a: -i});
}
+
assert.commandWorked(bulk.execute());
assert.eq(coll.find().itcount(), batchSize);
+
+ // Now add additional documents with IDs of a different type.
+ // Normal exprs should be type bracketed, and should never
+ // see these documents.
+ // Internal ops are not type bracketed, and will see these
+ // documents.
+ const extra = coll.initializeUnorderedBulkOp();
+ // `null` should sort before ints.
+ extra.insert({[clusterKeyFieldName]: null, a: null});
+ // And strings should sort after.
+ extra.insert({[clusterKeyFieldName]: "foo", a: "foo"});
+ assert.commandWorked(extra.execute());
}
- function testEq() {
+
+ // Checks that the number of docs examined matches the expected number. There are separate
+ // expected args for Classic vs SBE because in Classic there is an extra cursor->next() call
+ // beyond the end of the range if EOF has not been hit, but in SBE there is not. This function
+ // also handles that this stat is in different places for the two engines:
+ // Classic: executionStats.executionStages.docsExamined
+ // SBE: executionStats.totalDocsExamined
+ function assertDocsExamined(executionStats, expectedClassic, expectedSbe) {
+ let sbe = false;
+ let docsExamined = executionStats.executionStages.docsExamined;
+ if (docsExamined == undefined) {
+ sbe = true;
+ docsExamined = executionStats.totalDocsExamined;
+ }
+ if (sbe) {
+ assert.eq(expectedSbe, docsExamined);
+ } else {
+ assert.eq(expectedClassic, docsExamined);
+ }
+ }
+
+ function testEq(op = "$eq") {
initAndPopulate(coll, clusterKey);
const expl = assert.commandWorked(coll.getDB().runCommand({
@@ -40,7 +74,12 @@ const testClusteredCollectionBoundedScan = function(coll, clusterKey) {
// the range.
assert.eq(2, expl.executionStats.executionStages.docsExamined);
}
- function testLT(op, val, expectedNReturned, expectedDocsExamined) {
+
+ function testLT(op,
+ val,
+ expectedNReturned,
+ expectedDocsExaminedClassic,
+ expectedDocsExaminedSbe = expectedDocsExaminedClassic - 1) {
initAndPopulate(coll, clusterKey);
const expl = assert.commandWorked(coll.getDB().runCommand({
@@ -50,12 +89,21 @@ const testClusteredCollectionBoundedScan = function(coll, clusterKey) {
assert(getPlanStage(expl, "CLUSTERED_IXSCAN"));
assert(getPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("maxRecord"));
- assert(getPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("minRecord"));
- assert.eq(10, getPlanStage(expl, "CLUSTERED_IXSCAN").maxRecord);
- assert.eq(NaN, getPlanStage(expl, "CLUSTERED_IXSCAN").minRecord);
+ assert.eq(val, getPlanStage(expl, "CLUSTERED_IXSCAN").maxRecord);
+
+ if (!op.startsWith("$_internal")) {
+ // Internal ops do not do type bracketing, so min record would not
+ // be expected for $_internalExprLt.
+ assert(getPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("minRecord"));
+ assert.eq(NaN, getPlanStage(expl, "CLUSTERED_IXSCAN").minRecord);
+ }
assert.eq(expectedNReturned, expl.executionStats.executionStages.nReturned);
- assert.eq(expectedDocsExamined, expl.executionStats.executionStages.docsExamined);
+
+ // In this case the scans do not hit EOF, so there is an extra cursor->next() call past the
+ // end of the range in Classic, making SBE expect one fewer doc examined than Classic.
+ assertDocsExamined(
+ expl.executionStats, expectedDocsExaminedClassic, expectedDocsExaminedSbe);
}
function testGT(op, val, expectedNReturned, expectedDocsExamined) {
initAndPopulate(coll, clusterKey);
@@ -66,10 +114,14 @@ const testClusteredCollectionBoundedScan = function(coll, clusterKey) {
}));
assert(getPlanStage(expl, "CLUSTERED_IXSCAN"));
- assert(getPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("maxRecord"));
+ if (!op.startsWith("$_internal")) {
+ // Internal ops do not do type bracketing, so no max record would not
+ // be expected for $_internalExprGt.
+ assert(getPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("maxRecord"));
+ assert.eq(Infinity, getPlanStage(expl, "CLUSTERED_IXSCAN").maxRecord);
+ }
assert(getPlanStage(expl, "CLUSTERED_IXSCAN").hasOwnProperty("minRecord"));
- assert.eq(Infinity, getPlanStage(expl, "CLUSTERED_IXSCAN").maxRecord);
- assert.eq(89, getPlanStage(expl, "CLUSTERED_IXSCAN").minRecord);
+ assert.eq(val, getPlanStage(expl, "CLUSTERED_IXSCAN").minRecord);
assert.eq(expectedNReturned, expl.executionStats.executionStages.nReturned);
assert.eq(expectedDocsExamined, expl.executionStats.executionStages.docsExamined);
@@ -125,29 +177,65 @@ const testClusteredCollectionBoundedScan = function(coll, clusterKey) {
assert.eq(10, expl.executionStats.executionStages.nReturned);
}
+ function testInternalExprBoundedScans(coll, clusterKey) {
+ testEq("$_internalExprEq");
+
+ // The IDs expected to be in the collection are:
+ // null, 0-99, "foo"
+ // Internal operations should not perform type bracketing, so should expect
+ // to see the null and "foo" docs; the _non_ internal equivalents _do_
+ // perform type bracketing, so should behave as if null and "foo" do not
+ // exist.
+ testLT("$_internalExprLt", 10, 11, 12);
+ testLT("$_internalExprLte", 10, 12, 13);
+ testGT("$_internalExprGt", 89, 11, 12, 11);
+ testGT("$_internalExprGte", 89, 12, 12);
+ testRange("$_internalExprGt", 20, "$_internalExprLt", 40, 19, 21, 19);
+ testRange("$_internalExprGte", 20, "$_internalExprLt", 40, 20, 21, 20);
+ testRange("$_internalExprGt", 20, "$_internalExprLte", 40, 20, 22, 20);
+ testRange("$_internalExprGte", 20, "$_internalExprLte", 40, 21, 22, 21);
+ }
+
function testBoundedScans(coll, clusterKey) {
testEq();
- // Expect docsExamined == nReturned + 2 due to the collection scan bounds being always
- // inclusive and due to the by-design additional cursor 'next' beyond the range.
- testLT("$lt", 10, 10, 12);
- // Expect docsExamined == nReturned + 1 due to the by-design additional cursor 'next' beyond
+
+ // Expected set of IDs:
+ // null, 0-99, "foo"
+
+ // The last argument of the following calls, 'expectedDocsExaminedClassic', and the specific
+ // comments, are for Classic engine. SBE does not have the additional cursor->next() call
+ // beyond the range, so in calls to testLT() and testRange() its value will be one lower.
+ // This is accounted for by delegations to the assertDocsExamined() helper function.
+
+ // As of SERVER-75604, clustered collection scans can be inclusive or exclusive at either
+ // end; the filter does not need to examine a record at the lower bound to then discard it.
+ // Expect docsExamined == nReturned + 1 + 1 due to (not returned, due to type bracketing)
+ // null id, and the by-design additional cursor 'next' beyond the range.
+ testLT("$lt", 10, 10, 12, 10);
+ // Expect docsExamined == nReturned + 1 + 1 due to (not returned, due to type bracketing)
+ // null id, and the by-design additional cursor 'next' beyond the range.
+ testLT("$lte", 10, 11, 13, 11);
+ // Expect docsExamined == nReturned + 1 + 1 due to (not returned, due to type bracketing)
+ // "foo" id. Note that unlike the 'testLT' cases, there's no additional cursor 'next' beyond
+ // the range because we hit EOF. However, Classic needs to examine and discard the value
+ // equal to bound, as this is an exclusive bound.
+ testGT("$gt", 89, 10, 12, 10);
+ // Expect docsExamined == nReturned + 1 due to (not returned, due to type bracketing)
+ // "foo" id.
+ testGT("$gte", 89, 11, 12, 11);
+ // docsExamined reflects the fact that by design we do an additional cursor 'next' beyond
// the range.
- testLT("$lte", 10, 11, 12);
- // Expect docsExamined == nReturned + 1 due to the collection scan bounds being always
- // inclusive. Note that unlike the 'testLT' cases, there's no additional cursor 'next'
- // beyond the range because we hit EOF.
- testGT("$gt", 89, 10, 11);
- // Expect docsExamined == nReturned.
- testGT("$gte", 89, 11, 11);
- // docsExamined reflects the fact that collection scan bounds are always exclusive and
- // that by design we do an additional cursor 'next' beyond the range.
- testRange("$gt", 20, "$lt", 40, 19, 22);
- testRange("$gte", 20, "$lt", 40, 20, 22);
- testRange("$gt", 20, "$lte", 40, 20, 22);
- testRange("$gte", 20, "$lte", 40, 21, 22);
+ // In addition, Classic needs to examine and discard the value equal to bound,
+ // while SBE's scan starts after the bound.
+ testRange("$gt", 20, "$lt", 40, 19, 21, 19);
+ testRange("$gte", 20, "$lt", 40, 20, 21, 20);
+ // Again, Classic and SBE differ by 2 for the above reasons.
+ testRange("$gt", 20, "$lte", 40, 20, 22, 20);
+ testRange("$gte", 20, "$lte", 40, 21, 22, 21);
testIn();
testNonClusterKeyScan();
+ testInternalExprBoundedScans(coll, clusterKey);
}
return testBoundedScans(coll, clusterKey);
diff --git a/jstests/libs/crl.pem b/jstests/libs/crl.pem
index 4ff4ff02817..2887ebb28a5 100644
--- a/jstests/libs/crl.pem
+++ b/jstests/libs/crl.pem
@@ -2,11 +2,11 @@
MIIBujCBozANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJVUzERMA8GA1UECAwI
TmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAOBgNVBAoMB01vbmdv
REIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVsIFRlc3QgQ0EXDTI0
-MDEyMjE4MTUyMVoXDTI2MDQyNDE4MTUyMVowDQYJKoZIhvcNAQELBQADggEBABfy
-NagLOLdnuy8pkTLq5GKYbFGGTPcUhZ4J/Gv91EQmp/gUHJNxjxGdM7Gh6VsI8Kmw
-2JeZCOMXlerAqAV+SKP0kjb98yMhqoOz5F/J6wGfW5i3JKaBdlo1IUnfl8auy32B
-/PUmnx4CIF22L5+yrO7d3cP6cQX3Bu22kCImHdlNmylo9bToZTJ8tYMZv1cdyc8z
-uAt8CKm8IK8MRi3rxrPPOHSravFAYWGklqgPLmjSkI6mxIGdC8y4Izw9RFqP+65G
-NxgpFlbFLvhKHujw/5iUOXfCY3/pmAdHsyryqW57f35Isz4NL/U2VnbZmAZgQli5
-q0iVD3G3Sb8pHbojIYU=
+MDYxNDAyMzgzN1oXDTI2MDkxNTAyMzgzN1owDQYJKoZIhvcNAQELBQADggEBAFBw
+qJ4aHbQju026iBJuF1vJAacSLb8oR6rJnpKx0ZZHVmxLN3cHUAaSgLf2SyundJJF
+KfutQN9pJlm9crc1/En6qd59m7wl2zCMv/H9wPyNKlHSQhNwlBUUeSBukj9Plte7
+1xC2ND7hQ/J4oxix4g8+BbQyPhkccow2qh5BGAVYPlJ7GJzu/MZp7//SB/Zq8tFj
+GQAwperVep0WxF8dcAkDnoW+Lc2dziT76XqSRRLWBdrw3qSwLBc7rGusbmFjbtsn
+jLh2WqpazjRpBK3yhYC0XchTlZoxzIb+KIpIpMMtDSGimhkaQBDfCuq7bNezXNwK
+YIPzyDj6zjASyOQL/h8=
-----END X509 CRL-----
diff --git a/jstests/libs/crl.pem.digest.sha1 b/jstests/libs/crl.pem.digest.sha1
index cec6ab24b76..b43dcbfae08 100644
--- a/jstests/libs/crl.pem.digest.sha1
+++ b/jstests/libs/crl.pem.digest.sha1
@@ -1 +1 @@
-187A161CF237412C4FBB29C085257486391B05F9 \ No newline at end of file
+D729D47256CB736BE6A6ACDE504675AF4FCB9A96 \ No newline at end of file
diff --git a/jstests/libs/crl.pem.digest.sha256 b/jstests/libs/crl.pem.digest.sha256
index a879e77de66..1bb20c0d7cc 100644
--- a/jstests/libs/crl.pem.digest.sha256
+++ b/jstests/libs/crl.pem.digest.sha256
@@ -1 +1 @@
-E8AE353658685AEFC67D694500C47BB5DECDB1367BA129209449742D6BD4681A \ No newline at end of file
+042161424290087F0F16E96B2E138955DC91C57009F896ACF0221E18E2D671D8 \ No newline at end of file
diff --git a/jstests/libs/crl_client_revoked.pem b/jstests/libs/crl_client_revoked.pem
index 8d239a01554..a469d138236 100644
--- a/jstests/libs/crl_client_revoked.pem
+++ b/jstests/libs/crl_client_revoked.pem
@@ -2,11 +2,11 @@
MIIB0DCBuTANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJVUzERMA8GA1UECAwI
TmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAOBgNVBAoMB01vbmdv
REIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVsIFRlc3QgQ0EXDTI0
-MDEyMjE4MTUyMloXDTI2MDQyNDE4MTUyMlowFDASAgEEFw0yNDAxMjIxODE1MjJa
-MA0GCSqGSIb3DQEBCwUAA4IBAQA5u9xGEWdveHNz/k4gG1W5et32zuUGO5RVNNIR
-Vs37p2PcttdaULcgCcq2gl7Lk+MrdtjggSBsFQl3x8TkOIrSdNjzCAUQx1UrEnb1
-FQe6vyMy3TYfhRnp4DMO8BYSp/KGyh40RAD3ub1WLbfRTVktkJcXPa3FxYXUBSHw
-enZ6rcmL4iqZdwg3GyErLdFvYpEBO3xvH+8xkg+gQZgMwkPc+tiWMO3GDfedTYaJ
-3qYvXb03gnlZCgnIE8YZEBbb6gfY5nWztSIQ1WbBMTERrpC7jtsdNow+7rAXcwu+
-uaQZUisGNGqQ0Hl7drCEButWyUJH7hnSCRP5YgQCTIBLaLi4
+MDYxNDAyMzgzOFoXDTI2MDkxNTAyMzgzOFowFDASAgEEFw0yNDA2MTQwMjM4Mzha
+MA0GCSqGSIb3DQEBCwUAA4IBAQCCod+aKBqQIG4HLUrvOaJTyY0OA2DrAfi/XBs3
+RV9NGVyPaDQjnJKEM923Z2WUfOBQlAPw+3lvY4Ybng1chMq3KZ+Lml+hOU3ytuHO
+cnW5L10sEG4+NqqofEynu20BGD7e+6eUhcygHc4Z6E0BKwCKemNLqDiRj2UV0Ebu
++y4nTlTKRq5yp2uPbq2I0jKcfMJIrNmSTE6hOOIELnsGAT627cEjhkcYULYy0yaa
+VVp8K56SVIucF/zEnIienCbWExpAjH5/IBZkkgy34dlreuQu9RYiPbRz092Fep5d
+A1D33Fhe+m6oAr8tc5jpUHIszTNCFR7BzmrY44UMdhylGeLO
-----END X509 CRL-----
diff --git a/jstests/libs/crl_client_revoked.pem.digest.sha1 b/jstests/libs/crl_client_revoked.pem.digest.sha1
index 9cd279826a3..49519d11431 100644
--- a/jstests/libs/crl_client_revoked.pem.digest.sha1
+++ b/jstests/libs/crl_client_revoked.pem.digest.sha1
@@ -1 +1 @@
-FB309D91A36CE60B256C6AA1C7A492C0D2E66A46 \ No newline at end of file
+8A100E989DFEF7344F28349EE371625B98EF27FD \ No newline at end of file
diff --git a/jstests/libs/crl_client_revoked.pem.digest.sha256 b/jstests/libs/crl_client_revoked.pem.digest.sha256
index f089742f239..84430509038 100644
--- a/jstests/libs/crl_client_revoked.pem.digest.sha256
+++ b/jstests/libs/crl_client_revoked.pem.digest.sha256
@@ -1 +1 @@
-72FD49035D0B353A8A4DBB52D809B999838A1E8935B76800C156A0E40ACE2E8E \ No newline at end of file
+0D708E3CA860A437FB1CD82631E4C6E66C261073CF916DFD294521671C726C3E \ No newline at end of file
diff --git a/jstests/libs/crl_expired.pem b/jstests/libs/crl_expired.pem
index 56651023e3a..661bc83c754 100644
--- a/jstests/libs/crl_expired.pem
+++ b/jstests/libs/crl_expired.pem
@@ -2,11 +2,11 @@
MIIBujCBozANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJVUzERMA8GA1UECAwI
TmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAOBgNVBAoMB01vbmdv
REIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVsIFRlc3QgQ0EXDTI0
-MDEyMjE4MTUyMVoXDTI0MDEyMjE4MTUyMlowDQYJKoZIhvcNAQELBQADggEBAOS+
-d7Gp9Pxc0mTXDKyyabCpcbsDKEDSEGfzswvEqSC097FwRZ8UQILEbkaIul+urqH0
-HnHk+Z2+R5Ldejg4IdwQ9trSPIqVLshrNA72yd1ME683UdSZ/+0e2WCPiDFfF857
-1duOlbEhkqOLqambl8YQnAsSGCJ7KMhB+r307P3EED5s/gWfjKpnciKbCuMai+8c
-qhSsL3Mc1AiAqxytL6njKP0MSyWTr5R2gluWnEvHzGU7qI3m4JJU3+Ge9pTFJa3B
-Jh2D4TUqTotVLayHHv5oL07rBE907S2C+ZVz6cHqb6XDAxlqstneKUyJRSLe/OWw
-pi/ZvmNMqxHqBnIwdBo=
+MDYxNDAyMzgzN1oXDTI0MDYxNDAyMzgzOFowDQYJKoZIhvcNAQELBQADggEBAHtF
+ILSpweDGPI1/gOSkxAScwv/aYFj65wEC1gJSXCzLndjm/ovib103UqcbxSqtAHN3
+OPX8GhgCRKp6bWStDBG+HTLuOWwkpN5hLkt+XdjPuoqKvjqpekotrVFYWTQhvlYw
+HPQr6nCiw4O+QwHPv4f9vinarDWnqlzW5jsDiFS03PatALFKXpVPI8TKWYtrqydO
+pZUhuh9tcD5SOSrsUjXuGcTT2Dzp3GTdZb2uJWjg3FzCVjG1L62HnMYR2lh/yQ/7
+aXqcn934KudI5sTfR2zhkxuMgNqDEawmNT6+aYN4ldajuHkrYCIFmhTaFYFK+so7
+CgGt6JZxS6vUG4wCuv4=
-----END X509 CRL-----
diff --git a/jstests/libs/crl_expired.pem.digest.sha1 b/jstests/libs/crl_expired.pem.digest.sha1
index 6ec03775e8c..84625f12a36 100644
--- a/jstests/libs/crl_expired.pem.digest.sha1
+++ b/jstests/libs/crl_expired.pem.digest.sha1
@@ -1 +1 @@
-6B87D2BE8D4B39E00EAFEC376A91892DBE1F361F \ No newline at end of file
+7AB0472F6C3D2585273C41C4412291BF982AE314 \ No newline at end of file
diff --git a/jstests/libs/crl_expired.pem.digest.sha256 b/jstests/libs/crl_expired.pem.digest.sha256
index 932f0690526..357d7c2d3dd 100644
--- a/jstests/libs/crl_expired.pem.digest.sha256
+++ b/jstests/libs/crl_expired.pem.digest.sha256
@@ -1 +1 @@
-3ACEE3AFF9262E831663BD06F584E2C6F779C4B47E7EF1DB491CD1CFDE529A77 \ No newline at end of file
+B4F079D5D1E753D96AA9C0A4EBE93C020B3AB5EF8E00DACD5E391047B8D9606B \ No newline at end of file
diff --git a/jstests/libs/crl_from_intermediate_ca_B.pem b/jstests/libs/crl_from_intermediate_ca_B.pem
new file mode 100644
index 00000000000..d96d60c5f61
--- /dev/null
+++ b/jstests/libs/crl_from_intermediate_ca_B.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBvTCBpjANBgkqhkiG9w0BAQsFADB3MQswCQYDVQQGEwJVUzERMA8GA1UECAwI
+TmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAOBgNVBAoMB01vbmdv
+REIxDzANBgNVBAsMBktlcm5lbDEaMBgGA1UEAwwRSW50ZXJtZWRpYXRlIENBIEIX
+DTI0MTAwNDE1MzM1NVoXDTI3MDEwNTE1MzM1NVowDQYJKoZIhvcNAQELBQADggEB
+ALHascvQiwxAIYAMuE2kP/SnEErR7uMxVteHN8HNUbfAX5k070mnGKlixsJ0I26Q
+/ZcERRIGFZRrpp0u4m1Sak6Kb1oGjrM91d+8N4szjgj4FSFD07siY6kuIbYVet6M
+ALR+Ww5uOqhOv54di1xvsETvuLOakvV7BTy2jv13SvC7+59EzamVBXUNgWUI8DX9
+tpew9KH7JXYzvjMvVbdr0QfoH/PYDKZmlK7vPG14VpBc4BvO6jpclKjmvOxO7rhA
++11Vp8Bij3IiHLTZtvofk7Fn+HiI5Zd5sLPHLQjRWWDt6g0FmuIqebJJTMGzzFtv
+bIDCUryP2KJ0BsxQG/5Rumc=
+-----END X509 CRL----- \ No newline at end of file
diff --git a/jstests/libs/crl_from_intermediate_ca_B.pem.digest.sha1 b/jstests/libs/crl_from_intermediate_ca_B.pem.digest.sha1
new file mode 100644
index 00000000000..945b0a3c52d
--- /dev/null
+++ b/jstests/libs/crl_from_intermediate_ca_B.pem.digest.sha1
@@ -0,0 +1 @@
+0A41FB5894DAB67FB8D5B57506FE35DE926BE5B9 \ No newline at end of file
diff --git a/jstests/libs/crl_from_intermediate_ca_B.pem.digest.sha256 b/jstests/libs/crl_from_intermediate_ca_B.pem.digest.sha256
new file mode 100644
index 00000000000..b70dc738cd3
--- /dev/null
+++ b/jstests/libs/crl_from_intermediate_ca_B.pem.digest.sha256
@@ -0,0 +1 @@
+5A78E0DB3DA5C54F97E83B1C041095EF36DFCBCBC7B6BEB1B28986CD8268ADDD \ No newline at end of file
diff --git a/jstests/libs/crl_from_trusted_ca.pem b/jstests/libs/crl_from_trusted_ca.pem
new file mode 100644
index 00000000000..b20c0d75065
--- /dev/null
+++ b/jstests/libs/crl_from_trusted_ca.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIBwjCBqzANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJVUzERMA8GA1UECAwI
+TmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAOBgNVBAoMB01vbmdv
+REIxDzANBgNVBAsMBktlcm5lbDEfMB0GA1UEAwwWVHJ1c3RlZCBLZXJuZWwgVGVz
+dCBDQRcNMjQxMDA0MTUzMzU1WhcNMjcwMTA1MTUzMzU1WjANBgkqhkiG9w0BAQsF
+AAOCAQEAJ+Tz2mzrlYMH0C6csdRwpG3xAMzvn5nFOuWdHDDWbtBKGYx0Jsds1fc1
+ccCthhYAvEFzCBCjiNm5VVplMGaSkxGZ+yHqXjssDslD7KDQ/4zj2nGme+p1kXHE
+ai5Q+gvHY1dJ4wDqtELQugDy737XHnPm98DqLuZjD31PhdOJt/NaO93L6A1kFrvQ
+fpL9XuCumhk1z7kCZiU/4ysjBshWAkx+9vGwlcxXkwq2zEYulf4FqsV2hShklp7z
+AdI2AQPkWov47h08XDWRbC/aQnCJyC3UXn/pqzwPtEH1gBE/ry2Fv0OUxrvHfB2q
+ACDic7GrdkKOrE8/m7RJPhsmd8VwTQ==
+-----END X509 CRL----- \ No newline at end of file
diff --git a/jstests/libs/crl_from_trusted_ca.pem.digest.sha1 b/jstests/libs/crl_from_trusted_ca.pem.digest.sha1
new file mode 100644
index 00000000000..ee838848cd0
--- /dev/null
+++ b/jstests/libs/crl_from_trusted_ca.pem.digest.sha1
@@ -0,0 +1 @@
+520F782BCF4CF6DB791C0420A71E4C9127F59039 \ No newline at end of file
diff --git a/jstests/libs/crl_from_trusted_ca.pem.digest.sha256 b/jstests/libs/crl_from_trusted_ca.pem.digest.sha256
new file mode 100644
index 00000000000..b27e77ad1c6
--- /dev/null
+++ b/jstests/libs/crl_from_trusted_ca.pem.digest.sha256
@@ -0,0 +1 @@
+42CA4384684DCDFC82D9A22BAA5485661E0849F00E42E8E1CEE6F83A96D57A4C \ No newline at end of file
diff --git a/jstests/libs/crl_intermediate_ca_B_revoked.pem b/jstests/libs/crl_intermediate_ca_B_revoked.pem
new file mode 100644
index 00000000000..a9ebdce2f7b
--- /dev/null
+++ b/jstests/libs/crl_intermediate_ca_B_revoked.pem
@@ -0,0 +1,12 @@
+-----BEGIN X509 CRL-----
+MIIB0zCBvDANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJVUzERMA8GA1UECAwI
+TmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAOBgNVBAoMB01vbmdv
+REIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVsIFRlc3QgQ0EXDTI0
+MTAwMTE3MDQwMVoXDTI3MDEwMjE3MDQwMVowFzAVAgQQP6lYFw0yNDEwMDExNzA0
+MDFaMA0GCSqGSIb3DQEBCwUAA4IBAQC6XLhZfKBhniiRGvZ5W6OI5IjW436WWzoA
+tfF3uheYqSL6CSfHKzmHBUcdQHv63qOgUTW6axRZmTY/7nTFi/XU93ICAdQaqSo6
+Hb/8XkgzAP6uElH/e9UA3H6EN8Htr/FqcszcRsn0DhZzVgt4lGjZ3sZOKyIXfH+X
+4/SkHR5vTAl3WsjhsXv1Vgcpa4K8FXocm27nTzByu3/nAM7dVg5Tbv4NZ43aChRD
+e5Hbaha5IO/vOR/p+JqzLcztjMibVWE49kTu83YhJgBmXHmMVvxu6Or3DWBP31S6
+8WpuVZgFDJ6WIEQo2jRwSQxVXf+NXu18/U6Ky6akCR/mpzHNRbPj
+-----END X509 CRL----- \ No newline at end of file
diff --git a/jstests/libs/crl_intermediate_ca_B_revoked.pem.digest.sha1 b/jstests/libs/crl_intermediate_ca_B_revoked.pem.digest.sha1
new file mode 100644
index 00000000000..ca06d755917
--- /dev/null
+++ b/jstests/libs/crl_intermediate_ca_B_revoked.pem.digest.sha1
@@ -0,0 +1 @@
+EB6AC7435EEC30A81FBCD1D9964245F0F24EE089 \ No newline at end of file
diff --git a/jstests/libs/crl_intermediate_ca_B_revoked.pem.digest.sha256 b/jstests/libs/crl_intermediate_ca_B_revoked.pem.digest.sha256
new file mode 100644
index 00000000000..152732785a9
--- /dev/null
+++ b/jstests/libs/crl_intermediate_ca_B_revoked.pem.digest.sha256
@@ -0,0 +1 @@
+2928A1FCB9268902A63005544ADAC00A228B008C21703E116145524E34DB9143 \ No newline at end of file
diff --git a/jstests/libs/ecdsa-ca-ocsp.crt b/jstests/libs/ecdsa-ca-ocsp.crt
index 1f29bfba26d..9633cda25f8 100644
--- a/jstests/libs/ecdsa-ca-ocsp.crt
+++ b/jstests/libs/ecdsa-ca-ocsp.crt
@@ -1,14 +1,14 @@
-----BEGIN CERTIFICATE-----
-MIICFDCCAbugAwIBAgIEf+mqfzAKBggqhkjOPQQDAjB6MQswCQYDVQQGEwJVUzER
+MIICFDCCAbugAwIBAgIEWFhd2jAKBggqhkjOPQQDAjB6MQswCQYDVQQGEwJVUzER
MA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAOBgNV
BAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEdMBsGA1UEAwwUS2VybmVsIFRl
-c3QgRVNDREEgQ0EwHhcNMjQwMTIyMTYxMTQ3WhcNMjYwNDI1MTYxMTQ3WjB6MQsw
+c3QgRVNDREEgQ0EwHhcNMjQwNjEyMTYxNDQ5WhcNMjYwOTE0MTYxNDQ5WjB6MQsw
CQYDVQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3Jr
IENpdHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEdMBsGA1UE
AwwUS2VybmVsIFRlc3QgRVNDREEgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
-AAQg4iui/59MGUXHQ8S6zfHyDPVjq0WwO2a8bXk1BJB0jK05gLcdN/ly1hQfvon3
-vtuOtWfMTi6m1ljvIccKE/lWoy8wLTAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBRG
-IPVIJfxNIXA+UrvH+Q0aiH+OmjAKBggqhkjOPQQDAgNHADBEAiB0gAMf00QnFIRu
-1TPDc7NJGUxVRaf1Wj7GmMnpJ0GRRwIgLCypm0QUhxAKhARr8Ebk5JbrM8BNM8Ok
-cMOMrowGlx0=
+AARgNZMr4zig3g+jEYgBFsbMLNrlsOSYkc9S3K9jKhm/lBMM8XQK0ZjyTT4IB53a
+zTSvxjS61nKk0cIMYDoC8/3soy8wLTAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBTx
+kLqAkw2BuHTs7wFlDSwTFmWleTAKBggqhkjOPQQDAgNHADBEAiA46WwcXR8Zhhwl
+grWL0NzEK+k50w9G8IQccCTp3bPlyAIgDdzY6TiMoaNM9ZAS5KcSiGIu4Ral1y/k
+027VhQ5LXnU=
-----END CERTIFICATE-----
diff --git a/jstests/libs/ecdsa-ca-ocsp.key b/jstests/libs/ecdsa-ca-ocsp.key
index 6edb178c21b..be687593aaf 100644
--- a/jstests/libs/ecdsa-ca-ocsp.key
+++ b/jstests/libs/ecdsa-ca-ocsp.key
@@ -1,5 +1,5 @@
-----BEGIN PRIVATE KEY-----
-MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgo09lQ51MLcgO/0q4
-TNgEw/eyu6+HY6GYFhTblak4dEmhRANCAAQg4iui/59MGUXHQ8S6zfHyDPVjq0Ww
-O2a8bXk1BJB0jK05gLcdN/ly1hQfvon3vtuOtWfMTi6m1ljvIccKE/lW
+MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgtu0LeoR5JUweCBkR
+kpR2G8oKB8XsQKfQtTLL+1RCD0qhRANCAARgNZMr4zig3g+jEYgBFsbMLNrlsOSY
+kc9S3K9jKhm/lBMM8XQK0ZjyTT4IB53azTSvxjS61nKk0cIMYDoC8/3s
-----END PRIVATE KEY-----
diff --git a/jstests/libs/ecdsa-ca-ocsp.pem b/jstests/libs/ecdsa-ca-ocsp.pem
index 29783b71c07..c49af95b3c1 100644
--- a/jstests/libs/ecdsa-ca-ocsp.pem
+++ b/jstests/libs/ecdsa-ca-ocsp.pem
@@ -1,19 +1,19 @@
-----BEGIN CERTIFICATE-----
-MIICFDCCAbugAwIBAgIEf+mqfzAKBggqhkjOPQQDAjB6MQswCQYDVQQGEwJVUzER
+MIICFDCCAbugAwIBAgIEWFhd2jAKBggqhkjOPQQDAjB6MQswCQYDVQQGEwJVUzER
MA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAOBgNV
BAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEdMBsGA1UEAwwUS2VybmVsIFRl
-c3QgRVNDREEgQ0EwHhcNMjQwMTIyMTYxMTQ3WhcNMjYwNDI1MTYxMTQ3WjB6MQsw
+c3QgRVNDREEgQ0EwHhcNMjQwNjEyMTYxNDQ5WhcNMjYwOTE0MTYxNDQ5WjB6MQsw
CQYDVQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3Jr
IENpdHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEdMBsGA1UE
AwwUS2VybmVsIFRlc3QgRVNDREEgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
-AAQg4iui/59MGUXHQ8S6zfHyDPVjq0WwO2a8bXk1BJB0jK05gLcdN/ly1hQfvon3
-vtuOtWfMTi6m1ljvIccKE/lWoy8wLTAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBRG
-IPVIJfxNIXA+UrvH+Q0aiH+OmjAKBggqhkjOPQQDAgNHADBEAiB0gAMf00QnFIRu
-1TPDc7NJGUxVRaf1Wj7GmMnpJ0GRRwIgLCypm0QUhxAKhARr8Ebk5JbrM8BNM8Ok
-cMOMrowGlx0=
+AARgNZMr4zig3g+jEYgBFsbMLNrlsOSYkc9S3K9jKhm/lBMM8XQK0ZjyTT4IB53a
+zTSvxjS61nKk0cIMYDoC8/3soy8wLTAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBTx
+kLqAkw2BuHTs7wFlDSwTFmWleTAKBggqhkjOPQQDAgNHADBEAiA46WwcXR8Zhhwl
+grWL0NzEK+k50w9G8IQccCTp3bPlyAIgDdzY6TiMoaNM9ZAS5KcSiGIu4Ral1y/k
+027VhQ5LXnU=
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgo09lQ51MLcgO/0q4
-TNgEw/eyu6+HY6GYFhTblak4dEmhRANCAAQg4iui/59MGUXHQ8S6zfHyDPVjq0Ww
-O2a8bXk1BJB0jK05gLcdN/ly1hQfvon3vtuOtWfMTi6m1ljvIccKE/lW
+MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgtu0LeoR5JUweCBkR
+kpR2G8oKB8XsQKfQtTLL+1RCD0qhRANCAARgNZMr4zig3g+jEYgBFsbMLNrlsOSY
+kc9S3K9jKhm/lBMM8XQK0ZjyTT4IB53azTSvxjS61nKk0cIMYDoC8/3s
-----END PRIVATE KEY-----
diff --git a/jstests/libs/ecdsa-ca-ocsp.pem.digest.sha1 b/jstests/libs/ecdsa-ca-ocsp.pem.digest.sha1
index 82ea36e04ba..577d6bb5f91 100644
--- a/jstests/libs/ecdsa-ca-ocsp.pem.digest.sha1
+++ b/jstests/libs/ecdsa-ca-ocsp.pem.digest.sha1
@@ -1 +1 @@
-18FEE57D155BBA058BA430787D16D1A6545BFE1F \ No newline at end of file
+D705527C174C6C7F7D217B9D21CB7965E73EA4AE \ No newline at end of file
diff --git a/jstests/libs/ecdsa-ca-ocsp.pem.digest.sha256 b/jstests/libs/ecdsa-ca-ocsp.pem.digest.sha256
index 647abdee5da..707230ff323 100644
--- a/jstests/libs/ecdsa-ca-ocsp.pem.digest.sha256
+++ b/jstests/libs/ecdsa-ca-ocsp.pem.digest.sha256
@@ -1 +1 @@
-807E6089013C6B38897DBE03143A6842B13EFE4C242DAC20F0AB43FA555DB3D0 \ No newline at end of file
+C0EDEA7AD6BF5AF92CF1CDCF75A676D73E71964B9D3150A4031361754D7371D2 \ No newline at end of file
diff --git a/jstests/libs/ecdsa-ca.pem b/jstests/libs/ecdsa-ca.pem
index 0cae4446983..2164510de87 100644
--- a/jstests/libs/ecdsa-ca.pem
+++ b/jstests/libs/ecdsa-ca.pem
@@ -4,24 +4,24 @@
# Root of ECDSA tree.
-----BEGIN CERTIFICATE-----
-MIICFTCCAbugAwIBAgIEBTwUNDAKBggqhkjOPQQDAjB6MQswCQYDVQQGEwJVUzER
+MIICFjCCAbugAwIBAgIEQkXGSjAKBggqhkjOPQQDAjB6MQswCQYDVQQGEwJVUzER
MA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAOBgNV
BAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEdMBsGA1UEAwwUS2VybmVsIFRl
-c3QgRVNDREEgQ0EwHhcNMjQwMTIyMTYxMTQ3WhcNMjYwNDI1MTYxMTQ3WjB6MQsw
+c3QgRVNDREEgQ0EwHhcNMjQwNjEyMTYxNDQ5WhcNMjYwOTE0MTYxNDQ5WjB6MQsw
CQYDVQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3Jr
IENpdHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEdMBsGA1UE
AwwUS2VybmVsIFRlc3QgRVNDREEgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
-AATvUhRthkwmX3lvQW9ZCs6JVPYt2e6d6pV3JStLVIaUEMzgnii8KxRzq5fmVc14
-hi2i0tbKW+jSpMoZftlAmRZNoy8wLTAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBRg
-KFVyJb0f8WwrGbEhYy9ReJgKljAKBggqhkjOPQQDAgNIADBFAiBrhVkJ/aeX4Cck
-aNZzxtNSGcSXPn5qaxeik3t1eJDOmwIhAORvOaVh9xXo2ksMTUn3QtyVJ1yHxUAO
-ywu2i457Hi4b
+AARk/RSX4PA0/6IWuPe3ld6afiFmQtdvHuZ5e1CfHP8BigL26jmRpnK1FMljin+L
+WeJiYlwTgp6ynoHUB6zU9Llnoy8wLTAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBSx
+9akK29+hcGF3mC+2oMlqYtrDdDAKBggqhkjOPQQDAgNJADBGAiEA/rwU6FeHAwP1
+pY/K1Ox9MIakwWd1GI9SvEYsA8yLXGgCIQD+9v+PiEHB88/i6qhDRxd24x/CMrHI
+C2b0ndc/EzluLQ==
-----END CERTIFICATE-----
-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
-MHcCAQEEIG01tW3uuY2x8CsFb+AFNilKSKEGlRSBNHYo5HElGp8AoAoGCCqGSM49
-AwEHoUQDQgAE71IUbYZMJl95b0FvWQrOiVT2LdnuneqVdyUrS1SGlBDM4J4ovCsU
-c6uX5lXNeIYtotLWylvo0qTKGX7ZQJkWTQ==
+MHcCAQEEIJVFvCPRKNVthE4F/8cuHEL2oP+KhcO7q7N47wsbvfJCoAoGCCqGSM49
+AwEHoUQDQgAEZP0Ul+DwNP+iFrj3t5Xemn4hZkLXbx7meXtQnxz/AYoC9uo5kaZy
+tRTJY4p/i1niYmJcE4Kesp6B1Aes1PS5Zw==
-----END EC PRIVATE KEY-----
diff --git a/jstests/libs/ecdsa-ca.pem.digest.sha1 b/jstests/libs/ecdsa-ca.pem.digest.sha1
index ceb50c5f373..51018faabff 100644
--- a/jstests/libs/ecdsa-ca.pem.digest.sha1
+++ b/jstests/libs/ecdsa-ca.pem.digest.sha1
@@ -1 +1 @@
-BD3E75054D62730754A896B6805ED979D57161A0 \ No newline at end of file
+C2D27D3788493B8FDFC07B6FA8A2AA5EA174906B \ No newline at end of file
diff --git a/jstests/libs/ecdsa-ca.pem.digest.sha256 b/jstests/libs/ecdsa-ca.pem.digest.sha256
index 08314abaec4..d06a9e368a5 100644
--- a/jstests/libs/ecdsa-ca.pem.digest.sha256
+++ b/jstests/libs/ecdsa-ca.pem.digest.sha256
@@ -1 +1 @@
-D82890BECA711894263F062B230AB30678DF9A4A94F7A8625D1F64386EAF12B6 \ No newline at end of file
+C4B84CE90D4CB16DA9F67E8271225A82E9C9E6154369255D054B7404B3EEF66D \ No newline at end of file
diff --git a/jstests/libs/ecdsa-client.pem b/jstests/libs/ecdsa-client.pem
index 37de2d2632c..77e62b223a1 100644
--- a/jstests/libs/ecdsa-client.pem
+++ b/jstests/libs/ecdsa-client.pem
@@ -4,22 +4,22 @@
# Client certificate for ECDSA tree.
-----BEGIN CERTIFICATE-----
-MIIB1DCCAXsCBCwfwM0wCgYIKoZIzj0EAwIwejELMAkGA1UEBhMCVVMxETAPBgNV
+MIIB1TCCAXsCBEZTTwMwCgYIKoZIzj0EAwIwejELMAkGA1UEBhMCVVMxETAPBgNV
BAgMCE5ldyBZb3JrMRYwFAYDVQQHDA1OZXcgWW9yayBDaXR5MRAwDgYDVQQKDAdN
b25nb0RCMQ8wDQYDVQQLDAZLZXJuZWwxHTAbBgNVBAMMFEtlcm5lbCBUZXN0IEVT
-Q0RBIENBMB4XDTI0MDEyMjE2MTE0N1oXDTI2MDQyNTE2MTE0N1owcDELMAkGA1UE
+Q0RBIENBMB4XDTI0MDYxMjE2MTQ0OVoXDTI2MDkxNDE2MTQ0OVowcDELMAkGA1UE
BhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMRYwFAYDVQQHDA1OZXcgWW9yayBDaXR5
MRAwDgYDVQQKDAdNb25nb0RCMRMwEQYDVQQLDApLZXJuZWxVc2VyMQ8wDQYDVQQD
-DAZjbGllbnQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATfi2Qp8KiVPXjX55/T
-mO4lx6WqCKgyOs0smk59Lj98ycvP2ok3+oFbZW7zKeExw1+aoH7Ioi959lT4lpnF
-fAjRMAoGCCqGSM49BAMCA0cAMEQCIHY9N75Nvsn7d7BoteheoZCZYEfhoq5oeJf6
-liIl6vK9AiAyKEJReKijsYevlapMZj4AQRlVwkBETtTNxb86GDSr8Q==
+DAZjbGllbnQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQv2fau3G1v45dBRCUw
+vfAG9ETpSGo6H57adMXevZrRSVOdaA9wM0TlBU0ZwfIszdLAbjyJvkcAisSUpROD
+y7+iMAoGCCqGSM49BAMCA0gAMEUCIQCxgojurLyBmNO0JktuIdcly/Le/9KnymLp
+Whku8K2VIwIgWVc/WT81kz6b5kWMiRfdHXuQ9MCheAHnOaz9hnJHE6Y=
-----END CERTIFICATE-----
-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
-MHcCAQEEIDaapJXw/GRAKLr9FOVYx5GqBC7p/VSXSRos+Ap8niX+oAoGCCqGSM49
-AwEHoUQDQgAE34tkKfColT141+ef05juJcelqgioMjrNLJpOfS4/fMnLz9qJN/qB
-W2Vu8ynhMcNfmqB+yKIvefZU+JaZxXwI0Q==
+MHcCAQEEIBsdJ+CJupwLOy765QcjOGBK9FsrzsxQVzYBr8C++ag8oAoGCCqGSM49
+AwEHoUQDQgAEL9n2rtxtb+OXQUQlML3wBvRE6UhqOh+e2nTF3r2a0UlTnWgPcDNE
+5QVNGcHyLM3SwG48ib5HAIrElKUTg8u/og==
-----END EC PRIVATE KEY-----
diff --git a/jstests/libs/ecdsa-client.pem.digest.sha1 b/jstests/libs/ecdsa-client.pem.digest.sha1
index cf425ac54f4..90d4c522de4 100644
--- a/jstests/libs/ecdsa-client.pem.digest.sha1
+++ b/jstests/libs/ecdsa-client.pem.digest.sha1
@@ -1 +1 @@
-5B7FB2430D27B6FF16E4FB468D51AC5067A8DD51 \ No newline at end of file
+E7C86336F9F148B0922184735CD1BC11E0E2AD5D \ No newline at end of file
diff --git a/jstests/libs/ecdsa-client.pem.digest.sha256 b/jstests/libs/ecdsa-client.pem.digest.sha256
index a9b872d4ef1..7bfd4e822b7 100644
--- a/jstests/libs/ecdsa-client.pem.digest.sha256
+++ b/jstests/libs/ecdsa-client.pem.digest.sha256
@@ -1 +1 @@
-B2BA5D94B45F33128B2237B157C318C3EBD2AEA8F7929074E7EF1CB84B02ED99 \ No newline at end of file
+9EFC3406886B0B625FE746F3A60E9B847153A5C8E55BF73ABDEE28EDC6656506 \ No newline at end of file
diff --git a/jstests/libs/ecdsa-ocsp-responder.crt b/jstests/libs/ecdsa-ocsp-responder.crt
index 9c5cbabd286..d03813720fd 100644
--- a/jstests/libs/ecdsa-ocsp-responder.crt
+++ b/jstests/libs/ecdsa-ocsp-responder.crt
@@ -1,16 +1,16 @@
-----BEGIN CERTIFICATE-----
-MIICeTCCAh+gAwIBAgIERsPqYDAKBggqhkjOPQQDAjB6MQswCQYDVQQGEwJVUzER
+MIICeTCCAh+gAwIBAgIESfEy6zAKBggqhkjOPQQDAjB6MQswCQYDVQQGEwJVUzER
MA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAOBgNV
BAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEdMBsGA1UEAwwUS2VybmVsIFRl
-c3QgRVNDREEgQ0EwHhcNMjQwMTIyMTYxMTQ3WhcNMjYwNDI1MTYxMTQ3WjBsMQsw
+c3QgRVNDREEgQ0EwHhcNMjQwNjEyMTYxNDQ5WhcNMjYwOTE0MTYxNDQ5WjBsMQsw
CQYDVQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3Jr
IENpdHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEPMA0GA1UE
-AwwGc2VydmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEj08OTVJ8hguQKnKA
-YJb1UYTT2f4+U3o66HTBIH64sZNtZ1r9swz91QzVktaBIXjO4zkfK69yMkP3QUBL
-rmrQvKOBoDCBnTAJBgNVHRMEAjAAMBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAA
-ATAdBgNVHQ4EFgQUn3toS9eGTWrW0NsuA9JfHytMIHswCwYDVR0PBAQDAgXgMCcG
+AwwGc2VydmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEXVrgWDLpKY1WEUjk
+0ekovJFEbTdh9k/tnofLzVLWGFxeowvby0FzrF3SLjzGtn9NfTG2nZSLDF6sjach
+OOQOEKOBoDCBnTAJBgNVHRMEAjAAMBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAA
+ATAdBgNVHQ4EFgQUnD+dYSNlfLysgDIFgFta23i7mngwCwYDVR0PBAQDAgXgMCcG
A1UdJQQgMB4GCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwkwHwYDVR0jBBgw
-FoAURiD1SCX8TSFwPlK7x/kNGoh/jpowCgYIKoZIzj0EAwIDSAAwRQIgdu+cF19n
-98I74yeStxyub/8WEQC6fVr+tLB1Jw7F8JUCIQDkT1YhLDg34jC16DwDqywxE442
-Gkbf7bvY7EVWU77/GQ==
+FoAU8ZC6gJMNgbh07O8BZQ0sExZlpXkwCgYIKoZIzj0EAwIDSAAwRQIgQCBkfSaU
+3wXpTW1HBxWAHBhi4l7NHhOvUJLkcpups/sCIQDnTBHnP5wa41rPPovfB0KfC0Nh
+GiXelzE/Otyu1NHKkA==
-----END CERTIFICATE-----
diff --git a/jstests/libs/ecdsa-ocsp-responder.crt.digest.sha1 b/jstests/libs/ecdsa-ocsp-responder.crt.digest.sha1
index 50ba4628e21..2508409158a 100644
--- a/jstests/libs/ecdsa-ocsp-responder.crt.digest.sha1
+++ b/jstests/libs/ecdsa-ocsp-responder.crt.digest.sha1
@@ -1 +1 @@
-3A25C82C9AC7AA873EF884AED594C7B3CBA76B3B \ No newline at end of file
+E4A26A623C4978F12F13FEF4AC056763B235E231 \ No newline at end of file
diff --git a/jstests/libs/ecdsa-ocsp-responder.crt.digest.sha256 b/jstests/libs/ecdsa-ocsp-responder.crt.digest.sha256
index 964c5f60fac..4c65ebdba3e 100644
--- a/jstests/libs/ecdsa-ocsp-responder.crt.digest.sha256
+++ b/jstests/libs/ecdsa-ocsp-responder.crt.digest.sha256
@@ -1 +1 @@
-F44C7CF4780FDF8B37C69FEF372749492A6B1FC34C8C2E4CB5CD4B32C57A8AB0 \ No newline at end of file
+82B35D4B99223D9779D04343EE88C4D0311FDF57BDF9C6727297149B62F5F473 \ No newline at end of file
diff --git a/jstests/libs/ecdsa-ocsp-responder.key b/jstests/libs/ecdsa-ocsp-responder.key
index e92ff2058af..05d4695ce29 100644
--- a/jstests/libs/ecdsa-ocsp-responder.key
+++ b/jstests/libs/ecdsa-ocsp-responder.key
@@ -1,5 +1,5 @@
-----BEGIN PRIVATE KEY-----
-MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgxPMzk1hl1fW+3EO7
-ol87gjp4NrMTInSU2dn5mZPj2JGhRANCAASPTw5NUnyGC5AqcoBglvVRhNPZ/j5T
-ejrodMEgfrixk21nWv2zDP3VDNWS1oEheM7jOR8rr3IyQ/dBQEuuatC8
+MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgw0fUyC7cLUfF7VM7
+/PUaLmrlb0nyfaDRBb7umQTnMdihRANCAARdWuBYMukpjVYRSOTR6Si8kURtN2H2
+T+2eh8vNUtYYXF6jC9vLQXOsXdIuPMa2f019MbadlIsMXqyNpyE45A4Q
-----END PRIVATE KEY-----
diff --git a/jstests/libs/ecdsa-server-ocsp-mustStaple.pem b/jstests/libs/ecdsa-server-ocsp-mustStaple.pem
index 3f255a62525..02d2c4576f7 100644
--- a/jstests/libs/ecdsa-server-ocsp-mustStaple.pem
+++ b/jstests/libs/ecdsa-server-ocsp-mustStaple.pem
@@ -1,23 +1,23 @@
-----BEGIN CERTIFICATE-----
-MIIC7jCCApOgAwIBAgIEQWEoXTAKBggqhkjOPQQDAjB6MQswCQYDVQQGEwJVUzER
+MIIC7DCCApOgAwIBAgIEDewgkTAKBggqhkjOPQQDAjB6MQswCQYDVQQGEwJVUzER
MA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAOBgNV
BAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEdMBsGA1UEAwwUS2VybmVsIFRl
-c3QgRVNDREEgQ0EwHhcNMjQwMTIyMTYxMTQ3WhcNMjYwNDI1MTYxMTQ3WjBsMQsw
+c3QgRVNDREEgQ0EwHhcNMjQwNjEyMTYxNDQ5WhcNMjYwOTE0MTYxNDQ5WjBsMQsw
CQYDVQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3Jr
IENpdHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEPMA0GA1UE
-AwwGc2VydmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESm5ZKRhzaLpSri6S
-m8ezaZ4zz0orxPbVBgNf4DMvhEFTJHXpQEeH9W/v7Kp2mEfCRxKWy5JINF7bs3/U
-juQXRaOCARMwggEPMAkGA1UdEwQCMAAwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/
-AAABMB0GA1UdDgQWBBSeNE3TDmY6EJDc1qieEXXRUA81OzALBgNVHQ8EBAMCBaAw
+AwwGc2VydmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEL0Jm+q28keUNp7Fg
+puWK/9CYwENxs/Jz3DDphDJU6vzFt2vpmTI0t0cgg387BUhWGQlWDo08kS/sk0j2
+Dmxg2aOCARMwggEPMAkGA1UdEwQCMAAwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/
+AAABMB0GA1UdDgQWBBQRTIHd0QWEljTQ04qSWPwf3kmowjALBgNVHQ8EBAMCBaAw
HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMGcGCCsGAQUFBwEBBFswWTAt
BggrBgEFBQcwAYYhaHR0cDovL2xvY2FsaG9zdDo5MDAxL3Bvd2VyL2xldmVsMCgG
CCsGAQUFBzABhhxodHRwOi8vbG9jYWxob3N0OjgxMDAvc3RhdHVzMBEGCCsGAQUF
-BwEYBAUwAwIBBTAfBgNVHSMEGDAWgBRGIPVIJfxNIXA+UrvH+Q0aiH+OmjAKBggq
-hkjOPQQDAgNJADBGAiEAzUReQAnkn3yjlf5/gPhJuxblIppU9msD2BzAuhUqroQC
-IQDHf0RORr4NXODpiF7Dn25qlDU8AmvgDdPNj7IdIpV4QA==
+BwEYBAUwAwIBBTAfBgNVHSMEGDAWgBTxkLqAkw2BuHTs7wFlDSwTFmWleTAKBggq
+hkjOPQQDAgNHADBEAiBq0UjHLeIeI7nLP++iW/wnjQNmVqZXq1BbLZaSMAVXMAIg
+MwGOS9dce14kzChki2VHlgsBmSa5TIHYuzZ6wjWiRjI=
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgPYASX6QrrbFg4KXO
-KzwgMyd5QPqYSZJL2nN991vcqBOhRANCAARKblkpGHNoulKuLpKbx7NpnjPPSivE
-9tUGA1/gMy+EQVMkdelAR4f1b+/sqnaYR8JHEpbLkkg0Xtuzf9SO5BdF
+MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgrkqbXYW1aa0p7EF5
+4ZrhZ/4soKlnPELcFotNk1eJZ1GhRANCAAQvQmb6rbyR5Q2nsWCm5Yr/0JjAQ3Gz
+8nPcMOmEMlTq/MW3a+mZMjS3RyCDfzsFSFYZCVYOjTyRL+yTSPYObGDZ
-----END PRIVATE KEY-----
diff --git a/jstests/libs/ecdsa-server-ocsp-mustStaple.pem.digest.sha1 b/jstests/libs/ecdsa-server-ocsp-mustStaple.pem.digest.sha1
index 5094bc89b44..ce407e1cd97 100644
--- a/jstests/libs/ecdsa-server-ocsp-mustStaple.pem.digest.sha1
+++ b/jstests/libs/ecdsa-server-ocsp-mustStaple.pem.digest.sha1
@@ -1 +1 @@
-21DC9BDEA09E5DF65F7B6FB3A2718FAE47625527 \ No newline at end of file
+119BBC4916C89AA3EA2146AF4588745EA727AC6E \ No newline at end of file
diff --git a/jstests/libs/ecdsa-server-ocsp-mustStaple.pem.digest.sha256 b/jstests/libs/ecdsa-server-ocsp-mustStaple.pem.digest.sha256
index 1b394aa6c6f..9c8a8b6bc65 100644
--- a/jstests/libs/ecdsa-server-ocsp-mustStaple.pem.digest.sha256
+++ b/jstests/libs/ecdsa-server-ocsp-mustStaple.pem.digest.sha256
@@ -1 +1 @@
-720E9B92616603606CEC483DCFD4A67A9040B2289EAE90FD19FB583123CE9A95 \ No newline at end of file
+219DEB66B8F1AF1C56285CA3755D83659FDACA52F44660E190BF40D42C45468E \ No newline at end of file
diff --git a/jstests/libs/ecdsa-server-ocsp.pem b/jstests/libs/ecdsa-server-ocsp.pem
index a499313c798..7e604a6bff7 100644
--- a/jstests/libs/ecdsa-server-ocsp.pem
+++ b/jstests/libs/ecdsa-server-ocsp.pem
@@ -1,23 +1,23 @@
-----BEGIN CERTIFICATE-----
-MIIC1zCCAn6gAwIBAgIEGWlZWjAKBggqhkjOPQQDAjB6MQswCQYDVQQGEwJVUzER
+MIIC2DCCAn6gAwIBAgIEF9gU5zAKBggqhkjOPQQDAjB6MQswCQYDVQQGEwJVUzER
MA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAOBgNV
BAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEdMBsGA1UEAwwUS2VybmVsIFRl
-c3QgRVNDREEgQ0EwHhcNMjQwMTIyMTYxMTQ3WhcNMjYwNDI1MTYxMTQ3WjBsMQsw
+c3QgRVNDREEgQ0EwHhcNMjQwNjEyMTYxNDQ5WhcNMjYwOTE0MTYxNDQ5WjBsMQsw
CQYDVQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3Jr
IENpdHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEPMA0GA1UE
-AwwGc2VydmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEGk9VT+B1LEe/FL0
-qC7bHl9GbTV5M8ICQghOVb0F3GaW532BUULfiFOf4e7hBqa9hywi8rMPXh1JEu5H
-B2f/+6OB/zCB/DAJBgNVHRMEAjAAMBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAA
-ATAdBgNVHQ4EFgQUG+2fpiL1/iRcg4Y1aNyzsAuUqNswCwYDVR0PBAQDAgWgMB0G
+AwwGc2VydmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEsKbt/x2dfTOUXCSZ
+oDOJma83ZimpF4AYNSTmdDbn//XXH9KqDrEmUh315bHqxrlY2KmQWsiq4Ayn0Gwv
+YIS5u6OB/zCB/DAJBgNVHRMEAjAAMBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAA
+ATAdBgNVHQ4EFgQUYNvo3MBecpfz3i9p+jRbJC1XFxowCwYDVR0PBAQDAgWgMB0G
A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjBnBggrBgEFBQcBAQRbMFkwLQYI
KwYBBQUHMAGGIWh0dHA6Ly9sb2NhbGhvc3Q6OTAwMS9wb3dlci9sZXZlbDAoBggr
BgEFBQcwAYYcaHR0cDovL2xvY2FsaG9zdDo4MTAwL3N0YXR1czAfBgNVHSMEGDAW
-gBRGIPVIJfxNIXA+UrvH+Q0aiH+OmjAKBggqhkjOPQQDAgNHADBEAiBGPc3Mts4Q
-4aEpUPK/lee0PU3ISmU2nTRQMIg0epX6EAIgI4s8qe9iK3UB+iwpQeHW7bKlioAS
-ng7ZUPRQRuWNXCw=
+gBTxkLqAkw2BuHTs7wFlDSwTFmWleTAKBggqhkjOPQQDAgNIADBFAiEAqoWdxjQf
+ZmV1y+jMbY2IRQ7WkvfDGN+ilHCtNzDj+dcCIC8q5hh407W5ZjMg8F6XL2MHvYsT
+e2qDlul6A83Q0s51
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgcGADx6ZGUKAls1mi
-8IUuWAzUIHt1c76/1QwYm4R8JF6hRANCAAQQaT1VP4HUsR78UvSoLtseX0ZtNXkz
-wgJCCE5VvQXcZpbnfYFRQt+IU5/h7uEGpr2HLCLysw9eHUkS7kcHZ//7
+MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgVS5ZMswjZy4ySi00
+fSdEjD3j2dowkzs1QWEeNw1LaWGhRANCAASwpu3/HZ19M5RcJJmgM4mZrzdmKakX
+gBg1JOZ0Nuf/9dcf0qoOsSZSHfXlserGuVjYqZBayKrgDKfQbC9ghLm7
-----END PRIVATE KEY-----
diff --git a/jstests/libs/ecdsa-server-ocsp.pem.digest.sha1 b/jstests/libs/ecdsa-server-ocsp.pem.digest.sha1
index f84a3cba206..9755b6229e9 100644
--- a/jstests/libs/ecdsa-server-ocsp.pem.digest.sha1
+++ b/jstests/libs/ecdsa-server-ocsp.pem.digest.sha1
@@ -1 +1 @@
-D374E6032AEB154DDE5736A10439177747DCD5F8 \ No newline at end of file
+26C79E7E069AD99573663636EC5AC90EF023D002 \ No newline at end of file
diff --git a/jstests/libs/ecdsa-server-ocsp.pem.digest.sha256 b/jstests/libs/ecdsa-server-ocsp.pem.digest.sha256
index a3f9c6b2ec5..8ef62bfdf12 100644
--- a/jstests/libs/ecdsa-server-ocsp.pem.digest.sha256
+++ b/jstests/libs/ecdsa-server-ocsp.pem.digest.sha256
@@ -1 +1 @@
-6A447E5B5B20AB80DAB20575159BCEF8C137784FBFCF0796E1543B5D168DFC9D \ No newline at end of file
+60762550C178BE940DFDA65A5C84F3AE2DC61D3BEA1B0FEAF85FFCB830489F4B \ No newline at end of file
diff --git a/jstests/libs/ecdsa-server.pem b/jstests/libs/ecdsa-server.pem
index 5c81c06b4e5..58560da80ff 100644
--- a/jstests/libs/ecdsa-server.pem
+++ b/jstests/libs/ecdsa-server.pem
@@ -4,26 +4,26 @@
# Server certificate for ECDSA tree.
-----BEGIN CERTIFICATE-----
-MIICcDCCAhWgAwIBAgIERsYHJTAKBggqhkjOPQQDAjB6MQswCQYDVQQGEwJVUzER
+MIICbzCCAhWgAwIBAgIEJPTmFDAKBggqhkjOPQQDAjB6MQswCQYDVQQGEwJVUzER
MA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAOBgNV
BAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEdMBsGA1UEAwwUS2VybmVsIFRl
-c3QgRVNDREEgQ0EwHhcNMjQwMTIyMTYxMTQ3WhcNMjYwNDI1MTYxMTQ3WjBsMQsw
+c3QgRVNDREEgQ0EwHhcNMjQwNjEyMTYxNDQ5WhcNMjYwOTE0MTYxNDQ5WjBsMQsw
CQYDVQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3Jr
IENpdHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEPMA0GA1UE
-AwwGc2VydmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENn4pCjEJYo3yPonV
-dvaF0e7mB1RM51ymmvCjI0gbzUVwkKkgEcfIOvG7pr9ywDR8pdjMd4vysO3rxS66
-3WWf7aOBljCBkzAJBgNVHRMEAjAAMBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAA
-ATAdBgNVHQ4EFgQUO7zxDRdNiUustB+D8Y9Lc7psRDYwCwYDVR0PBAQDAgWgMB0G
-A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAfBgNVHSMEGDAWgBRgKFVyJb0f
-8WwrGbEhYy9ReJgKljAKBggqhkjOPQQDAgNJADBGAiEA4+MS6ET5wvod3o01GJ9B
-ss2qZ4GTlj0rgYyy+wg0Iw0CIQCTL+moLAt6c1v7f9U7HBFzn2jqW8PwMUKIN5ez
-AxLR+Q==
+AwwGc2VydmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkwb5MwmLBvOcNN56
+bHD1X01zycR2paXveqMc/ID/bng78dTLSSKDvDJ3UzBzW1YhNo4ntzAcGvBJRrkb
+6gGOu6OBljCBkzAJBgNVHRMEAjAAMBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAA
+ATAdBgNVHQ4EFgQUBs832lDcwDFwC6qYkpKZf18YxF4wCwYDVR0PBAQDAgWgMB0G
+A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAfBgNVHSMEGDAWgBSx9akK29+h
+cGF3mC+2oMlqYtrDdDAKBggqhkjOPQQDAgNIADBFAiEA3GoaM4C7fI/OmGHv2QoM
+UvQ7kb91GOuZc51wIOqRLOsCIBpnF0BEekN/2lDOm/v71Amg7ukisuXR75UBR8uz
+5eAT
-----END CERTIFICATE-----
-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
-MHcCAQEEIIuchTfTWifCFiQ/qc2f+vFfb7/3MYViHDND5Wwm4YomoAoGCCqGSM49
-AwEHoUQDQgAENn4pCjEJYo3yPonVdvaF0e7mB1RM51ymmvCjI0gbzUVwkKkgEcfI
-OvG7pr9ywDR8pdjMd4vysO3rxS663WWf7Q==
+MHcCAQEEIGe/mYpft3Yov0QbbfoWgTuixEubQb7O3X+ivuFriuGjoAoGCCqGSM49
+AwEHoUQDQgAEkwb5MwmLBvOcNN56bHD1X01zycR2paXveqMc/ID/bng78dTLSSKD
+vDJ3UzBzW1YhNo4ntzAcGvBJRrkb6gGOuw==
-----END EC PRIVATE KEY-----
diff --git a/jstests/libs/ecdsa-server.pem.digest.sha1 b/jstests/libs/ecdsa-server.pem.digest.sha1
index a9106de5f26..2c8b01762d1 100644
--- a/jstests/libs/ecdsa-server.pem.digest.sha1
+++ b/jstests/libs/ecdsa-server.pem.digest.sha1
@@ -1 +1 @@
-94A674D102A3E16CAAB6E25EC38D34320CB82B68 \ No newline at end of file
+D557239BE21748A8FDAEFDC3187467CA5E2CA9FC \ No newline at end of file
diff --git a/jstests/libs/ecdsa-server.pem.digest.sha256 b/jstests/libs/ecdsa-server.pem.digest.sha256
index 29491d760ba..7fc15546552 100644
--- a/jstests/libs/ecdsa-server.pem.digest.sha256
+++ b/jstests/libs/ecdsa-server.pem.digest.sha256
@@ -1 +1 @@
-7396AEA83D86A3AFA9210D1429495FB05D726CA679C801D2CDA83B73F1398B9A \ No newline at end of file
+B170A66807997F614E90A4321CE55A5A506C72CF8A9A8E381E21D9752150ACF9 \ No newline at end of file
diff --git a/jstests/libs/expired.pem b/jstests/libs/expired.pem
index 4de2b24f328..bb06736d623 100644
--- a/jstests/libs/expired.pem
+++ b/jstests/libs/expired.pem
@@ -3,52 +3,52 @@
#
# A certificate which has passed its expiration date.
-----BEGIN CERTIFICATE-----
-MIIDkjCCAnqgAwIBAgIEFG5ETTANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDkjCCAnqgAwIBAgIEYQXKwTANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjMwOTI4MjIyNDU2WhcNMjQwMTExMDIyNDU2WjBtMQswCQYD
+IFRlc3QgQ0EwHhcNMjQwMjE3MjIyODA2WhcNMjQwNjAxMDIyODA2WjBtMQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEQMA4GA1UEAwwH
-ZXhwaXJlZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM196Mzf0Xci
-UvtIYb/oq1BNdPwVSNyEbzYZc+cXqcmel78ffSPH9w4WpFNi7xo9hVW3u3F+E5Tr
-VAehsII3Vinx1wFHk8l4VWpxOE+GzxfG6P+R4bZPg/04uG+6wSuAnnl6LEqnND3O
-O+CPIpoOtjTZga3FkAMmZF+81bHH8q3t1tl/PFp5pENPCp2h2uCxtHCVrz3lC4kP
-vR7nhe0dPWAIEkYRAXiqfYvVdq9I4R+Htwx9JrUKsdn87TSFwuuZZ++q0iELPIWg
-8t6egrW/4znG44MiR7d6aKGWWZKfi+BJf27IE4cAYPURo3mmXyp/4E2SYADK6Ok7
-NpyyEw+3+WkCAwEAAaMzMDEwEwYDVR0lBAwwCgYIKwYBBQUHAwEwGgYDVR0RBBMw
-EYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBAQBtZPhNmbUNDN7F
-InyRYdHb+cXVHmIN1jBbHjudQA3BS5IgtNkAjhbv777euxMe7j6LJW0oli4otDQW
-/ZsLX47y6LOZeXbMa9oqft/+gIls2fewzVaasljyqsBTML8SgWmZuGIgAKk+e9RD
-tL/gXCMGLcl60RXodJFe1AJkITj7Oo7F7NP50dh9qSuiy9wx+5H83gZVjJ3Uylch
-ri1JqVUqNBObOfSvphhTBmCOe3bB8l9mc6TjnNDSM3ORevpFApxcJ+v58IsVU5Cp
-7WNuHjhbMUX2KLSTB8Yhjfpql1uxI4yVWl/8z2OwXe0PFBbytiMwtXmTVSuZ1wNl
-OH5wBSxn
+ZXhwaXJlZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMIADzrcUgzr
+YOqHomaPsbchV8qkHghuLLszi4xTrXt324KD/rIkBIcAltjhXSmoQwaeTeideRoE
+USdzQNlDbRW2OwWeced9/LZJ+Yx2igcQE9yRzq/4KMxdyCx7sBpdtdQrfhCt0n+n
+p5hLhR9iZEsizPLVg5Ei8x8mbQxEfeTdVmv+9914yreMUulgKxu5EzREflPyCVQc
+QfFSXF/f/atA2tdwnOOEHeJCnr6ijRtAw/RWE8w1B6xtcpVhB+7G01kCBxvMHAMr
+ys+Tr7jOZ4n4wUVlJwcCCOl01FSefQNaPH6RIRGBe8XVAjlN4Xve5dbM6o9DL1xv
+MJ0FdcQvFnECAwEAAaMzMDEwEwYDVR0lBAwwCgYIKwYBBQUHAwEwGgYDVR0RBBMw
+EYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBAQC8BROimbLKSKE8
+e0xOzEPETLBH55N7CU82byr6NEqIqMZM1marsksBsXsX3ppfuUSgKKVxb/dZnBFr
+cCo5iS/i1qAoBpAALOMoWWHSzOuAtgiVAK3ikqHfl7mwaUYE4VVWOUAQpksT9blf
+gtiqQ+hlZzzQn1iCEh+5OxKzTZy+Icwp0pCJvY00LrRYkutJqWqJTnKeu0+BbgJQ
+cQi2URnRRuEsaF7JUnpArnsi9U/OKrUbhSTu4b/opsdug+tkRylrXo8N5t3GYiHx
+3xWL6j06W1AA7EdwIgPDsBO+ZTZgEIx9+E66Xhuk/4HFt4LxRb4ATp2NnbQdxc2Q
+QfrSmtGQ
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDNfejM39F3IlL7
-SGG/6KtQTXT8FUjchG82GXPnF6nJnpe/H30jx/cOFqRTYu8aPYVVt7txfhOU61QH
-obCCN1Yp8dcBR5PJeFVqcThPhs8Xxuj/keG2T4P9OLhvusErgJ55eixKpzQ9zjvg
-jyKaDrY02YGtxZADJmRfvNWxx/Kt7dbZfzxaeaRDTwqdodrgsbRwla895QuJD70e
-54XtHT1gCBJGEQF4qn2L1XavSOEfh7cMfSa1CrHZ/O00hcLrmWfvqtIhCzyFoPLe
-noK1v+M5xuODIke3emihllmSn4vgSX9uyBOHAGD1EaN5pl8qf+BNkmAAyujpOzac
-shMPt/lpAgMBAAECggEABJ0onn0CB4JCSbkY1MXFHvL2Rvi1X5oroxPUOeKaodfJ
-QXXUCfsh7XONsf+dLcIm3cNX1pcFmojkJJ25SFs0uJFhCfrQ8yucA11SbdqxiK+j
-KKXeYwkLBiMBZSTU1IS5SjH3j5+MeTzJtGOSW9IrvikKE9xFPQTeKRYk2C6MoOIV
-XeBxdO+y93QEqCJr+lZhGBZseXOsUXHIblXapykJLSQ+MzYO1SsaTD2gAznhk9RU
-JrX3NadVQPBTx3Bdq+kdGrWpO5XYicpffI7aHIr8KVvOmehOvDHVatuAV8tGiaEc
-GS24yZFea0fqubFobwNoYme6AkJiwfnK2JZkigmCVwKBgQDNnQwBHnAqhORYUx5L
-TX/QG2D+t0KIMST7DHLAUYZSgafDjcPAA++a8uAjARujAkYS1EwJFWIT47tAZzC6
-3lXgHFuNzgXoZbkx0BiacmjFh9rneLPypWphG4x0BD7kYlsrJxQfv1PDMCFfdjxF
-0q2Zx4LeRxAHFPzImJBvhun9bwKBgQD/2TtqUKAm/lqsAGNbQFJvxvsByuSpmMqC
-B57Jx9UkExqSfXROB5Lgn8GzN4vUpoloiklPyzs0ZoqeUOq3G05Qci/f/IsBNAO3
-Jv6HB+l6XMSWOs+lGOwr8AB3pDDBFRZNnnWW1BYLsZG18isDFpwDk7K1IwBhjHi9
-zaL3DZ+6pwKBgQDK0whsciIjT0QQ/Kz9i01xdBCSMySmRBQ+sWDg5YqjCNL8zHM0
-jq1lJACFhypD+pI1MMZwj29YP2UPertPGtOLZ23IzFp3jSDKSoR6ljFT6Ve+zgp0
-aUgu0oYSS73efEeCoeHwD0QJXwkMqg16swAcmfo2WdMtqT5Sgmy4F1XqcQKBgHCt
-fGRbM91YghhkZ12l22iNCrkEYWZr+yv/LSiS0MT9gONpSxKedUpmMYm7eeLioXug
-A5+X0vBGBOCqpGSWKwx07a7I63NRNB2yl8BidKpGNvIu3opIiqLjJWGLt0kh/1uZ
-4RHXQApQXurxx42ppHZS0w7BZoaPthFpgk8p+eHbAoGBAM1+L+7+/tDorxXlcXU0
-ZMB/Po/oB6c0GA99AN0p2Dz6TkdHymt9nYNpWqP4xpazetCYHKOefD59RYR5adR+
-KHw7YP4AGgxzJgZOgiWqHzJ4IwEjZPqoQ2GJ7X7P72rfMYCX4FJOZOJaS0t+jI5S
-I9TAUnjTXl2FWjH7k0USBYYf
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDCAA863FIM62Dq
+h6Jmj7G3IVfKpB4Ibiy7M4uMU617d9uCg/6yJASHAJbY4V0pqEMGnk3onXkaBFEn
+c0DZQ20VtjsFnnHnffy2SfmMdooHEBPckc6v+CjMXcgse7AaXbXUK34QrdJ/p6eY
+S4UfYmRLIszy1YORIvMfJm0MRH3k3VZr/vfdeMq3jFLpYCsbuRM0RH5T8glUHEHx
+Ulxf3/2rQNrXcJzjhB3iQp6+oo0bQMP0VhPMNQesbXKVYQfuxtNZAgcbzBwDK8rP
+k6+4zmeJ+MFFZScHAgjpdNRUnn0DWjx+kSERgXvF1QI5TeF73uXWzOqPQy9cbzCd
+BXXELxZxAgMBAAECggEBAKxJlTz20T98AjQGhKmEz5UNXYQvQCTIg50056eV4KmY
+Bi/gvV7DMeobEdxGOJB4SB4mlJYS06vRTak1Z9ALW2M+1SfmUM3/S2EwTRj7ZRVk
+p97o9p+8Sa9FUjJ/HiQsOQDWJzz0wc5wvBw6ZV076kn3+/9ks1U/rp5pZ8rPQObw
+RiU5cUg+Xgq/c9KS69h2HKDwqwe5wSqYZ06m73U48eenjda9L01W26XFt4Osz+Zh
+iVL8DbIa72WckMGW2ZvTA7YuF3Lk21pG/LzmheSY9tuVFf+ys4jnllbHffqusNpB
+OSKJWoScvnFe+E+ezWHzIMUG6n4zjpWXBxad5HFLEMkCgYEA6rTydmcdhw8BsfmZ
+UpelEf9Y+KsCpc7LV7IK9VV5Bb6e/PGiE4jDVULyJTRQG0sbrHYJsv4Qrw0DxpVN
+PLN4MzY5392oKPZej1rUSXM2yO0JQYksmo0lFipFaB2Pwx2O0Fu1mzfwunfobwyF
+YgRKPqsJV3R3GyRf8otppnoCLesCgYEA05m0PCKMrO0x8/HL+Ph4g4vmBi58p6/Q
+5vqXXcSYvtRa526qSv2Z+dsnbCvwKry9xd06nTaTmncoed/mWjScIzJD7ZDLkv27
+JCmHN/x1nyxy/2JiJOKIdPUnv5m/XvWcd4v/GhQfBgRQV623FZev8mAZMErdDbsH
+vFU8OemPihMCgYBI/mmBxWP7gwFF9phmhV8DD+T9wUGbi4rWBTs/PYvb64LKq+N6
+K8iEFcP1KiXXty4uHq+5iSZrKqMH+ZsBy9cQJkcthmQsCSMzdk4bYceiCYYdaaoD
+ju3/zLm1PaxeRC0MQ9lhIq6tb2lMUBqTdz4X612GY2Q/frqQVidPbRaMbQKBgQCZ
+hAsCEeLT1uaF4GgmgkYU0huZYoKnueOqoCXPLsHOuQwWmfBMpb7fSgNI9Huy1eos
+sjtDMgRWbZrdCPb7fO3Gj0I/CezYAOOT8dkbYjsHt1zbMcqYjg2IJRCobmgsAa96
+AASdK/nyCJEte2e376wEAXpk0fucaZPMLF6ceXndJwKBgEexYP/j6RViv9o/umWi
+iMtKc2Bnv7qe74+Z9PnQ3lLxVt8GNW52BICvJfJH0hcctiuIlG5Ys/HWIntfhOT+
+6nm2H0WPTIuMyV/P8OJzjYA4PekP6xO2ihkwFifjq/TWdO62XRCzjtpZ08fhIpRV
+940C4Qp1dq6ZLBLTy80tOty5
-----END PRIVATE KEY-----
diff --git a/jstests/libs/expired.pem.digest.sha1 b/jstests/libs/expired.pem.digest.sha1
index 3cbee5a7a0e..01f1bc5e8a1 100644
--- a/jstests/libs/expired.pem.digest.sha1
+++ b/jstests/libs/expired.pem.digest.sha1
@@ -1 +1 @@
-25F67C05DF95E97E6CCD4F0F6E70138E2A68CFD9 \ No newline at end of file
+7003003E0C38B744866C761E786028ED1D0B24E5 \ No newline at end of file
diff --git a/jstests/libs/expired.pem.digest.sha256 b/jstests/libs/expired.pem.digest.sha256
index 92ec2a6382f..42dc26da817 100644
--- a/jstests/libs/expired.pem.digest.sha256
+++ b/jstests/libs/expired.pem.digest.sha256
@@ -1 +1 @@
-79B72F323FAB7675F11690921DBB6CDCCBFAC528182D6FFBE0FC3666454854FB \ No newline at end of file
+C4CDAE7699B93927C7016C2AAC82F56C4E2715B3157D6AC5C7DB6078559B424B \ No newline at end of file
diff --git a/jstests/libs/intermediate-ca-B-leaf.pem b/jstests/libs/intermediate-ca-B-leaf.pem
new file mode 100644
index 00000000000..5de2495137c
--- /dev/null
+++ b/jstests/libs/intermediate-ca-B-leaf.pem
@@ -0,0 +1,55 @@
+# Autogenerated file, do not edit.
+# Generate using jstests/ssl/x509/mkcert.py --config jstests/ssl/x509/certs.yml intermediate-ca-B-leaf.pem
+#
+# First end-entity certificate signed by intermediate CA B
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIEUIFx6jANBgkqhkiG9w0BAQsFADB3MQswCQYDVQQGEwJV
+UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
+BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEaMBgGA1UEAwwRSW50ZXJt
+ZWRpYXRlIENBIEIwHhcNMjQwOTI0MDAxODUyWhcNMjYxMjI3MDAxODUyWjCBkjEL
+MAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMRYwFAYDVQQHDA1OZXcgWW9y
+ayBDaXR5MRAwDgYDVQQKDAdNb25nb0RCMQ8wDQYDVQQLDAZLZXJuZWwxNTAzBgNV
+BAMMLEVuZC1lbnRpdHkgY2VydGlmaWNhdGUgdmlhIEludGVybWVkaWF0ZSBDQSBC
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoSGzhf1k1g4iySsXa/ne
+UbFSK0YFeEmxyV/YNYAXGnuv+UNzrNES2Pl58eukPbZRVkyqUfn33aq6uuTVbmG8
+7hw4YhwujCpaRh37CznLaz8V4cg6VeNR44otA+O/nSIWoAaL3Jhv5g7cYrCuu9OD
+w6+UNpCaZOCi6FrghmoI9dKPmlAhy59aA7zac8I2qog/urf1MnfCC80UECcHaeh9
+Edltxqk2J2XzaN70g7Zh0HiH8Syju24NhTUzQP+l0i+3OVizcdoyAlkr5aSYTab8
+s9OIRCM9diRRcxAV4ny31PnW9iVPZMP5wJrR5SQUZMIj/sk6kGvPPBxAASVKVeKp
+CQIDAQABoz0wOzAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGgYDVR0R
+BBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBAQB1PXgnNJtG
+4E+c9YqomiUWuKnSAjCtPfaFeWMHUeRKltWOF4uTedpU5iLr9hAlCslLaZIbVIyb
+pGJzv4deCapAUdz45QF2k3ekABeMsU4CbLWlzKDQn7bcLCWgRIbqjGt1eQRTTYOA
+tZYkIZ3ntsk6uyn+VJu3sTOwQM/kAuHHbnBuUZsRxKCKUgpgq6qXHVmQJ3FJJFVa
+2VVpX2iycLD5/3RIICNsbzz0zHPhV3DCwTHlK/I0ZzrmO/2NLQD/jQBpm1QCtRyU
+akVGR6/OokY1CWZD+VrnWcK7Ua/LHbwbzlJFioXXoAcSGyXaY/Ep9MFx7psvLsOQ
+2UaDEdtbu/p5
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQChIbOF/WTWDiLJ
+Kxdr+d5RsVIrRgV4SbHJX9g1gBcae6/5Q3Os0RLY+Xnx66Q9tlFWTKpR+ffdqrq6
+5NVuYbzuHDhiHC6MKlpGHfsLOctrPxXhyDpV41Hjii0D47+dIhagBovcmG/mDtxi
+sK6704PDr5Q2kJpk4KLoWuCGagj10o+aUCHLn1oDvNpzwjaqiD+6t/Uyd8ILzRQQ
+Jwdp6H0R2W3GqTYnZfNo3vSDtmHQeIfxLKO7bg2FNTNA/6XSL7c5WLNx2jICWSvl
+pJhNpvyz04hEIz12JFFzEBXifLfU+db2JU9kw/nAmtHlJBRkwiP+yTqQa888HEAB
+JUpV4qkJAgMBAAECggEBAJUU9WDXXeCfG5g9AmKowQWcpoXbN1xf8tp6jzSQ2s9p
++RsLSY9vsZyG1kj62O8wLHlIXZ2TRb4WJMaeyspiK8ey3IgJwxd0aCnPu2JbitYj
+fD92XmLw++cnBRdANR1RWNWeuPDVKVMWFNpK1qB5xsPbQ6poiDEllhSdYHd8y+WD
+/2/djk+Iqc1QSV0ZkVa0ZQ8fO+GeZ+3X1oPcKmxTOYcgZQzl/kjW+s8yW3Aw/UgF
+941LpnvbhjOfLET02T+/8Fjh4fNVDx6IN9EVdjkOFTZmkHsZVbYeBo2UZnw56rid
+txXqomcS157gVw7Q1t6HgVn5g8q7Yws1jtfOhDs37cECgYEA1moqBA4LF+ElWFih
+CVxwHuZXmISnuIzKgiG59lZBhL2/NOUGZFOqtYwsWJJ5y+C+tEqKCKj/+PzH70AU
+oPO/KabI6LWUunatkR7HrWPuCN9I5zdOMZM/tSzPj/A9xBWEAv3r3Rar4OeENuZq
+BILRjM6XA/DBSqRGYRh3fdqT4V0CgYEAwGH/P5zSR/P5G4qXt9EEVj9OzZYTaY1U
+7fy8Ru3vZLQeFrZSveeRrr80+IJ8UEDxGhNYKneYcVE7bj0zx1PnupMcDIH6tjv6
+8yT49D3BENurRxUiHkd+b/IsPaoZooZCipx3bECHMIi8q6ZaqBOp94auwJyYk2SC
+5Jx1i7ohD50CgYBqW709x62PCdrZiRVQrG7dlQssl9kOvaASjyJM5JqZevonBdh2
+2d3bMo4o3XfXP0O58SOpihN3cgTHVDUnZeGUiqwsay48lHQigW8xPlmsQv5J23BJ
+PS6j83d+ggBRjQ6v4T8nq4BVDuLRzNgYJsBFpZDZnopzOSvELDvRzSP/7QKBgQCl
+RIpuL15GCcT6b/keJCVBomkkG8TZbFyFhhSIKmb5b/JZOI+kLIbuQ7xRsGby2pdE
++1FGSi9fSZVwgos0tVPg5/e0lwS2AJj4v85Oo65zuQJOskz5DhoEOVrgLnyPLh+D
+zB6blGOOwiiynNpMgXgF+GGvfddk53e6xN4GBwPX0QKBgHfEQV1Cu+g+3kUHqB3a
+dhYscphGea5fMlutWfRcPrbcEvyWHbgZMDu2ORSbvMC7oLeOzTQWh5LsTgLZSahZ
+bIj8DVH+JehZQ3LnjgPgaviCyPQ47uP0vrJsWAyDmB8z+htUkPbLUUrMB+5AMCTd
+BdJ9ZlwgWJzJZxnVbv3pUs09
+-----END PRIVATE KEY-----
diff --git a/jstests/libs/intermediate-ca-B-leaf.pem.digest.sha1 b/jstests/libs/intermediate-ca-B-leaf.pem.digest.sha1
new file mode 100644
index 00000000000..622d96b72b2
--- /dev/null
+++ b/jstests/libs/intermediate-ca-B-leaf.pem.digest.sha1
@@ -0,0 +1 @@
+399431186FBE5673C78AB28EBF74B0F378D4F973 \ No newline at end of file
diff --git a/jstests/libs/intermediate-ca-B-leaf.pem.digest.sha256 b/jstests/libs/intermediate-ca-B-leaf.pem.digest.sha256
new file mode 100644
index 00000000000..925da35f40f
--- /dev/null
+++ b/jstests/libs/intermediate-ca-B-leaf.pem.digest.sha256
@@ -0,0 +1 @@
+2A780CFD54A44D38DE416E46C91B609B9DA7435A2347B2DF62723A90EFBE143C \ No newline at end of file
diff --git a/jstests/libs/intermediate-ca-B.pem b/jstests/libs/intermediate-ca-B.pem
new file mode 100644
index 00000000000..eb35c9bce78
--- /dev/null
+++ b/jstests/libs/intermediate-ca-B.pem
@@ -0,0 +1,53 @@
+# Autogenerated file, do not edit.
+# Generate using jstests/ssl/x509/mkcert.py --config jstests/ssl/x509/certs.yml intermediate-ca-B.pem
+#
+# Secondary intermediate CA issued by the primary root CA.
+-----BEGIN CERTIFICATE-----
+MIIDeTCCAmGgAwIBAgIEED+pWDANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
+BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
+IFRlc3QgQ0EwHhcNMjQwOTI0MDAxODUxWhcNMjYxMjI3MDAxODUxWjB3MQswCQYD
+VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
+dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEaMBgGA1UEAwwR
+SW50ZXJtZWRpYXRlIENBIEIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQDdic72SasL8/GPCBYEanD/UrhC4st38jq2lAfEInHJb4Bkam4U2vmQcha7lI6y
+HyhNQbw7Id5GzpR6oVeg7eRRHG4WrLlBq3VMOKcNoyTEinSwZ9O3Ei530o2Te6Ff
+wqmAS1pge8f4Sp1BZxO3pW+qschdA6KTRkWQV71Qcmg/V5g/0ozk3EmmyPitnFmC
+saJGRcUsJQE92f6cYYaZN7/d1MSZ47w9l0revtD5ICYKF3fCbTm3WDDVRmKP3m44
+M/X5TP29ChfZyFvn4PHd+hYtbW7JECHMwcXLI7EtazzkyoS+hkp24NomnDZDpBY+
+lNDEu/wjXxnIcNYnqUDAyHVbAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAHb32m5NNURKVqv5fgl73+ZgVw95LrzK3GW617lZf1BtJRzR
+V3ksCM07va9ylu0lS8HlglNJMYlC0vCw8kVNolutL/l6IunyzIK418VViYlOluvY
+SE8f6dhRsIhMggbD/qkHqDc4Awu++6Ix+6LwC+34ttc7BUuG91Y3Kp0H4uzv4VIJ
+Rhbq8r5AOWWKFbtNqE4kqjXqIN/7pFvTlW8CeK9wGMG2ax/fX5GDtMcAQdQ1z0/n
+4GPxy+f4SM9vtkJlUDOm/YmJlYUvRVUd4pB3F4TlN2fzdcOJyT3cMCQEBLXTIVnP
+pQ+YtXGx+9SK1j3hmIPG4lAl9hmRT7esVY2sYPU=
+-----END CERTIFICATE-----
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDdic72SasL8/GP
+CBYEanD/UrhC4st38jq2lAfEInHJb4Bkam4U2vmQcha7lI6yHyhNQbw7Id5GzpR6
+oVeg7eRRHG4WrLlBq3VMOKcNoyTEinSwZ9O3Ei530o2Te6FfwqmAS1pge8f4Sp1B
+ZxO3pW+qschdA6KTRkWQV71Qcmg/V5g/0ozk3EmmyPitnFmCsaJGRcUsJQE92f6c
+YYaZN7/d1MSZ47w9l0revtD5ICYKF3fCbTm3WDDVRmKP3m44M/X5TP29ChfZyFvn
+4PHd+hYtbW7JECHMwcXLI7EtazzkyoS+hkp24NomnDZDpBY+lNDEu/wjXxnIcNYn
+qUDAyHVbAgMBAAECggEBALAXw0+XXQOiQwcbOU0HQoxgtyBLX8oW276WydmIO4QP
+QjIPOzMOn8LGPPWbbxV8mK9YKgOityj3OaSELMA5d/tVKtiRMKxXWmRcv8SiQi6L
+k5dI4Eurgw4xaeGqKqqQc+ULgGoi2d+th3QeN9kJAkrfB9GPeyGvgMnsRAn29pAp
+WGV8r6Ag/PQV7sEqpnXa5j0FGTlU/+og1OROSD+hp3bjKD6137TDZdx04WBrZ8x6
+QaK1v6SgS4SHMjytMr5TBKEuyTtSFxP9GEr8dEJ4VsqAdNFpujzM6SmvVqiV0vhS
+UpZ0zEModdMCJchBV+BkwH6Ef2L1RaVjmYhp98NDYGECgYEA+JM78lTCr3xVBhlz
+qE/GCuSn9/Z+1o2IE6n2p+s/2GJ7N5o1L3O70YD10pxGVSipua90nsuDIiP61PZ9
+orsmzWRx8Ax5XYvwupMf+6gJYSZyLU60MIO8+pqxC4I40NOPLf+LcggDzrvi+lYN
+4U4CsdowBr/ut/8l2EmX+OZF+EsCgYEA5CfVVEUTUkO3w/nfdhef4uKEOzqA2LA1
+TUBuUSN/vBOAwFvPNVDi/qrIkR8b2mKo0QsdvuCRqsQsHNdnc6DWon09kDFpVnhN
+B/mz/KEPGIcTegrEijmgXtOGqU5BbXoccDF7GtXLaYcydLNrrYrlX9AeIm97DYcP
+1rme5RSEbTECgYBM/+bI6UKpc30u94FhONzjEPOLFxsxQQRO+w5B89iCIfeDQMyK
+13HtsuHzDJ+oz4DL2TLp4abMU5LmlzhRyWF6rEuzDVonBStb0ClPHj1Rj8Q8jq24
+fYZzpqmDJCKPZYlruUYr25m6V283FqMUEMM67piD7r521p2Vgy6FVmeEQwKBgQDF
+/k9h7wPiawPJXUlv6PaGZT6NS6rO4LOQ064oWZ8a7u3XgJTj1sr2Z+zgC1gXf3Cy
+4Guy3p1qzQzfBosvS8+XeQn43Phl4sYueqKYRIieJ3JegYOn1HR4diYxPMkIoWSW
+dEo5snjwnjPKFH4IPzXonOnZxlbKGYBEPhdHAzQcsQKBgQCIHaqZ7VrSvgaeBlZT
+XBY6apYnFtBvWP9Iw/uYRn1WyXPl846huKDz6GfhNNQcsfLclYC0h5h94G6Fe+Hw
+UMtT6s5v+NxGP6PRj8SgfQTLQczcIZkh0qBJ6UrjxMHkj8kmVIaq+6VffIMm/hds
+BuBEtlHp6qkEDHWkVMXk4ZMI2Q==
+-----END PRIVATE KEY-----
diff --git a/jstests/libs/intermediate-ca-B.pem.digest.sha1 b/jstests/libs/intermediate-ca-B.pem.digest.sha1
new file mode 100644
index 00000000000..f8a7a9ceb51
--- /dev/null
+++ b/jstests/libs/intermediate-ca-B.pem.digest.sha1
@@ -0,0 +1 @@
+A829D6E7E82F9A3D22F55E117DD50AF5B27F6826 \ No newline at end of file
diff --git a/jstests/libs/intermediate-ca-B.pem.digest.sha256 b/jstests/libs/intermediate-ca-B.pem.digest.sha256
new file mode 100644
index 00000000000..e6223f17ce1
--- /dev/null
+++ b/jstests/libs/intermediate-ca-B.pem.digest.sha256
@@ -0,0 +1 @@
+EC0AC5E4827BB348A6799569FC39C83C1DC0A72D30C162BFA6A7E127D019B523 \ No newline at end of file
diff --git a/jstests/libs/intermediate-ca-chain.pem b/jstests/libs/intermediate-ca-chain.pem
index 924f905cb3f..9fbf1e8b675 100644
--- a/jstests/libs/intermediate-ca-chain.pem
+++ b/jstests/libs/intermediate-ca-chain.pem
@@ -5,45 +5,45 @@
# Certificate from ca.pem
-----BEGIN CERTIFICATE-----
-MIIDeTCCAmGgAwIBAgIEUuls7DANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDeTCCAmGgAwIBAgIEIGnWnzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTMzWhcNMjYwNDE4MTYxMTMzWjB0MQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ2WhcNMjYwOTA3MTYxNDQ2WjB0MQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwO
-S2VybmVsIFRlc3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDl
-0p4T7cqWDu/0AZ+5LTrt7U66WVm0Fm4yU8ZJgYpQ7BLuIGb664/BqpvitrKzogwh
-4O61sO1UtKOiD/KiyTjq8SzA1Go9WtdsIfDQkz6lU1cgy4HChOw/kLI6i012tg9E
-UzSoH+bvLxr18LtpOvyY6yLiT824AqN/Q/NjvRNrihh5HOcDkRR8+XzcWcg4fgKo
-8RvnEHxZ3jY7gpT5URfaisyOzNImWvB3hWjQseo7BpMIJLes7Sp2TSFtaHw0+Koe
-t2e/Ex9ls5X1fmN2Y5N9hUNN641eMMXUqIPdPq6mSeF7CCHWBETG+908TFBuQQJp
-ZJ8CmKeP7qJLxciseL7lAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
-hvcNAQELBQADggEBAHtFJmKTdyEGJlnl+zKNbOWK6+H8VglYQdWFojNXrWCnqiuK
-4NdEv8lTpEaUuV83Dz4neueFGiw9w0UIpspRPPahR5CVkVs1Oxy/LD3qAKPmxcJy
-nfj3eEYY7CSpc7TmNXHRFIWrv+40m7UJvfi+ns2MKL7IppY4A1bAwjoozvAI4rD+
-CkU61xGLYAD8YjzhNEu88LrIkV0JluBmsMen8tUce3rzVrNRouWpcc29am6JWyB6
-FLsPhUfHDZnxKl/SosXd2JvEDj27NvNtAEydpPQB4084KjDqfVzyJgMXLflkXBDS
-pdhzraLljLpRKZt6FvfDBDw4DzsW1abYUEUGJNg=
+S2VybmVsIFRlc3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDU
+tM92EQ+UJAvDZHjcHGCM5M2E/wHRXWV6z3pXNT+cZliEsUbCBqwA+rs3KYyT0NxM
+2bxDo7/yplFGEb8Kz3gZJGiXcp0WEqZKN8yfTd6p2OTzSlQ/Yw4wcsfnhDX/i2HK
+NQVh258vf1e4t8spr3udsPnfQo0ap/28F3Jq2QxGmKiTPQ2xdyWvk/K5zABHX4mu
+3c29FdViZpcYoKCdYhIsO7IWPBvvPQEqRDPRU/UDweYbJFyrlWNWMCislj0EfGIn
+LBhtXxeZHIXh9fWO8DfMzER+r1fIhxX7lvzdpyT+t3NcOGSWYRKcG8q2+iUnCK4H
+2a2Vg5YKQYGGWmkEQ++XAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAMjiHKAOjasqJPeqSaibtcpClQ2qK6xVMvAdX2YofNzO9/WD
+T1vqF06nuUlUTN+onacW9bT/cABzX2WmBlXH3N0kkr3bQ3dZy6KJpZnLhat3TLYd
+pYWbbVvHUJ31DGnZXNpWzvH/7KSK/IUixfjlYXaKocRNacXtRlidKN1IgTjaMNvL
+gTGaeiaylRYQ0wwirxVJWUzCkRahVlu8nHipl4oWoRfzCxeKGLpXWPBBVJPmupxJ
+qeU0X4fppEYMfXBZLoA5XFPeGcA+epZxNCOEP9f+0CxLmJibe/IUWRcNPS2WWznT
+MV/vxlcqKt0YqxFFk8LzbYMfKa4RXKvk/xpy87g=
-----END CERTIFICATE-----
# Certificate from intermediate-ca.pem
-----BEGIN CERTIFICATE-----
-MIIDdzCCAl+gAwIBAgIEPxCEvzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDdzCCAl+gAwIBAgIEMRP94zANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTQ2WhcNMjYwNDE4MTYxMTQ2WjB1MQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ5WhcNMjYwOTA3MTYxNDQ5WjB1MQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEYMBYGA1UEAwwP
SW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
-mnjixoApuIjaBybO3Fy67HEdqhIQTSUiLdcte7A+Lip/nZ7H+r2eJdQntWpuCAA2
-ExSsjn3IXwHayp/3ekUX8f4KX1CwWx3fP3UpyPfirea+AOhJIPuPWGTGzZEcaJm1
-JJHnuKCMWq3xQjKszi6IqH/725jWFRG5uz4yFdsnIFkG6Q/MqV6L80bndJX4VgfM
-s1Aw1ax5tLjxsuk5fAyw3WjPepJ1f6pOGpaWmgp+z50PLOIXufDQcPxFxv0WAPwv
-W5XkJXCDDhh2AktF9eaVjMvV2lPqHmCQiYMsPj3uNT28ceiGa+mQBHr885g8zWC8
-v/MtsdKWce+sMyDjCxFnmwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3
-DQEBCwUAA4IBAQBjv9XjW85ID6T8L8VxNe31U7+dlVZfLsaFVvUBWioTXl3MbTOx
-89/E+GOzsY+0q8OjPiDoGoEXuQzRrPTkSk/Fe36RBEStUMQSQa01Oq3dxVXzIQW6
-ZUkD+C2aGYxmq60evvkgewvTxs+iROv5Rjs2IPkgX2XXNzeGRgDUNZbVY55dBljR
-5ctsmGsmgjdakOKoSdxhwuW0EP44c0JzaBqX+kbPIi2RUMH34ZCyfWVUCgkLrEf4
-TM0fKYEwt/cgcBG7dA80HzLlD/WYvbuVdY4wUAM5UsrfRjVFVQJz+q6CE4COkB6i
-BrhBbDMi1k+WXyR9lVyrDVaFsUqdzXIXHalC
+4iGdS94QMpwbVEkqXD7LhyfKMr1qMcSVgSNAOw5XCvgF/i0/TugIcOgdGanq6ksQ
+1vO87jraCegLuOAz3HnzdAw6grcsAohk3RpZcmyDvpsyW9t80UwoGE6WeZ9+//BW
+uaXuUuokuoTEFQBxU86igIgZ1we3sFfuD47pettQr8NUz911Oqh4xXztXLmD+8Bn
+FHA2kwlSR7fJRJDOa/jG60rKSYbUvTCH9qK7GinXiot3qiX1XgO2CCesuYDG1XXH
+72ENb6bg0kGS1pKMJQhxArwV5xwykaJ3UUmggCPMwURtc96RD+9S5yhIjKPB8PRs
+lU8o4Qz4//3CLqMFQQqRMQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3
+DQEBCwUAA4IBAQArkFpwgHPoKuWHeuDnSqsM68vtORDN95H/4NXaRONxxBz/1owW
+ptJ74jPMlXLYy3tA0q5cLZuJzFQ9c643S3kyDeKsFYqzzDrgRSpJPcKE5Rg6DWXu
+7zBHWbqcvfYoBrJCUDTN30DMkEGkHpdVd0RQSZ+/KjyTEu4CvEei0taAZ7vWj3Yn
+5KwMKyvLNxjpil8SF4nofBC3iIxpD3C9uSSzLrm2ASTYWQLWGX2KUZiKF5Y3KYim
+ZYdBBVDNtHJaKJbomwcXRjcUA68J/4XPeFRH5yyE2/j8xII3W2pB0iPrS3DgMoX+
+0GMp3Vx+WBnnDC1dAintOkSJtW8hKlvYnfJr
-----END CERTIFICATE-----
diff --git a/jstests/libs/intermediate-ca-chain.pem.digest.sha1 b/jstests/libs/intermediate-ca-chain.pem.digest.sha1
index e771ea3472f..094d60417bb 100644
--- a/jstests/libs/intermediate-ca-chain.pem.digest.sha1
+++ b/jstests/libs/intermediate-ca-chain.pem.digest.sha1
@@ -1 +1 @@
-F2FE3C922B6A5408AA06C1A0EBBEAF0363C52046 \ No newline at end of file
+13D573B8FF4C9E4AAEF37A360BA2D52AAD8FAE48 \ No newline at end of file
diff --git a/jstests/libs/intermediate-ca-chain.pem.digest.sha256 b/jstests/libs/intermediate-ca-chain.pem.digest.sha256
index 6537d4ba893..7f833323449 100644
--- a/jstests/libs/intermediate-ca-chain.pem.digest.sha256
+++ b/jstests/libs/intermediate-ca-chain.pem.digest.sha256
@@ -1 +1 @@
-6796FD7146BB58523E125BCA35AB2D882A6A2699C82BA63496636386703A998C \ No newline at end of file
+ABFD56D37533C4F7EE311891B1749818EDB90DEBFC957968A37066688598C607 \ No newline at end of file
diff --git a/jstests/libs/intermediate-ca.pem b/jstests/libs/intermediate-ca.pem
index c3f63dbd3f3..6869eebe184 100644
--- a/jstests/libs/intermediate-ca.pem
+++ b/jstests/libs/intermediate-ca.pem
@@ -3,51 +3,51 @@
#
# CA issues by the primary root CA, which then issues its own server cert.
-----BEGIN CERTIFICATE-----
-MIIDdzCCAl+gAwIBAgIEPxCEvzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDdzCCAl+gAwIBAgIEMRP94zANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTQ2WhcNMjYwNDE4MTYxMTQ2WjB1MQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ5WhcNMjYwOTA3MTYxNDQ5WjB1MQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEYMBYGA1UEAwwP
SW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
-mnjixoApuIjaBybO3Fy67HEdqhIQTSUiLdcte7A+Lip/nZ7H+r2eJdQntWpuCAA2
-ExSsjn3IXwHayp/3ekUX8f4KX1CwWx3fP3UpyPfirea+AOhJIPuPWGTGzZEcaJm1
-JJHnuKCMWq3xQjKszi6IqH/725jWFRG5uz4yFdsnIFkG6Q/MqV6L80bndJX4VgfM
-s1Aw1ax5tLjxsuk5fAyw3WjPepJ1f6pOGpaWmgp+z50PLOIXufDQcPxFxv0WAPwv
-W5XkJXCDDhh2AktF9eaVjMvV2lPqHmCQiYMsPj3uNT28ceiGa+mQBHr885g8zWC8
-v/MtsdKWce+sMyDjCxFnmwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3
-DQEBCwUAA4IBAQBjv9XjW85ID6T8L8VxNe31U7+dlVZfLsaFVvUBWioTXl3MbTOx
-89/E+GOzsY+0q8OjPiDoGoEXuQzRrPTkSk/Fe36RBEStUMQSQa01Oq3dxVXzIQW6
-ZUkD+C2aGYxmq60evvkgewvTxs+iROv5Rjs2IPkgX2XXNzeGRgDUNZbVY55dBljR
-5ctsmGsmgjdakOKoSdxhwuW0EP44c0JzaBqX+kbPIi2RUMH34ZCyfWVUCgkLrEf4
-TM0fKYEwt/cgcBG7dA80HzLlD/WYvbuVdY4wUAM5UsrfRjVFVQJz+q6CE4COkB6i
-BrhBbDMi1k+WXyR9lVyrDVaFsUqdzXIXHalC
+4iGdS94QMpwbVEkqXD7LhyfKMr1qMcSVgSNAOw5XCvgF/i0/TugIcOgdGanq6ksQ
+1vO87jraCegLuOAz3HnzdAw6grcsAohk3RpZcmyDvpsyW9t80UwoGE6WeZ9+//BW
+uaXuUuokuoTEFQBxU86igIgZ1we3sFfuD47pettQr8NUz911Oqh4xXztXLmD+8Bn
+FHA2kwlSR7fJRJDOa/jG60rKSYbUvTCH9qK7GinXiot3qiX1XgO2CCesuYDG1XXH
+72ENb6bg0kGS1pKMJQhxArwV5xwykaJ3UUmggCPMwURtc96RD+9S5yhIjKPB8PRs
+lU8o4Qz4//3CLqMFQQqRMQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3
+DQEBCwUAA4IBAQArkFpwgHPoKuWHeuDnSqsM68vtORDN95H/4NXaRONxxBz/1owW
+ptJ74jPMlXLYy3tA0q5cLZuJzFQ9c643S3kyDeKsFYqzzDrgRSpJPcKE5Rg6DWXu
+7zBHWbqcvfYoBrJCUDTN30DMkEGkHpdVd0RQSZ+/KjyTEu4CvEei0taAZ7vWj3Yn
+5KwMKyvLNxjpil8SF4nofBC3iIxpD3C9uSSzLrm2ASTYWQLWGX2KUZiKF5Y3KYim
+ZYdBBVDNtHJaKJbomwcXRjcUA68J/4XPeFRH5yyE2/j8xII3W2pB0iPrS3DgMoX+
+0GMp3Vx+WBnnDC1dAintOkSJtW8hKlvYnfJr
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCaeOLGgCm4iNoH
-Js7cXLrscR2qEhBNJSIt1y17sD4uKn+dnsf6vZ4l1Ce1am4IADYTFKyOfchfAdrK
-n/d6RRfx/gpfULBbHd8/dSnI9+Kt5r4A6Ekg+49YZMbNkRxombUkkee4oIxarfFC
-MqzOLoiof/vbmNYVEbm7PjIV2ycgWQbpD8ypXovzRud0lfhWB8yzUDDVrHm0uPGy
-6Tl8DLDdaM96knV/qk4alpaaCn7PnQ8s4he58NBw/EXG/RYA/C9bleQlcIMOGHYC
-S0X15pWMy9XaU+oeYJCJgyw+Pe41Pbxx6IZr6ZAEevzzmDzNYLy/8y2x0pZx76wz
-IOMLEWebAgMBAAECggEAKajBbAxDdC+AMV6PelGN3ddRyzyM5elGUvuNmiZ5VoUC
-nrUkNKSvwn75aI03+HNqIfI46ULV531+Dpheqzx4DTzYekUuEpy3SQtlhfwIR6ML
-if4bPshpK8sd7HGeqj0N47tvtVSjFY+EmbhF72MQWvUNLPeGgO8jWnKXGlrcrfW5
-LFngl3JI0CPvgxeTSuSZSFAZDDGO7a13YhUFeI5v4gUWCAvG2s1qP8NrFDqWjRxF
-5WR/BS1CfsY3IgnXKXHyFzzKR3tJ18dxMqrbOgdlKtL5+HtlX5M17hfDQx2mgo5i
-jMcIX3mhIfSt6fcA63SQXXEPaMA0FNwVsV91QUdj5QKBgQDQe9dItdwgGzVdeHqC
-s+WHpXqrZDcHgFI77QeGYsw9Cl1Ktbx93LZQeRDH1UcspkG8TAq4O4n1wZE0du7A
-inVd93hbWgRPI+/WuG9SzfFYqiQ9RRzpGqm7pWdFg6XTqq5w/YjHlxYQ/jL+uY7o
-xEeKe5d33/TSMW08HoTyDdAgtwKBgQC9rbI5/ZAxIjWQ7Bu28zXfGfddkGrG2pYo
-wwtMG6Z1OQVkHqXD+knfrNbxYjIp/oAttaaxbZTll18a5cWQBobER7/5Sf3K7sDW
-H7d+qWpca+HyyJIAsGSXLyfhu84KckV3r9Kuo1G+5CFdobU4c3o6bcMi7KGfpk8V
-YaQQq39EPQKBgGZDyPdWlZJ+JjAiT93bBoUCK+j0cHXSgQP6Ic3OmqZ6dgaWnM4U
-PK2+pPeQ66fAKdCGcF+sfOC6wVI94KE7iZS9NiGBR0nWs+fccmbotDEszDfttd+1
-/3oXCVA04luwhn7QLo7Q0rclKbh/JtWQqhMIyuS3S2zrZ8ysn8Pn+KaDAoGBALE/
-cX8TXf0sFJZarQNnfv3+y9OZMs6kURHCQfpbFFASeuE2an0alJH6d9mVg38OnkUY
-rK680hlCPNNryBRwpNsimVihNhK+zWDKvrQUKJo5DinMF/Og4j8NB92/nCjS4+uW
-V/BuGeOiVzOh+zDHaH7VNzaZnecMiHZYifIx8HmZAoGAC9qR/k676ABE15nattV6
-uclf3r5q7N4oCgAZG8R6XqjzSAkpe+zgXHd/rmb20n076YU/kiQxrA3Aqjww5VG0
-eWQpxYIu+TnrcNcaQdiPjR0Kol/McNF/7qq/VIIWGYO21E6bDmc8/JSP384Tk3Nn
-EwuZiLI1KdOg5PkSKAGCwe4=
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDiIZ1L3hAynBtU
+SSpcPsuHJ8oyvWoxxJWBI0A7DlcK+AX+LT9O6Ahw6B0ZqerqSxDW87zuOtoJ6Au4
+4DPcefN0DDqCtywCiGTdGllybIO+mzJb23zRTCgYTpZ5n37/8Fa5pe5S6iS6hMQV
+AHFTzqKAiBnXB7ewV+4Pjul621Cvw1TP3XU6qHjFfO1cuYP7wGcUcDaTCVJHt8lE
+kM5r+MbrSspJhtS9MIf2orsaKdeKi3eqJfVeA7YIJ6y5gMbVdcfvYQ1vpuDSQZLW
+kowlCHECvBXnHDKRondRSaCAI8zBRG1z3pEP71LnKEiMo8Hw9GyVTyjhDPj//cIu
+owVBCpExAgMBAAECggEAJjo2hCfTJysat6HyxktbTsrcNL2uoSExgPY7moAvGMya
+/sAZbrZtDuE+YiNGcjskaqIjs0ZBq+ENckB8o+39yQV0MrrSds8l9fbJXj2X+/Xy
+inLNY/hy4sEOURs0dgHkN1gktOGeOeXN3BsKDXfmIsJfU+mbFPWYagrnz3wZ5MxY
+OpoWdSXCYX4gZOtLIwrlfvHIL/mMAosy03e07kqpIyGhD+aR9onmt3V3/SN/WxrM
+iDiblmbFdTMnuPJjt1uHB/ckwZlOb0rGLg7WnN50eA4wp5AlL4NB8PBhZLqtI9M4
+WvK0S1qIPF6mVNH7C2J0QgSPpOQVoM9GHGmUd7xqEQKBgQD4oGO5iZCI1+msyZdB
+rzi6DUruaPWAkxK6bSWJHNAlk4UM4vqobHWMx9ACxXKwDx+tD2yP+g8vzBszuLRZ
+3I3gZMndYYDk249yo4HsacfO542F5I/igfx91DImPQoSyYF3UZeyObPW6MGeURAk
+dTn3VJfd9WTm29HuMxwtr4TKLQKBgQDo1nASusUt/KzhWcRUIS5PPb2TXARuLsJf
+Nu4dfwufD2JgUHFfVSWc8fShZRwqZxtLuX/Ll23E1Nzf30Scn9LYXzcR6CjNb5Xs
+ssaTB4yrecn2WwdQ4LVOlhviH+JXrt/dJs3sia8BLvlgdwvXxfV7IlWyi0Llu4Xa
+mSsWexyZlQKBgQChdYdNtkhmldDqpP/VaDUunfNLYF4OYXSIHNmDcXK69FIzTDP7
+rHOqORictB0GuMuZV6ro1TuHjsUbkZeNw+1fDBUL74YFGZDOoeB95zQa6cS+bvAB
+6OhPzr3Cl2EzUikBk7svwslHh2A1r+8LvhUmyYjWW8ZrJdXvGsHx6UoTAQKBgQDl
+X6rUqK3rGcptzfL9Nhra8WW6r6GlsebFyeVVpXybW5p8a4LkeYsuS6XFAUh39U8M
+kFd3B1yZ1WEqIlcDPOeHRHWJ7H2VtGGr5op8+aj4nGf7i71vTY8PNg2N+/8Mhjf/
+M2UVqqV+svn0sBI4pMmqXi6yT0K98rhwmwe5g9qu6QKBgE+Ej2TxeXAtiayGRsLw
+Vyl2WN//RLsrfjzNz+6pY5hwUj+gYO3I1f3CoQ02khk78iNCS9nM1Dtv20jlQ2yi
+Pu5f+Um8zRC/4Ugt7Bl46FPplu74Cd7FPHpvzFgOOAjAeAIK6OUkhoB6FDkGU51O
+D1GN3r2NBj2XKQL426wVUYIp
-----END PRIVATE KEY-----
diff --git a/jstests/libs/intermediate-ca.pem.digest.sha1 b/jstests/libs/intermediate-ca.pem.digest.sha1
index 2e648dba805..635e1982b7f 100644
--- a/jstests/libs/intermediate-ca.pem.digest.sha1
+++ b/jstests/libs/intermediate-ca.pem.digest.sha1
@@ -1 +1 @@
-0671E7953AC9FF9425FB84E961351F2E45E7657C \ No newline at end of file
+523148EE3FA4607CE0612E1039A3E92373D84467 \ No newline at end of file
diff --git a/jstests/libs/intermediate-ca.pem.digest.sha256 b/jstests/libs/intermediate-ca.pem.digest.sha256
index ddad4d781d5..f6f3da914f0 100644
--- a/jstests/libs/intermediate-ca.pem.digest.sha256
+++ b/jstests/libs/intermediate-ca.pem.digest.sha256
@@ -1 +1 @@
-22ECC6414618C12F58256D4A26F9D2F951970B9F40AA0B5FD622EFF9A5508F2F \ No newline at end of file
+A3CD90260965024596C187422E78AD59C4BEE8F4185479FCE1D19B546EA7244A \ No newline at end of file
diff --git a/jstests/libs/legacyThreadSupport.js b/jstests/libs/legacyThreadSupport.js
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/jstests/libs/legacyThreadSupport.js
diff --git a/jstests/libs/localhostnameCN.pem b/jstests/libs/localhostnameCN.pem
index 475e1642333..89042adb7a5 100644
--- a/jstests/libs/localhostnameCN.pem
+++ b/jstests/libs/localhostnameCN.pem
@@ -3,53 +3,53 @@
#
# Server certificate with IP localhost in CN, includes a SAN.
-----BEGIN CERTIFICATE-----
-MIIDyzCCArOgAwIBAgIENm1nbDANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDyzCCArOgAwIBAgIEeHfK9zANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTM3WhcNMjYwNDE4MTYxMTM3WjBvMQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ3WhcNMjYwOTA3MTYxNDQ3WjBvMQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDESMBAGA1UEAwwJ
-MTI3LjAuMC4xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3dq+1hHB
-5sV/c67ztetqc83Ii3EzD+lrcc6d7TSkZhEkV8MuAQfJoaoY9cyOZjPI9sS52YW7
-rtbiGCPKz59wd3NfmBB0rftcpUQkUlfqqQYBGY7Yr2QR9lrovN/2dANYSVSE1bvh
-vKByLEAodMB3hUrTVeKTLedQl8i03S9c8Lm7907L6sCEwhQutH4f6cGEmB1AaO/u
-/vJYU4vJvkuPZFS/zA6GxyBsK5GobfeUKCUcf+npLITKpg1c95kktX88eLZgZUKS
-orj0JWoapjTvAydztyuX7G30d0IQ888ci1Ca+pa8oGIrBfXU4Qiix/IFlEuRiXox
-7m+nzYTsKIfhEwIDAQABo2owaDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDATBgNV
-HSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUPCXfvh96QSGuHqnssQHmj73tjbIw
-GgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBAQCI
-IPnk1PO0vGikIQLprBGfuSuE/yFl1nTvcVVCtfcoYRKXxuO32QdFuN9/xH93W/Lr
-i6ucf+ZIJGafGxgvYy9eR3co5YhrROXz8/Q7Yw/a/vUuhWmB6MNomFwFm9h+Cc1M
-8PDGdM5zgBuz1VAVBBtFa4coYZpGWGQLaGmYhobSh71Hkbau5xUx1zZtNnTMwsM7
-0G9s6FQgAVgFO4apnsSbQZwoovtfUSAKJKLFBHQBVhZ0eHxzxnCmcA9hfwu8uUU+
-rOa1hMyJei5HdbYPXS6jyEBCwrUQ0UwAHmSUsZOOF5OIiG8R3B/ImhJjcfHNbUwo
-p0uaUNRn/Mc9QeTWS0Hv
+MTI3LjAuMC4xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz/5ooffH
+DwTGrJQgEPCuhev8qwMHSMt3IjvsmQc0uFJDUEtdYhL3oObHOX5MlnxE2jFmVCxJ
+vy2JYfxYEEEMJ/QJn67RvWsmUY+7Oiph4MNsuQchrGDSzC3NvpM7kOTPt5hyOI0i
+7qfQk/TQkGMYwQkACyEoBCA/4E5vilTyvAV6Ch9brThTNVB/AcGhDt78disCH4O0
+g/9PM8RadzTwn+0LT/8jZVEMSoyIbXbO09rlJ6ARe6o6ffZM8vlW5eEgRBLINcJ4
++++4pTSIBhwfXXeKfkcJgjgqbCc7b4vg8N/3RdWGJbQAXYPA2V5T4NGGUcnyPC+l
+kviQ8hPMnZKDZwIDAQABo2owaDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDATBgNV
+HSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQU6TmKi4vi/ePI7hbd+UjlwfHVVtww
+GgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBAQAd
+fyDI+zcrgGEWiRjDxwn2acYDD1xI0ABIuF4v1yFxebWiS4Lv5g8R8FOc7ELjiUkZ
+6fsgyVBBMuPOxyvThyPF334sf+UKPGhtvfMcSLkC062uAgNe5f3xk0eR1mFrfI+y
+CYwQblujac1Zdx5dZB7LknwD6Bcr5qwhAHrQzu71KZZlSkrPd66Q5htZZe3vhes/
+XxoDS3kJzrN1Sy6Uh3xKUgoLFuG7vuZB5Xhxz5UaFhfOTwURvOBuSvn924KYsxA+
+VVFucneLy7cdvCzKo0mYAsfsdnkCNiI4ejqv6Kx5AZOYMpUHkKvdu0eAcPpGZE2g
+yg0XcRFxZu0yUKmKOQEv
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDd2r7WEcHmxX9z
-rvO162pzzciLcTMP6Wtxzp3tNKRmESRXwy4BB8mhqhj1zI5mM8j2xLnZhbuu1uIY
-I8rPn3B3c1+YEHSt+1ylRCRSV+qpBgEZjtivZBH2Wui83/Z0A1hJVITVu+G8oHIs
-QCh0wHeFStNV4pMt51CXyLTdL1zwubv3TsvqwITCFC60fh/pwYSYHUBo7+7+8lhT
-i8m+S49kVL/MDobHIGwrkaht95QoJRx/6ekshMqmDVz3mSS1fzx4tmBlQpKiuPQl
-ahqmNO8DJ3O3K5fsbfR3QhDzzxyLUJr6lrygYisF9dThCKLH8gWUS5GJejHub6fN
-hOwoh+ETAgMBAAECggEAUQK+arbjQhxeFOUOsyA6p/y9vUVhqu7GQDF9c4+kdGzQ
-A4gO9Wtdkj3ljWPbn7BLMujVIHv387kdqEjxlu0WiVfE0Wc45AsEYojGZpcZ5gx+
-PFHwB+OXt4isscNqYCSUiXpmYxGPNWy1JDltTGy3eCHBl/v7WGi+Ah7VBGt2GaRa
-a3Wr6y2lv2piD/5ebtPka4CVSADEo0tt74qxoEjKB/3JELtV/0fpN6FBPbyclaN6
-S6N0a5isXXLNjRIyhmp53GF9fBJIyWHVGSoPppmP2Gh3O52feNOxSfvlalglXD++
-eZ2el30+rhwIU6j/CJ9mb5wM5jsDO8M3YSAmcuALyQKBgQDeZqtpewgFRRqCn8Pb
-ri1FeM49Sd70dAsgkjFvdYi41TLW9vK8E10yVnC7gwAfJZpm7WRRKCIPKAuPPph7
-zTIolO33Z3RjxLH0CWbtQs8quXcr+rLQdilZ/XTlfptYMzUDORp4wFIKbnuo6n6R
-Mh9G7PLNKWNWwSBhRBiGe3xiNwKBgQD/Xu/gsx587kqq/xp++F0cAlcJnn5U4bOL
-+fT7a3LJM0wLyT2m7GVO02a6PoaYiIw6oCnqkY788A+oIh4+E4+6+W5A8emPLgQb
-Y0xe/DJ9PyB9Q+cXC8X8zJuzWvSXVf0TdPn34+py/Xrv8W7miD5Zd3h4A58oYffg
-RsiU1zK6BQKBgCxWGWvwy/uI+Cz8PqZnxbyoxaywMlNXYvR+UH6g1r3KOtVh66gU
-0Cp90wF+ryKGc457WtlW/9s3p35KA0oC8THn5rzAkhJlnvhAe5VnETe6O4i39Lfc
-Jog7H/e0UrG1m6bl1mImLPTJa7uT6+F0NYoFKK4/xv7/hz38vkrpCTXnAoGBAP30
-1ayptIodF5hRtXHLYBz4nsHsIkobYkizvNNDGZXJM7kM2gjkUiM/zIsunv+V2455
-tPWW55HW0lssAtNM9MTGRMTFTrWa1269IzfaqgMwAglQu8GJbc1nVPfaXh8Z3mG5
-FNVWjNLqDZYMjXMozoh+bQk84MxyEOWyvsp17/ZZAoGAYHv4bYcND8JstCmUtSff
-ouHowdzUqCHHJVzah7LHlQ2LGHG2jTnA0x/3/Dj8O+RTt0UddX5EXSf1R71pUDZN
-CI8ECdwZT2XDjtPvcrihJs6pZW5BxzBX4uXh/fvQiniCGr4E2ho1QMUS1fsFZ1Fr
-KoACSYc+nGQcWt6VOKlftO0=
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDP/mih98cPBMas
+lCAQ8K6F6/yrAwdIy3ciO+yZBzS4UkNQS11iEveg5sc5fkyWfETaMWZULEm/LYlh
+/FgQQQwn9AmfrtG9ayZRj7s6KmHgw2y5ByGsYNLMLc2+kzuQ5M+3mHI4jSLup9CT
+9NCQYxjBCQALISgEID/gTm+KVPK8BXoKH1utOFM1UH8BwaEO3vx2KwIfg7SD/08z
+xFp3NPCf7QtP/yNlUQxKjIhtds7T2uUnoBF7qjp99kzy+Vbl4SBEEsg1wnj777il
+NIgGHB9dd4p+RwmCOCpsJztvi+Dw3/dF1YYltABdg8DZXlPg0YZRyfI8L6WS+JDy
+E8ydkoNnAgMBAAECggEAGsKw06X9hoEmzq2AMq3ExpZGO/p3xXXoLg9nsYirz8tF
+vd70dNnb4mfO2ibV08bJVQlmEQ5hrqc9Nc4xxmWYGsvbMSBc+/H9TCEiBanOTgzW
+wDearYMHnB2IiyyGTW4jC4whpgUCqZIN0/t7mhgl5zAxQT1S2LUNgt6Um0eys14F
+e8L6zqautFgPfSJcJWIPfGTgcnzxb7Vw/ccEFQxicr5ssMz2FpGfFSExhX+xMJ6S
+amomfe4Wye2gdKENqItqsnXQUOQ3JnDOJmMEir3WejE5sdUuZt6SlCQYwCZUBjKQ
+IN9xIYFsXC/sqElLZiDD3OtkwF+ms0B8ULRcGvR7AQKBgQD4XBdC+oOxwKK00BT/
+8M++1DHGfXyLKTZV7qBzeSRycWORzOOQnmohAQnmUQQG5xCIyiOMvsABe/jivnxb
+CIlltwv7+zw7bbesXYp0ZXN4+gD7+Woj7ZQO2ccOS1fbpTGFy7QpWocwyTwZ86+W
+ueqdCj7Y7ZUjUAdYx9ftGCu/vwKBgQDWZGxzfL10biiSqKGpI/F2B13iByWlU8aG
+C5OSlpThThXhAR1OqYWYBAl5ltM+7cTs2fKIYPcx9q7kEH7bgzMymaQaO9gXV5JC
+9BOkdGGw1OYqW5tPmRrVieo6nTACAC/zjwgKq4XFc1xFfoTZ1HAUlUn0hGPjU7na
+3H2MebmmWQKBgHrKfS2+UfJGPauL3XYVB4FfxCRQ0oyzGYwu6OFumZiDeykQ1cog
+qHQc4Vof4A/RmhknZ6AkhyW0t37TkwQnGldRwvkYY9U2D8OGk/esWQUNBgOOcu3E
+fplBDuuAULXl3LA74J05hvGV7MMf+kZZMSfnct8px7ynypoYZCdy9d5dAoGBAIRH
+afLHoE1aOoZirXwixTTBztdK+ZtMWU0Tj3X+mtV4zF8LxP1n8xmcRAxVVvmY0swg
+nVgwG9UkEzx8QQlHpisuSOY2zll4mrHcztHFTRFCCtFPvEAcg0YF1hNcMObLHsr0
+EU4kDmGJkAEA0w9j19ObWQoZNVhprF6xdHVcFYPhAoGAEmQ1qOPYk49TDfJl+elI
+e7xMgxxRKE0VRTlTAPS0NFvt2pNdS51/9gerjO4ZSS3cE3Un8UuPEY6hIuY21rsr
+mr3fm4Ug0RtzUJNXgZzEQO5RQt3SOIjqdXLGTvLrsk4kgyTHyjU5t22OyhX8wK+Y
+t1IHUbzVM5HiT4ddV9Tjugw=
-----END PRIVATE KEY-----
diff --git a/jstests/libs/localhostnameCN.pem.digest.sha1 b/jstests/libs/localhostnameCN.pem.digest.sha1
index 095d3a87f11..20d26279646 100644
--- a/jstests/libs/localhostnameCN.pem.digest.sha1
+++ b/jstests/libs/localhostnameCN.pem.digest.sha1
@@ -1 +1 @@
-93BB4BE2B37B48CFEE05AD9AC08ED40479545566 \ No newline at end of file
+E44F27C25B5F4DC3799B470BED1758BA4BF56512 \ No newline at end of file
diff --git a/jstests/libs/localhostnameCN.pem.digest.sha256 b/jstests/libs/localhostnameCN.pem.digest.sha256
index f73cce5fe34..0e14a08b92e 100644
--- a/jstests/libs/localhostnameCN.pem.digest.sha256
+++ b/jstests/libs/localhostnameCN.pem.digest.sha256
@@ -1 +1 @@
-41751A42749C133AF5AEC3E7C5541EC463FCCA90CC4F3E9950C1BCEDBE62F8CB \ No newline at end of file
+EFD929DC05EA56DE6221E03DAE94061C19EEF80AD2B0ACEA158B09EBB62F9F7F \ No newline at end of file
diff --git a/jstests/libs/localhostnameSAN.pem b/jstests/libs/localhostnameSAN.pem
index f80decd9de9..bf31a299ba8 100644
--- a/jstests/libs/localhostnameSAN.pem
+++ b/jstests/libs/localhostnameSAN.pem
@@ -3,54 +3,54 @@
#
# Server certificate with a selection of SANs
-----BEGIN CERTIFICATE-----
-MIID8DCCAtigAwIBAgIEXbro+jANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIID8DCCAtigAwIBAgIEf+dqwzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTM3WhcNMjYwNDE4MTYxMTM3WjB5MQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ3WhcNMjYwOTA3MTYxNDQ3WjB5MQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEcMBoGA1UEAwwT
c2FudGVzdGhvc3RuYW1lLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBAJ2vfhP1jO205Y/PRJKMFm1PVqk/HIe0cc33hovA9w9XCZge1xHfHM3JdnCJ
-FyzDFlknNjzg/GUsAHZo9T0eabsRUUPgZL66ZBwWZvwS2WUe0vkuPb7ghGBLWili
-4SNTEHy3GnyWsQPGrsxsDyA7ti9F6aaI9zuH/IH9gPtwuOVn1YS3GdEBSchDSwBD
-PfWKlAmml5IdnFDqB1Av0GSh1RO8W5RWj217fUm8B/smkF/zwSsFQh2ckk8N71su
-WGNbLFzq0Pvs8bZJiYz7UAy29ZxVVs/QLcChQWtdB02H0Z+K7hE2lr3tx7uInQvn
-8/te2SSf1aglOl7RKM4AJtETq50CAwEAAaOBhDCBgTAJBgNVHRMEAjAAMAsGA1Ud
-DwQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUNNSGBjzjvI59
-FnmGAFvwfQxIHOEwMwYDVR0RBCwwKoINKi5leGFtcGxlLmNvbYIJbG9jYWxob3N0
-gghtb3JlZnVuIYcEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEAmoWFJaLTkYqFj1UB
-fsPbpb+MdcFhWZHX5lknwfqq79xk0Onj19RZRAYo7x/wW9Zxggkgpz/jBubEgT4M
-whLMVIRlHHberBtOrSs0RPhtRL+QVWRsqdP6wqclufnOv5PMbIfRVJLEGwtbCFoZ
-AmVbVgl2fmr2ECwohV65MCVg1Ys53cm59g9efSZ9GErRhe6rZC6AAwZeArHlW/IY
-5+d9wfI/+DpE4ZwDm4EWfG9U013Sqn4hE+9ZY5cUhfn3bZU619fChLm2ZfRuhyhc
-e7yZNw319RzlY1w+g18cKp+xJSJA4k721kt+bNigwMvRx6h8748aIsZ2h770Gd8Q
-tuOXuQ==
+ggEBAN49K1hjLk0yCNf3ScHKp/5OKbZAHucQEXrlQawVlyMMqfG2o6glNBOxEgt9
+UyoYLnmW+TU184iXMfwYLiDRnwUFEEWjiHGIvoTXAdYQOtJqYMt+H/WH0wFtyNaK
+rmiZkQSTn1HrRAcYEpvYtd8On/nHM03Sbi9zeThZRDiroWy7RN2wniu3Pt0gksIW
+Srpt5RbT/HdWWtvfcimt2yKcqpvKorNF+9PNMQ9u8d1jDKzBvWHNRieeflQeApR2
+COOKfEogrG+evzrE+9wHXDHnNqZwWQFX+2hh796uRGTZF5mi0f+VJfaP/x83ufxo
+u7PRjk//1yRZj6j8kL+1DLLnV58CAwEAAaOBhDCBgTAJBgNVHRMEAjAAMAsGA1Ud
+DwQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUAk/V35yUy+iJ
+pDxzwZV/QAYP4lQwMwYDVR0RBCwwKoINKi5leGFtcGxlLmNvbYIJbG9jYWxob3N0
+gghtb3JlZnVuIYcEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEAAGN3tpecRRZsVwFH
+7UIJzo7vCP4TyjM8tNgy4Ulszmrqq3NgHHNoh/AnBeCm/veqTDc9mWHrt31oVGi6
+jxXy38M5yBrnfw6t/AwpNlG1ceR9yuxCucdUrEkwDFuzBFwRe8Mv5TYjsa1u+z1V
+Nocc9UphCaabqMRtHi7uuvKrRI4bW53zIGXNlHf6MyYPWpH6AzLbOjLy3dYkV/g1
+YntXYoq8nvB/LM2lZmk8fby/1j3NzC4nr/L6YqNYLSC+1+fT2bVOfALiLbaPgsEs
+DsDCtLYLh0g9KdoWtNrC3AtFbplG16nDOahl8eIkkpCCwv0bRo3WuZjdR2MibcO2
+WVebwQ==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCdr34T9YzttOWP
-z0SSjBZtT1apPxyHtHHN94aLwPcPVwmYHtcR3xzNyXZwiRcswxZZJzY84PxlLAB2
-aPU9Hmm7EVFD4GS+umQcFmb8EtllHtL5Lj2+4IRgS1opYuEjUxB8txp8lrEDxq7M
-bA8gO7YvRemmiPc7h/yB/YD7cLjlZ9WEtxnRAUnIQ0sAQz31ipQJppeSHZxQ6gdQ
-L9BkodUTvFuUVo9te31JvAf7JpBf88ErBUIdnJJPDe9bLlhjWyxc6tD77PG2SYmM
-+1AMtvWcVVbP0C3AoUFrXQdNh9Gfiu4RNpa97ce7iJ0L5/P7Xtkkn9WoJTpe0SjO
-ACbRE6udAgMBAAECggEAIYdCKJ5Kk/Sl5zksHHj6/80h4STRPS2qESBzlF24aqOY
-H6dXFa66IiuXKoCL0/G7W8ORrcotAJolkwfoNVG1K5iYDfW1ljRtuucsiKa9YNn4
-BBHIAUEeBJehGTG0K12rIMmSMTGde+8QFdlYMgNgTpbwAoAXCap1j3JGrbAfMG/Z
-EQvGgs0MMikMrinruZInpwXeJzSwfkChSsOOPn9ORknd0qyZ1VVEr6qV1LicgWdE
-6WDX3fUE9aj+3HxSF93ZUiBlp1FRAB9PVJD0w4MBl6CthngVJmxucDzeEiWFtZLy
-ftSRWHKWMTnYWCToN+PQxql124K8P2RuL/MisqILQQKBgQDTnfnlx/5PYY8h2z86
-vQTz+zMrjHJsypDZvvIwaLJYpvK7bXrO0tnT5zML6qHJHzkX/pD2aPIqkNeRKFdc
-W8HJd8La87dVitpeFL5P2SmtDafYO1ZjlSH8r1U0oAY/IwCQppzK0knps23oGQJX
-hhPC6AGFhP+CrlA4FF+OcTY5zQKBgQC+wdpdvsOd2B8xccI6YUCxbqHEztDVV7O8
-sEpf0C8b6T+jjxHA+QBh2XIV0KcldYgUZLFDvIMcdupSHrheJVMTt2+TRlc5H52x
-/AbRkTFx4WW8Bz8jWhNJRzjZeYrCp0vPcwgqlgOa8bWZxz4nG5+xBaqX/KF8yifP
-2jYo+hgpEQKBgQDJuTkDkq7Y6u3vXzmZ+59iGJ6Br+NP05VbDEuAW/1Oxu5yPn2n
-9JUTC7y8alEJEMtzFQcI7aeTbfkf9W25q/pB2/kSkOq+D5vzvSBhq2iv/2l1lbLX
-QM1iO50kijsKKoqaWUjzipxMu+9UJar21ee2j0UMC2kqIJJ1su4YMdF4LQKBgDRf
-Mp20Ry6p7H59tg6jLsjID//hrDI2nvE6EWFW3egy1LcKC5zIgFNdCNZ2b714FEFN
-F+H5+qExAMpFBudKJhHuteJgWIglZv07rX+R9lpGwNCryKjjDRJ8TF5g4TjqB4VQ
-FrjicOD0ZaBvtF+2VNScMqcBxDBnrCCDz4TWjRWRAoGBAImt3zByXlk7eWR944QX
-5eeSPWAmESpRbq84iUCclbWYKr4BHcnUXJkcmHDZ9SVB1gocjbv944/wD6hUDrHe
-9ECkdaQ+LKY0IMgCSHERHn6vzKrQL09To/x9CUbII9/D056Y91Wd+t7XDq5S6Fjn
-Hh8RpGoD/ao9g7fCW3zXl8WK
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDePStYYy5NMgjX
+90nByqf+Tim2QB7nEBF65UGsFZcjDKnxtqOoJTQTsRILfVMqGC55lvk1NfOIlzH8
+GC4g0Z8FBRBFo4hxiL6E1wHWEDrSamDLfh/1h9MBbcjWiq5omZEEk59R60QHGBKb
+2LXfDp/5xzNN0m4vc3k4WUQ4q6Fsu0TdsJ4rtz7dIJLCFkq6beUW0/x3Vlrb33Ip
+rdsinKqbyqKzRfvTzTEPbvHdYwyswb1hzUYnnn5UHgKUdgjjinxKIKxvnr86xPvc
+B1wx5zamcFkBV/toYe/erkRk2ReZotH/lSX2j/8fN7n8aLuz0Y5P/9ckWY+o/JC/
+tQyy51efAgMBAAECggEANSCkYw3avMOQT6ijLju3K1keKZ5shMpXk2yI5Y2Hwu49
+FjaWKxUxvN9gs/Ry1CZRvel0i97o6CdU4LIbHOdfv4B1YmB0tsd83B7WJolctn6N
+wzfUhgrBS58mGvuuM/06KMDtnlTCv3tmv3DwEXHaloijYCBFDPzq5qiYYX/OKEKu
+RzoZ35KuL18fn9wl/3o/i4nhj3mEgCY2dqEPk0uIcPOnpATElRAXPPJkdpvEbHh1
+6uE3BdhX3JYbRkVZHkN2foMij/J5Lx1fF4w4MVt4778nvUlCTczrrPckQ5jE2JjT
+F+tHkXp/D7IzSBZN5+K58Hw21B1prKMBXSLUu6950QKBgQD6dUM8FgN48D9LXdyY
+7G3v+ZMR4CghuBr3F+Uft5s4FNU7J4lfbyQS8bgRITQHrrNJBiTyRoaeF8E+Xh4q
+dcDPzbSq55KY5Os4dm32Exj0JfATGXWqToFRzzP8lE/EHKWQacpUURXZFhhTrBxT
+ZBjTJrIVBa5P1ocyXU76uS+dhwKBgQDjKA65MvVRMOHiLmvUBuRXpf8piwWzQSsB
+NS865cAj8Jh8ME6ub3d853zY+Tn3ggmDc2GToyRdUfsWdknC0gp/ssI7OhafIMCt
+iQDJbQf31y8FssuP0DZxrsODVFW/5g+1jgp8/g4/CGZAJ6avv0PWSExhbiB1yuXz
+qj4rfX87KQKBgB9VYkb3HhIYRGLiaEG9eneGSq720y58wOre02xnZQTcHl0bMiV9
+Ww7/rJ5//+liIs3k9eRVjGvk3uk1jyKSvr+ApbSn6gA0y3Sx5Enf08RfpqxNCBp5
+XdZlTMSxrVUEnHX3tjdcOZaCHCMDqjuIj06DTc4xesBEP3++iq31Uw6rAoGBANL/
+Y2W9oscO29KngftJh5KumywweVP/JX4Ss9NGk8oOcuVwTbWTzm6T65DzN1fjTwju
+BOYJNP8F5m//4hX32k6xcd9n3pli5/aJetSe1TbuhzwIzzK/mcLRLcRwctI0VcUz
+siRWLE96ctgGvLsks1N4hpI9pCMmG6DRMrxc7vC5AoGAfV30FhZeueDqnEw8XBE7
+hvhxtBkXAfkiQFPxwru5vchhdO+pJCH7GFc5SA0urBTP1pxNiIbGnOsj3fYYTZQ5
+0zG3tpj/iwxIaXBVnDZn4av89wSw1r+LaLnxcFFSK7sdH2De6gxxXizrZkvFM2FE
+imAH17PeyOYpyspDE7RlaZs=
-----END PRIVATE KEY-----
diff --git a/jstests/libs/localhostnameSAN.pem.digest.sha1 b/jstests/libs/localhostnameSAN.pem.digest.sha1
index 960770cca92..97e209c3a67 100644
--- a/jstests/libs/localhostnameSAN.pem.digest.sha1
+++ b/jstests/libs/localhostnameSAN.pem.digest.sha1
@@ -1 +1 @@
-BE6447857C33C9DCF64D04E54E8AB9058A3671B4 \ No newline at end of file
+D9FBFF103D99F938D781CA0875D8D79C8D7F181D \ No newline at end of file
diff --git a/jstests/libs/localhostnameSAN.pem.digest.sha256 b/jstests/libs/localhostnameSAN.pem.digest.sha256
index dd94621b51e..3636d31382d 100644
--- a/jstests/libs/localhostnameSAN.pem.digest.sha256
+++ b/jstests/libs/localhostnameSAN.pem.digest.sha256
@@ -1 +1 @@
-990F5BB5892A9E32ADAF5F5399526C29E028837AFEF5A6984D102BF0A77C6FAA \ No newline at end of file
+F479EE0CB7FA5C5299AA956D3FB0C18CB524618791D49E114605B2E2F17492C0 \ No newline at end of file
diff --git a/jstests/libs/not_yet_valid.pem b/jstests/libs/not_yet_valid.pem
index 8bbd571be75..2c542630228 100644
--- a/jstests/libs/not_yet_valid.pem
+++ b/jstests/libs/not_yet_valid.pem
@@ -3,53 +3,53 @@
#
# A certificate which has yet to reach its validity date.
-----BEGIN CERTIFICATE-----
-MIID1jCCAr6gAwIBAgIES/Jl3DANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIID1jCCAr6gAwIBAgIEZZn89DANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNNDQwMTE3MTYxMTM3WhcNNDYwNDIwMTYxMTM3WjBzMQswCQYD
+IFRlc3QgQ0EwHhcNNDQwNjA3MTYxNDQ3WhcNNDYwOTA5MTYxNDQ3WjBzMQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEWMBQGA1UEAwwN
-bm90X3lldF92YWxpZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMb/
-+Pw3jfMT1jqW+l/GR5P9tGc8vWgAEFXlS+4LyrYUGaSs6eZCsIcLp3hw53CBx7/a
-/CuouKe2i3QB2OTPk3qosuVgi4LtXZ1r+3Fn4ZGey4HPPNC9QrP/RJwKfss4QGFD
-MCVVf/WH5jg1+NjbNicAtz8xDzflr56tR49gEfKhUukNXeiUX3WmIOGgCZ5kVQya
-91s/kZHBmM29ipj+ZwW0vRLYV3/4Z/QTB8Pjdvww3Xouu/G/D1+Wx7PKQXGodUQT
-qi3DWHVgdVWcPDVRrODQlp+zf3+uvsfkBlF4PQIXxjeZzeJxfFqaPfKfJo082ifl
-rChYW8QJWTY7YMx2NjsCAwEAAaNxMG8wEwYDVR0lBAwwCgYIKwYBBQUHAwEwGgYD
+bm90X3lldF92YWxpZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALNu
+efjoKq6F6zCqoHb2a1CXWUt8+E7K0DRI2kxzSnwz1XLAGBeF6NPHrBdSI4JBOfBC
+F14+w+Wf1Ka9ssidoXdw2AEujaCjkxH5TFe3g/q5TPeP7uZhx/DtV3Z1DlKialkK
+uT0tV8XeNySYzMqi6yUFAoTAJdUvM+d2HJnEKJyoyYZw8/BJdkcUW+s2qHpcWnrY
+u0wCsEFz3jjhZIVW4B8HnMACYA2lMpYSG+xuPD2b3Ux6qxQwybOF1o/7DoHd1WZ+
+1u1H4Sez1oSX8SbPMTwyXXIpkcKtAUdMiI/Ndfyf5e1XQ0YBoMqoh2Oq9CvZlWVj
+NwnBEOPwWBx6QLQbjsMCAwEAAaNxMG8wEwYDVR0lBAwwCgYIKwYBBQUHAwEwGgYD
VR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMDwGCysGAQQBgo4pAgEBBC0xKzAPDAZi
YWNrdXAMBWFkbWluMBgMD3JlYWRBbnlEYXRhYmFzZQwFYWRtaW4wDQYJKoZIhvcN
-AQELBQADggEBAJu9tFv+hLs6AaaWeA8jtSd/vPCGZNVvkZQNOQcupixvjlv/1V1E
-MDUMZ7WE1odcNfajskVt6eWh0nzZVmdf4NmixmsqUuqg/RW+9JK6LOguf2BqhMpw
-87082Ktqc7X4Jjbvj37cZkBoe1wF3FVDqG9asUCk8t7owV+NgS0LDgQHkaQmEbCg
-M/Xli0DaT9KPIK/SORPoaefa2DmhT04I9+wvzvOdgTnDZ7vQUi2lFdCjAOz1cZG3
-eVJAy+MgOEQ5l4W/+D9S+fETHQjMd1WKPcXeqFwUnvFRwD2hgxJTXrVjKAeUIMOp
-wNCOyVfE3wJxX+SdIlshbBa4prxWXYdySwA=
+AQELBQADggEBAGFMdF6J125wgi6r/s9KOFK3S3wLaocpNADJca8meTaLlnbOQVFz
+iDa66KxLvUGM9XnlAI2+sPfcKQvwfBNC34DcdaAjJxTrZmUjX+9j8TudEvKIQApq
+h3Oclb5DUV52TQxbyrytZ1vHyWin04h2n5J7mF9M+tExCwhIVS089gswSrUiQRHb
+DO4FfuLOQLI59GAbNEDKvm/+l+nzFQ5cOMy6IAs1Wj1JuXtpuJrhYs6UxAV0MvAN
+yfJabvNieKDy/uFli4BmIrd6aLI+CD+m9ApDCq/bz5+bYYWrwGLjeXFoi9Xcb7r/
+J00L0/k+nQTCstr5yxz76jYKFJ0ZM6fjfMw=
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDG//j8N43zE9Y6
-lvpfxkeT/bRnPL1oABBV5UvuC8q2FBmkrOnmQrCHC6d4cOdwgce/2vwrqLintot0
-Adjkz5N6qLLlYIuC7V2da/txZ+GRnsuBzzzQvUKz/0ScCn7LOEBhQzAlVX/1h+Y4
-NfjY2zYnALc/MQ835a+erUePYBHyoVLpDV3olF91piDhoAmeZFUMmvdbP5GRwZjN
-vYqY/mcFtL0S2Fd/+Gf0EwfD43b8MN16Lrvxvw9flsezykFxqHVEE6otw1h1YHVV
-nDw1Uazg0Jafs39/rr7H5AZReD0CF8Y3mc3icXxamj3ynyaNPNon5awoWFvECVk2
-O2DMdjY7AgMBAAECggEAGayYwQxMghoDFQK5lssMHRR/G/qtgnzPnrq7SyELrDt3
-pilbnAY/+YxlX5f2ztXPoaRtIxeHi2Ef0328L/kf++lGphVd/9cEBvVm4Wts93lX
-TuN1OIZ9KUqRMtifzImbX3ETBci8KOoO/R2ULNZLbEjJW5vGwjLIr7OHfKtWZXPJ
-3Rrtiemn5Ttko1ZOEb7T6SIwfJmMCflUS27zaG+mcqhev/2aLp8tNq16F8gVgpeX
-tRZJNe64ux/a7eeL3bPGob0s2AIzzMLuHYM+VR1VbX2VFMGyR+Y70PtAP66H4xZJ
-5uB/49bik65SCe92dg6u7k7HALjRM0pI2sQcWikgQQKBgQDuRawEmhGCWc0ETpF9
-l7nNNOafd1BHgSpCeNWQbN9gVmIJEhBVutzOpaq00CM/9k4o9Q32PqHnDTFNjRj9
-EBaHMBTO7uK7Ksj5UsaJDC+3sScqHvXDcjFRqpsh3ccfPJ93bikD7DjfUgBK3Vnv
-5ERwPbBrxVYJEPeV/SQDc187UQKBgQDVzknqU7kVx7hv1WUYjIr+H/tsqBEEubIi
-VV+BKibFN5qtxnpPwY34HgZI5wynpvcAbvxe34rCajyaFx2lBu6q6zVglsT3qycH
-vCXbcCbdyZ5n7lHG0sH2Ed5NGbnjsSOLFUL3kYmfE0Wgj6TV7iX7CBcEDN35HhAV
-OJPegBodywKBgQCVyWjFD9G3/xn5/iZKLMqZ7QqZ7tihyto1JV8kRrz6A/PnPdrU
-+f57TfwNZNb0C7PA3aSkS2VeKZX36Z5u3+E5pQk/uT8BaHkk+1thpi6NLKmxOftH
-nY7Rhw208YWO5n5dBvxzwdlS0mrqpVI3k2lOogk5Brn6QxdRy+wK20lfsQKBgE2e
-Rlc7bcXqa5qt7bWr0AnRsoUPvp3ojDLKq5FIrCqMtSrBE0ZBDjk1LTLqLj3u71zI
-7fXDUayixL1sBucSTTLfkNEv6vG+wLyeIWA4puN9fnRcoHN9r8yVUA7NeB6hADZN
-0bHus/d8F5riiwTfIAqyNSjTQwJdV5lcoNH1z4VhAoGAHiBOvQAuulaZ7y6uVpQ1
-RewUcqpDWxPWqr7JUvp31qPFdzPgS0ZAm0iXEuI2eFoX5tP3n+uxO1j8sWeFCBE3
-OE3m5cl5N05RRqO96TaEciflH0IqaoB/rcPov0xFfbsx0sKDWucdQLeWTA8OUIVK
-zBRsUBz3J2GmZNnNJTMd+VI=
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCzbnn46Cquhesw
+qqB29mtQl1lLfPhOytA0SNpMc0p8M9VywBgXhejTx6wXUiOCQTnwQhdePsPln9Sm
+vbLInaF3cNgBLo2go5MR+UxXt4P6uUz3j+7mYcfw7Vd2dQ5SompZCrk9LVfF3jck
+mMzKouslBQKEwCXVLzPndhyZxCicqMmGcPPwSXZHFFvrNqh6XFp62LtMArBBc944
+4WSFVuAfB5zAAmANpTKWEhvsbjw9m91MeqsUMMmzhdaP+w6B3dVmftbtR+Ens9aE
+l/EmzzE8Ml1yKZHCrQFHTIiPzXX8n+XtV0NGAaDKqIdjqvQr2ZVlYzcJwRDj8Fgc
+ekC0G47DAgMBAAECggEAclxVbSk8GuPL1MbLY0cHeuQby5so/78QGGLej59jt+mp
+f2ujb0qv7Fr0+iAl9Zzw+oqFLlI+tRm7hVKeonKlOOU5Jveu2NWopOoJmFakzaZQ
+wfCAyWFE9++tsRhGOrC9q2bETZOav8gzySWCURypVnzs8AMvmcJuCHYlIHP/lmiE
+YGdsWAM7E1GLNTS82BCpoWsuEbAP9ShKYIlAIZu3l4xmmMXQH/8b7G7nQJPeQYEJ
+jM76YerPAW/TnwG/TUazo+SeNtUSSM6aYNfeIRaKXuAAIaRIiAUofgCmBk7UdxAU
+D/Krg+8npwdlTqijFrGi6qHqqVepw8dYOgS21wKDQQKBgQDY6ENoaie8WbzGdRBx
+lVeR2U0OJdJUifnf4OfG7zcPSag9chnTCe9hzDYdd7vuW4/cJCXAzh6E1q4P4STb
+CMX8e/XYZR8D00dBQnmf1+Xsz8azV2jXeXS924RNwPXYPIKdr2ct0V5NTxqo/Y2h
+GFDhBRf7FXBeGsNL3Qg3z9xOkwKBgQDTxSVjnd10/89/KQyeyP0TVzLDSxiB1JMW
+cwSCLFRxSjyPT2a8wk7wIk4dOcFNa8o2JenpRn46cTQq2/X4i2GoMERdASvJi/hc
+iJLYO+uJyvkyYv8hTAp6Y6X7WDIY2qxbuBe0I4mf286DZes0aXFuBzNWEU1uWuZY
+kUvC4LutEQKBgQDS9bL5zqUu7yhG7Hw9vD4bP/lNlUNnrXo1YAyM0wP9/ml+uYac
+VsFXoMHRDy7cuHjGZvHA/7d3A0TvdM3fqjzFP9rvyAnOMqLOudSIvfaFx989dfol
+956vON0Ism9pDBENRBdZ3JOXJSSMz238DCY9dDLKpSNQoz7mfecMQUHHuQKBgAMF
+cgYcz3cG20f+Ju7xASNQgCnnHV9k0ABm/a55wW6oV3rX8ChLQWMNqj2igE6Bdi4V
+lmO8nLpquQrPfo/gNTF4FtGY3a4PcCipziaFnFOn8Kw2W1t3QUMDvu96D6TpIcJh
+Ov1X8HO2aBjZ0GQ8COE/+wyETK2BYH3s/L64BBVxAoGAVt0TBOCz7R28MT8qqewT
+yBvpvojU0Xe5IBDL/U2K41m4P+TmCh+2+QLDPOQqj0zbPEab6okkIbOTvINSegPq
+DwE6dgMJGdsA2NcE3awNAtUlxrq1XCIHTKjatmP++HkO92Ku/uN0AU3hI8gTso8L
+p9a83aJSK9/trd41AmhxYuQ=
-----END PRIVATE KEY-----
diff --git a/jstests/libs/not_yet_valid.pem.digest.sha1 b/jstests/libs/not_yet_valid.pem.digest.sha1
index b008fd75f36..99c3e6fbd76 100644
--- a/jstests/libs/not_yet_valid.pem.digest.sha1
+++ b/jstests/libs/not_yet_valid.pem.digest.sha1
@@ -1 +1 @@
-61BC938206DABDBCA7A12D382655BA8D3C159425 \ No newline at end of file
+10081A8AE949DF39C8EC74FB7E2CE5964D00B9B0 \ No newline at end of file
diff --git a/jstests/libs/not_yet_valid.pem.digest.sha256 b/jstests/libs/not_yet_valid.pem.digest.sha256
index 45b7dff08ac..8e90766b435 100644
--- a/jstests/libs/not_yet_valid.pem.digest.sha256
+++ b/jstests/libs/not_yet_valid.pem.digest.sha256
@@ -1 +1 @@
-6E437AE955BB7B7104B930406DD2941D5987A7DAFEADB041214BD0C4DD7C4686 \ No newline at end of file
+6BE588A92C971639EEB1C9B146E17F270D79F7F16D035A6A97DB6C1EBFB2FCAE \ No newline at end of file
diff --git a/jstests/libs/ocsp/ca_ocsp.crt b/jstests/libs/ocsp/ca_ocsp.crt
index 764450171b5..ff9cdd585b4 100644
--- a/jstests/libs/ocsp/ca_ocsp.crt
+++ b/jstests/libs/ocsp/ca_ocsp.crt
@@ -1,21 +1,21 @@
-----BEGIN CERTIFICATE-----
-MIIDeTCCAmGgAwIBAgIEB9wTPzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDeTCCAmGgAwIBAgIEaS5ADzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTQzWhcNMjYwNDE4MTYxMTQzWjB0MQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ4WhcNMjYwOTA3MTYxNDQ4WjB0MQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwO
-S2VybmVsIFRlc3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCe
-ytoe84QvjltBg5/lNoKxXMUAd8Kg9AUxc9cfnBvdtwpmNSLkiNj/zgwtdCvfHqkt
-16rPBm5XXCb1IdSBS5+IUwfvav8FHdkEc+h/KcLCR3CXwEONtEWCpAhEp/2qz6z1
-TXu3KxYwlsqFFregnk/LSzD1SZEhrostXxH96SjLvwYMtyprzebHBb23ezr1wv3s
-NlE/SVm9X8IvTrosvvVSuKvp4PSa9bqg76GE6CXEUbfTIXwobnqhGcRoWuNXH4MG
-Yp4hs177RNiuSnEvUzxs7K8B3rOyGqmCndYErOD0U8uZy61bG7SZi/ccGRoTmhCa
-KYO4ZVUBQVW/RW6P71kFAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
-hvcNAQELBQADggEBAHyfVvg4s8wTHzJZ5vgopIXbZWzFtgQts8wslTktkt9itpfF
-Oou67JQqn8egFMJt56fRy7BCAIIEDFfrtp1PSic8CZDRB6Ks9+/fIHfYIkm9eHZl
-TbR4Zz0hpk8BNqfsk/CH8pp2/7l9nowh2mLZa+5Zfk+ImZGsib+aqUCkTq+xboai
-YDuq2OWctC+9YqIQBgIu0PB+uwcdqhLAwdwtXuVRYV2ZJgs+ruUvdTKw1ztMI2dn
-+dzMSEKHFTOJl8goRPl0xi5ToJEK5/qfaDTXt2x991VTrnFJGNlS9esaKaDSsWA3
-JNQdt3Ar/o0SRs+MHAhoHFtevq0tU5wXB0mF/Gc=
+S2VybmVsIFRlc3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDD
+2GI3zcFmEpeZhPndIW42gT4VwRkpWLEtogykbFhCrDCXaici313xjXm/TIypRxxC
+K84wKlNYx2AAgRdgehdKkLSEgDYFL64PcF0hXCFocmVrJDr0+BMI+JsA3RxQ6mAM
+xD18flNxx8GhL8zFPXYkMG8cP/X5oaVnTXk8fvyZbKJG1HyVDHXds2T3jI9O04HQ
+oYbm4n27SV09LCMiav7jaXdc+OdwTTnW1E7x9E3XsfWFqY2v8RnlDYA8TK6QyiGG
+XsHVdex41Yg3zqKwgP5h5EjXPr5KD6ChVEMnExitkHUIuI+SxaaE0S+B7jS2jCQv
+6EQP9f8uStHJUQgegycZAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAJEs7uxFM5UudRNEX1Qo+wvp0y7bMJbf6ECjAL9dJ688Cp6I
+GgKXWA5ltJNDXR8aQmVYafA7dDiu6Hs7F7y+MP9ulV+MqCoVuJF82QK4jcwxgx11
+fRxbTGgh9WX2f/w0zVJ6sp4QHYDq3vgE1f+2AV1v4OdDnXV9O+wrUOmDTCt5RNa0
+Qo6FCeFG929+LKjR1VmlCCHNMO0+s4UdxBo9AQRq/+mOiPXw63jXckwGOxgpReA9
+lhQVC4rAHfPiYxegaJwwcU3gGbwxMZPTMHkUbKRaMEJJGHs8vCKZ/pK9ivTx/Sys
+eA+6l3QJeLuhA+Ifs78oJ8emAdCpgMgS5nhjbVQ=
-----END CERTIFICATE-----
diff --git a/jstests/libs/ocsp/ca_ocsp.key b/jstests/libs/ocsp/ca_ocsp.key
index 46fbf93ad33..f3472a2bd0e 100644
--- a/jstests/libs/ocsp/ca_ocsp.key
+++ b/jstests/libs/ocsp/ca_ocsp.key
@@ -1,28 +1,28 @@
-----BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCeytoe84QvjltB
-g5/lNoKxXMUAd8Kg9AUxc9cfnBvdtwpmNSLkiNj/zgwtdCvfHqkt16rPBm5XXCb1
-IdSBS5+IUwfvav8FHdkEc+h/KcLCR3CXwEONtEWCpAhEp/2qz6z1TXu3KxYwlsqF
-Fregnk/LSzD1SZEhrostXxH96SjLvwYMtyprzebHBb23ezr1wv3sNlE/SVm9X8Iv
-TrosvvVSuKvp4PSa9bqg76GE6CXEUbfTIXwobnqhGcRoWuNXH4MGYp4hs177RNiu
-SnEvUzxs7K8B3rOyGqmCndYErOD0U8uZy61bG7SZi/ccGRoTmhCaKYO4ZVUBQVW/
-RW6P71kFAgMBAAECggEAJP+6gY43jVYj5Li8261PF/D39RMyjgq1oA9v/01CP++r
-lGOKqQnK2BXESB4Cr+cGv+f5xGmo8aGG8USL7YF3n03LcklxuNk6zPsN3/1UxCxd
-q3ows1afAKDkTU0AQdnIYNLIQgZf0fv8nbSMnjfs+z8enfShhKHVC4IUoN9AMnLG
-tOaAqobht0WskDxmbKP/3TXr2E1C9gO8HlXlOVfkGAdiJEtSFrMI0469VUair/f+
-mhIZd92crbmeo17Q3W4KT6i7j9vPsIZsXy01Dp09+fVJWwjYc12RF08K09aAWzn6
-9M22ICUbpDCQ5NiVRPbw5Q3pqK49D2Ddqh7XzfU3QQKBgQDBNej9+i0qt+PyV9C6
-NIwqzkg7KmkE+XNtGrshBT1QCp9Qo4MwR/Aq+R3GQryGignVbcDTAw/95yu4v+rZ
-m3QIJXfhurtS32X8o1+9ICo8+d/sI6T7kmtAVJiMF3wvnkTGbsR9oMW6c/vIoIpO
-g+oqPyKLUtf1ndxTcnM/YAgWxQKBgQDSZYgb42eFcQsffvMNqSVHyWtBEyswa096
-9GWJVTi8wfUREDNN1wlxFW4RH3n+NtqD1HGsBqAoXpMNu5VoF8SUuwDE813MpAfq
-9zZ+B6Ld5EPsk8deNAMTUD5PtUh2MfRgzY3ZdrY59vQ+eBzwwtyeHNm4EKhsKCDw
-kDb2QOxdQQKBgQCqS34E/ZD56gM8AzKyLMaupAr+Oy89dzDJpZnyTM/x0KsDRFvJ
-Hl8NQW2A5imM2/Y26/ndAwIBZNQgjufMzTvEQmIbz550OPuHZehopgUUoZlAZVpx
-cmid1vJt5/VJc1JjJBaENESTRs9R0k6VTagDfIpSCr7WekFMO8Bgx5/ZkQKBgDBz
-WSiy8X/1TE5weaBHt2IUrDJMK8H2tFLoPQmnKm2tbLYFOQtP3cjA2pvu17UHBMMf
-BR5MWE1zmgGrlPhnoMlvVvoD4THjBD/DtjTHpWXbzxiH331+FMc5z1+jq5AsaM5y
-B5xwjf5DNHO+TUvUU+HFWw3cKCzgANXlIAMNaGEBAoGBAJ8ZObdgvgK7RCQTHJIi
-OF4CAWvqshGpM3eT1Xgf7ceT3ZjRAohnktbkdwENNOWe4xiiQi/O3iLA9PFE/n78
-t7XlEcMM03Oj6qpFT4F3fT+RpaTujl03aMwdyul6EyWoyrDA0j9ZqP9UWkIs490L
-nnwStULa7PR4K7mR73YmBzLf
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDD2GI3zcFmEpeZ
+hPndIW42gT4VwRkpWLEtogykbFhCrDCXaici313xjXm/TIypRxxCK84wKlNYx2AA
+gRdgehdKkLSEgDYFL64PcF0hXCFocmVrJDr0+BMI+JsA3RxQ6mAMxD18flNxx8Gh
+L8zFPXYkMG8cP/X5oaVnTXk8fvyZbKJG1HyVDHXds2T3jI9O04HQoYbm4n27SV09
+LCMiav7jaXdc+OdwTTnW1E7x9E3XsfWFqY2v8RnlDYA8TK6QyiGGXsHVdex41Yg3
+zqKwgP5h5EjXPr5KD6ChVEMnExitkHUIuI+SxaaE0S+B7jS2jCQv6EQP9f8uStHJ
+UQgegycZAgMBAAECggEASMMzMqJ6cU8FDh+uqa7LAOshwvlcPNVb9qVXZxtt60+I
+OilRYw50G9PBYQay2A24fQlDcPe4wapJi8Zqhgi2cJi0yOnNqD2fwNKxdzyAmQqv
+jZAHa45jnBipljeQVqvNhdC/O2q/2+0ojpdwz/NW2nk4PtmwrM+W4XuSSJyxgtqH
+5lqaLmGj7UlkJEuFakOtNLjLTbH6BpkOqf9r4Q3qlV5xgNXDnGrNfCMxgQAn1xRh
+/sxcaQeEm6HM/i2VSdCilM9Td8W1S9E6jfiQyYb8B3E2o3bhQS0ktG8jpze/2GjQ
+IqJD9cXFvGOjVpCIfxHacV0G7wXWgSKeJx4fNihjZQKBgQDvxx7BIsOg35QD96Sl
+09Wk3zow+0jloqyZfw62OIgG3aUyTvIw3KFv8F6PCmAZG3OoeMnfbJT/sxK2X4IA
+4aTL+zdHhpGn3EwCgf7cfiYTRD8nPlVe8XrFU4SpdAEsF7o9NHgauXTL6F/Bfyz/
+HHDSuDnVe97xLtOBt95X7E+UtwKBgQDRGF1bt/jBfYkknJ4I5dpM7nsXO2WIZ06f
+my/xBlbK3OOKAFA96zcGD4ppuJtgyRwhYnkjPD4hoHxVLkcoHOkWBnCTwB+LQi/Q
+mQYMgwpQXpi8EbLvX6nf/K2A11acKeqb7RTD9EP1bhgrrVz4anxzG/xbYToPXW/b
+AAC0djVyrwKBgCODv7dlmco7M2Y/COES9kL8WVcl8Q8qQBxgKGKvDt7Nd4lzDgZU
+t4in9qmDJOazHTdn5Ka2I3+YG35tuQi+YzVfWTm74dkWFSAN9xzbhnI2GpCKeASf
+CcsuaqjaqM3KGei029FBhN4q5fv4BUcoBEIBzXckaMoaYHOHM2SceNETAoGBAM2p
+hmIpcQ53+IW/Wp3r3y1eQEoYjQR+gFHypVQP5RyB6XiaWFKe4a8faAgWoRWwme+o
+WPg0T/RpUwHBlBG7ZfPY/7AD/8LMphUp/k4eMe3dLaOGURarZH5AnTOmGrVdcTpP
+FeargpCL6lBDo7dfnermsu/6kM3+HIAu34Kg5m9XAoGACTkiGqNDHHuP+s3iC2uO
+xhnhJmnxbS/6sNy148LyfPNkdVWGPWuBiyxirsKF9L3iAUM13FLdo9n9DlwSl2Vd
+uLRso65t7jRa31RdcmKqHrIA/fun9/kEziyLSb402DKvp1rqsYNhHKXH3UYNPoQV
+8Dd1LdVSKpTRQuMpA7yA2q0=
-----END PRIVATE KEY-----
diff --git a/jstests/libs/ocsp/ca_ocsp.pem b/jstests/libs/ocsp/ca_ocsp.pem
index cfecddc81f1..20280b7ca18 100644
--- a/jstests/libs/ocsp/ca_ocsp.pem
+++ b/jstests/libs/ocsp/ca_ocsp.pem
@@ -1,49 +1,49 @@
-----BEGIN CERTIFICATE-----
-MIIDeTCCAmGgAwIBAgIEB9wTPzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDeTCCAmGgAwIBAgIEaS5ADzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTQzWhcNMjYwNDE4MTYxMTQzWjB0MQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ4WhcNMjYwOTA3MTYxNDQ4WjB0MQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwO
-S2VybmVsIFRlc3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCe
-ytoe84QvjltBg5/lNoKxXMUAd8Kg9AUxc9cfnBvdtwpmNSLkiNj/zgwtdCvfHqkt
-16rPBm5XXCb1IdSBS5+IUwfvav8FHdkEc+h/KcLCR3CXwEONtEWCpAhEp/2qz6z1
-TXu3KxYwlsqFFregnk/LSzD1SZEhrostXxH96SjLvwYMtyprzebHBb23ezr1wv3s
-NlE/SVm9X8IvTrosvvVSuKvp4PSa9bqg76GE6CXEUbfTIXwobnqhGcRoWuNXH4MG
-Yp4hs177RNiuSnEvUzxs7K8B3rOyGqmCndYErOD0U8uZy61bG7SZi/ccGRoTmhCa
-KYO4ZVUBQVW/RW6P71kFAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
-hvcNAQELBQADggEBAHyfVvg4s8wTHzJZ5vgopIXbZWzFtgQts8wslTktkt9itpfF
-Oou67JQqn8egFMJt56fRy7BCAIIEDFfrtp1PSic8CZDRB6Ks9+/fIHfYIkm9eHZl
-TbR4Zz0hpk8BNqfsk/CH8pp2/7l9nowh2mLZa+5Zfk+ImZGsib+aqUCkTq+xboai
-YDuq2OWctC+9YqIQBgIu0PB+uwcdqhLAwdwtXuVRYV2ZJgs+ruUvdTKw1ztMI2dn
-+dzMSEKHFTOJl8goRPl0xi5ToJEK5/qfaDTXt2x991VTrnFJGNlS9esaKaDSsWA3
-JNQdt3Ar/o0SRs+MHAhoHFtevq0tU5wXB0mF/Gc=
+S2VybmVsIFRlc3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDD
+2GI3zcFmEpeZhPndIW42gT4VwRkpWLEtogykbFhCrDCXaici313xjXm/TIypRxxC
+K84wKlNYx2AAgRdgehdKkLSEgDYFL64PcF0hXCFocmVrJDr0+BMI+JsA3RxQ6mAM
+xD18flNxx8GhL8zFPXYkMG8cP/X5oaVnTXk8fvyZbKJG1HyVDHXds2T3jI9O04HQ
+oYbm4n27SV09LCMiav7jaXdc+OdwTTnW1E7x9E3XsfWFqY2v8RnlDYA8TK6QyiGG
+XsHVdex41Yg3zqKwgP5h5EjXPr5KD6ChVEMnExitkHUIuI+SxaaE0S+B7jS2jCQv
+6EQP9f8uStHJUQgegycZAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAJEs7uxFM5UudRNEX1Qo+wvp0y7bMJbf6ECjAL9dJ688Cp6I
+GgKXWA5ltJNDXR8aQmVYafA7dDiu6Hs7F7y+MP9ulV+MqCoVuJF82QK4jcwxgx11
+fRxbTGgh9WX2f/w0zVJ6sp4QHYDq3vgE1f+2AV1v4OdDnXV9O+wrUOmDTCt5RNa0
+Qo6FCeFG929+LKjR1VmlCCHNMO0+s4UdxBo9AQRq/+mOiPXw63jXckwGOxgpReA9
+lhQVC4rAHfPiYxegaJwwcU3gGbwxMZPTMHkUbKRaMEJJGHs8vCKZ/pK9ivTx/Sys
+eA+6l3QJeLuhA+Ifs78oJ8emAdCpgMgS5nhjbVQ=
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCeytoe84QvjltB
-g5/lNoKxXMUAd8Kg9AUxc9cfnBvdtwpmNSLkiNj/zgwtdCvfHqkt16rPBm5XXCb1
-IdSBS5+IUwfvav8FHdkEc+h/KcLCR3CXwEONtEWCpAhEp/2qz6z1TXu3KxYwlsqF
-Fregnk/LSzD1SZEhrostXxH96SjLvwYMtyprzebHBb23ezr1wv3sNlE/SVm9X8Iv
-TrosvvVSuKvp4PSa9bqg76GE6CXEUbfTIXwobnqhGcRoWuNXH4MGYp4hs177RNiu
-SnEvUzxs7K8B3rOyGqmCndYErOD0U8uZy61bG7SZi/ccGRoTmhCaKYO4ZVUBQVW/
-RW6P71kFAgMBAAECggEAJP+6gY43jVYj5Li8261PF/D39RMyjgq1oA9v/01CP++r
-lGOKqQnK2BXESB4Cr+cGv+f5xGmo8aGG8USL7YF3n03LcklxuNk6zPsN3/1UxCxd
-q3ows1afAKDkTU0AQdnIYNLIQgZf0fv8nbSMnjfs+z8enfShhKHVC4IUoN9AMnLG
-tOaAqobht0WskDxmbKP/3TXr2E1C9gO8HlXlOVfkGAdiJEtSFrMI0469VUair/f+
-mhIZd92crbmeo17Q3W4KT6i7j9vPsIZsXy01Dp09+fVJWwjYc12RF08K09aAWzn6
-9M22ICUbpDCQ5NiVRPbw5Q3pqK49D2Ddqh7XzfU3QQKBgQDBNej9+i0qt+PyV9C6
-NIwqzkg7KmkE+XNtGrshBT1QCp9Qo4MwR/Aq+R3GQryGignVbcDTAw/95yu4v+rZ
-m3QIJXfhurtS32X8o1+9ICo8+d/sI6T7kmtAVJiMF3wvnkTGbsR9oMW6c/vIoIpO
-g+oqPyKLUtf1ndxTcnM/YAgWxQKBgQDSZYgb42eFcQsffvMNqSVHyWtBEyswa096
-9GWJVTi8wfUREDNN1wlxFW4RH3n+NtqD1HGsBqAoXpMNu5VoF8SUuwDE813MpAfq
-9zZ+B6Ld5EPsk8deNAMTUD5PtUh2MfRgzY3ZdrY59vQ+eBzwwtyeHNm4EKhsKCDw
-kDb2QOxdQQKBgQCqS34E/ZD56gM8AzKyLMaupAr+Oy89dzDJpZnyTM/x0KsDRFvJ
-Hl8NQW2A5imM2/Y26/ndAwIBZNQgjufMzTvEQmIbz550OPuHZehopgUUoZlAZVpx
-cmid1vJt5/VJc1JjJBaENESTRs9R0k6VTagDfIpSCr7WekFMO8Bgx5/ZkQKBgDBz
-WSiy8X/1TE5weaBHt2IUrDJMK8H2tFLoPQmnKm2tbLYFOQtP3cjA2pvu17UHBMMf
-BR5MWE1zmgGrlPhnoMlvVvoD4THjBD/DtjTHpWXbzxiH331+FMc5z1+jq5AsaM5y
-B5xwjf5DNHO+TUvUU+HFWw3cKCzgANXlIAMNaGEBAoGBAJ8ZObdgvgK7RCQTHJIi
-OF4CAWvqshGpM3eT1Xgf7ceT3ZjRAohnktbkdwENNOWe4xiiQi/O3iLA9PFE/n78
-t7XlEcMM03Oj6qpFT4F3fT+RpaTujl03aMwdyul6EyWoyrDA0j9ZqP9UWkIs490L
-nnwStULa7PR4K7mR73YmBzLf
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDD2GI3zcFmEpeZ
+hPndIW42gT4VwRkpWLEtogykbFhCrDCXaici313xjXm/TIypRxxCK84wKlNYx2AA
+gRdgehdKkLSEgDYFL64PcF0hXCFocmVrJDr0+BMI+JsA3RxQ6mAMxD18flNxx8Gh
+L8zFPXYkMG8cP/X5oaVnTXk8fvyZbKJG1HyVDHXds2T3jI9O04HQoYbm4n27SV09
+LCMiav7jaXdc+OdwTTnW1E7x9E3XsfWFqY2v8RnlDYA8TK6QyiGGXsHVdex41Yg3
+zqKwgP5h5EjXPr5KD6ChVEMnExitkHUIuI+SxaaE0S+B7jS2jCQv6EQP9f8uStHJ
+UQgegycZAgMBAAECggEASMMzMqJ6cU8FDh+uqa7LAOshwvlcPNVb9qVXZxtt60+I
+OilRYw50G9PBYQay2A24fQlDcPe4wapJi8Zqhgi2cJi0yOnNqD2fwNKxdzyAmQqv
+jZAHa45jnBipljeQVqvNhdC/O2q/2+0ojpdwz/NW2nk4PtmwrM+W4XuSSJyxgtqH
+5lqaLmGj7UlkJEuFakOtNLjLTbH6BpkOqf9r4Q3qlV5xgNXDnGrNfCMxgQAn1xRh
+/sxcaQeEm6HM/i2VSdCilM9Td8W1S9E6jfiQyYb8B3E2o3bhQS0ktG8jpze/2GjQ
+IqJD9cXFvGOjVpCIfxHacV0G7wXWgSKeJx4fNihjZQKBgQDvxx7BIsOg35QD96Sl
+09Wk3zow+0jloqyZfw62OIgG3aUyTvIw3KFv8F6PCmAZG3OoeMnfbJT/sxK2X4IA
+4aTL+zdHhpGn3EwCgf7cfiYTRD8nPlVe8XrFU4SpdAEsF7o9NHgauXTL6F/Bfyz/
+HHDSuDnVe97xLtOBt95X7E+UtwKBgQDRGF1bt/jBfYkknJ4I5dpM7nsXO2WIZ06f
+my/xBlbK3OOKAFA96zcGD4ppuJtgyRwhYnkjPD4hoHxVLkcoHOkWBnCTwB+LQi/Q
+mQYMgwpQXpi8EbLvX6nf/K2A11acKeqb7RTD9EP1bhgrrVz4anxzG/xbYToPXW/b
+AAC0djVyrwKBgCODv7dlmco7M2Y/COES9kL8WVcl8Q8qQBxgKGKvDt7Nd4lzDgZU
+t4in9qmDJOazHTdn5Ka2I3+YG35tuQi+YzVfWTm74dkWFSAN9xzbhnI2GpCKeASf
+CcsuaqjaqM3KGei029FBhN4q5fv4BUcoBEIBzXckaMoaYHOHM2SceNETAoGBAM2p
+hmIpcQ53+IW/Wp3r3y1eQEoYjQR+gFHypVQP5RyB6XiaWFKe4a8faAgWoRWwme+o
+WPg0T/RpUwHBlBG7ZfPY/7AD/8LMphUp/k4eMe3dLaOGURarZH5AnTOmGrVdcTpP
+FeargpCL6lBDo7dfnermsu/6kM3+HIAu34Kg5m9XAoGACTkiGqNDHHuP+s3iC2uO
+xhnhJmnxbS/6sNy148LyfPNkdVWGPWuBiyxirsKF9L3iAUM13FLdo9n9DlwSl2Vd
+uLRso65t7jRa31RdcmKqHrIA/fun9/kEziyLSb402DKvp1rqsYNhHKXH3UYNPoQV
+8Dd1LdVSKpTRQuMpA7yA2q0=
-----END PRIVATE KEY-----
diff --git a/jstests/libs/ocsp/ca_ocsp.pem.digest.sha1 b/jstests/libs/ocsp/ca_ocsp.pem.digest.sha1
index cc9ebf3faff..e03788433b2 100644
--- a/jstests/libs/ocsp/ca_ocsp.pem.digest.sha1
+++ b/jstests/libs/ocsp/ca_ocsp.pem.digest.sha1
@@ -1 +1 @@
-71AE7CFF25964FA6E18220E66272C30DB3B20D68 \ No newline at end of file
+3C7C66BB50D271D0AA2995C03DE445CDA84497FC \ No newline at end of file
diff --git a/jstests/libs/ocsp/ca_ocsp.pem.digest.sha256 b/jstests/libs/ocsp/ca_ocsp.pem.digest.sha256
index ce9009de5f9..64f8f00b244 100644
--- a/jstests/libs/ocsp/ca_ocsp.pem.digest.sha256
+++ b/jstests/libs/ocsp/ca_ocsp.pem.digest.sha256
@@ -1 +1 @@
-1384027A47FBE288793724606ADEB3DAB541DC6EAA4427D6503D2C118053E4CC \ No newline at end of file
+7FF7B27A66BC0F3638B410545FB49D5FE045A8A49EE801C558824ABA0378A0A0 \ No newline at end of file
diff --git a/jstests/libs/ocsp/client_ocsp.pem b/jstests/libs/ocsp/client_ocsp.pem
index 89e6c005c18..fe53e4a0ad1 100644
--- a/jstests/libs/ocsp/client_ocsp.pem
+++ b/jstests/libs/ocsp/client_ocsp.pem
@@ -1,52 +1,52 @@
-----BEGIN CERTIFICATE-----
-MIID+jCCAuKgAwIBAgIEP62DRjANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIID+jCCAuKgAwIBAgIESOhoOjANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTQ0WhcNMjYwNDE4MTYxMTQ0WjBiMRAwDgYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ4WhcNMjYwOTA3MTYxNDQ4WjBiMRAwDgYD
VQQKDAdNb25nb0RCMQ8wDQYDVQQLDAZLZXJuZWwxEjAQBgNVBAMMCWxvY2FsaG9z
dDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMQ8wDQYDVQQHDAZPQ1NQLTIwggEi
-MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz5qAs9rnyXJ2Xf035AOyAVARe
-z0YM/kAdWxhE9hunwxx6BHlp91JB70dVJTU25sC51v2h1/q2k1vH7EsKJVxQ5guK
-P3V7dVZvQshjV45VQOu7yixKyYXTf3d82BP3InmB1piItg1ohAMbG2KwLXgkuOZY
-vvrnjiBF3SDHkXUFFEw2NVR0dLLSSElq5QtT9gnEMZEFxZwVKGr63ASqTijockHW
-krGJYf4TbMbAyQZx8yTOWPixkDKxLcUKPCuHFacHKgkyI9uErJUjShEuGF/MT5FJ
-O6g9QyjdHI4QAXVENrcwL6fb/aJBk4Dn/DLd8KdLTbVHbK9M9BobqXlCILP3AgMB
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC8xe5nazpzrywMxD6PyYwtbF1s
+IuHFzVo74Q1svWrL0ZxBTghlipT8MbUYOKasfoYoD1cKtQcKNk6rcVqTgaM9/Rxp
+okgJQ9t5Co/l3iUd3NxdzZA8u1DieUcoRSugRrbdZAWC77RuWv34AYWpOVeGl1Jx
+8ZXOocDzczuzf4+j4QzY/q3Idzran1Vb4fWVadVdtfmDpRJofN9eDVi2mhEdYEt4
+M8XktPENsUgrLeIsmzZGSavPbGgxmSqB5z8kpr/SNa4Cze0rh+XkuDsOtc0ksGWQ
+6PV6/aBiHSasJZucFPF2vTWPmYZLu184Meyy5mzUkbYuBI6uYCp/gVeMZCu9AgMB
AAGjgaUwgaIwCQYDVR0TBAIwADALBgNVHQ8EBAMCBaAwEwYDVR0lBAwwCgYIKwYB
-BQUHAwIwHQYDVR0OBBYEFNb4o1OY72yOL3e+NJrS13RWIt/oMDgGCCsGAQUFBwEB
+BQUHAwIwHQYDVR0OBBYEFAanEEZhMpxFkqjtdwXEyPz1jHQpMDgGCCsGAQUFBwEB
BCwwKjAoBggrBgEFBQcwAYYcaHR0cDovL2xvY2FsaG9zdDo4MTAwL3N0YXR1czAa
-BgNVHREEEzARgglsb2NhbGhvc3SHBH8AAAEwDQYJKoZIhvcNAQELBQADggEBAI7n
-v5XQlQxV4ZQ17C6AMFNU/t+Ddb7K7CtX9krbMEMKEYrHi8lM+DfZ2EXhR8WBrlon
-vyYpFPOXU39W2SYQqsSwUDUN7HBKrmu4oz6Fu0zoMbw7wfk38NKPtEGeL+3MnEps
-6ePgcqIdcJgdqKJAiVo+F6rOhrULd3v8WwD5GW38KwxHdO2XzddpMxkFZ+xDPiiu
-C3Zmka4Se803hf5xbtWYhJ8HuJyXmXsV/iZOyHpRMASOsQ9SAl5P8vAwOx1N/6K8
-kO8FcemHHHL7Ttn/wc+695gYx0xBtoW2m5n6imoKDK9YU5f7/EgJsmkAROPsaJjl
-GHNTBPT4PSlpE6X0/OE=
+BgNVHREEEzARgglsb2NhbGhvc3SHBH8AAAEwDQYJKoZIhvcNAQELBQADggEBAJ6/
+psehenRWBDcLieWeC54R3sKjGXnSvbBX05RDV2V1RQCrI5F4EPyzAdACT5nGr16o
+DB53OGTLMmGHotjgpB38bbi+scZYu0rwfcwst7fZ6hyq1N6uTKfmY45fykz4+Eih
+Ge6Su6CgOC0tm2u+QrwvTxfalKHNcNDLLM1o6DjitgDf6Ni2ROli6hH347pOf4p7
+Bieg9/eUhEitw5TABp9vN3J3f5zNq2q3wNxxjYfTsuOBroiC6TnPYI5PCe6wpQN3
+ceY/W23RNUrZXsgk1XESinYCoqSVgwM4ZMKuVgVcCm5vKGI9tCISkkoJDbciipRa
+zpcSoQV2cD/0kuIgLNE=
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCz5qAs9rnyXJ2X
-f035AOyAVARez0YM/kAdWxhE9hunwxx6BHlp91JB70dVJTU25sC51v2h1/q2k1vH
-7EsKJVxQ5guKP3V7dVZvQshjV45VQOu7yixKyYXTf3d82BP3InmB1piItg1ohAMb
-G2KwLXgkuOZYvvrnjiBF3SDHkXUFFEw2NVR0dLLSSElq5QtT9gnEMZEFxZwVKGr6
-3ASqTijockHWkrGJYf4TbMbAyQZx8yTOWPixkDKxLcUKPCuHFacHKgkyI9uErJUj
-ShEuGF/MT5FJO6g9QyjdHI4QAXVENrcwL6fb/aJBk4Dn/DLd8KdLTbVHbK9M9Bob
-qXlCILP3AgMBAAECggEAWDoADt0XV01lehFUX4w88DiEBi03yRJ9xgfRUKyz5mPx
-GMQN+VJyFGTxQkgjn1+uX9WYgKFH0vdUuSjgqkKlUgVn3m59wsTKVXlWhiW/536V
-vXyKmUjYqV8nbeIYdIiDN5JTLyS9UacAUPBux0EdXUESsq5CpYHVwP2P4F+tGIZH
-z4Krs5wS83jb2vOrnEMD0kLwAeSFfkIk82rx15glrt/lnl1lp1fdBcuW1DLOEoBm
-2N9t9Z1NWTaXEHw7FVeiYcZLr6I0b745FwQ5tRA10dRSyjvU7uN4x1IU85e4abYc
-EGrPrMuG5esJehdzJVq/5IB8McJORIqX7y0OqZRXZQKBgQDTZqfo/LGk2mFZIWl+
-LwnF8l6sRXZRhJgLrgGLLX+O1iTNaqdjQhu3CYWUqUWSPS1DpU5kizWSWSuSyVqC
-f6eoHw9ojqdfN+wuUhRa3uP7hkkOdHNEzmIbytGFM9rl9BukdB5EM4R2JHuNvYRU
-yzwQujDTNSH++9VFpHDgnMlgWwKBgQDZ2rYpyC/F0h4V+6j8w0AxF3XBn3AVjiIu
-sXDL5br+ZA8Xtunsd0iZscsGv3N5U0Fd1rVm64i/hdPw8Io1K0xmxHJ4WiEVEckC
-WTK+TtbDgtVTeH2y8j02jAkjREGTv/6LUzB87iddrzdsrORlpbqOVDmioc05MGvN
-3lcjs8UNlQKBgDvHN4vmiMU5C3YMwKvx2S2kT6kfK0n52JTU65LTltJpM5bypcqn
-kva7No7HHukva3FJeVVtGAT+OhgT4Agu2NXtkonabPG7+olOpHrdtFIXsujnfQDj
-61I4k+66rxd/Y6GpRDW866QMxPNbt+PSZHXGcLAIwkg8Jh6/VTvumfMpAoGAGXx3
-wS2VQSxSrrmxTFi/Qr7+3Lb9Utg88X96ta/bj3U/OsQAW9ScnrZpDRIKvU/bHtJG
-iJLXfah3YgGR+aRmHMOwrJnGswNQo8CxqgfpIhhFQq2e7vdd5+q8Cu8qSNG2QrBp
-xMPLwS8FaeZUFfwsdggucfNB4gXjJsNzKE8Yp30CgYAOrAKCq7yQvd4aw/aP7Y5f
-1cm1RBjyI83DUi4doSvjmIUcEq1EpDjJ5W+v7DhrZTIj7Y+gWBfbWyUVkfrch7eH
-fWAbBgvY3UOMZ+vB+s46rKKuyV5W1FMV/tRmZYGeiCbI+5G5LjLDTDM7uiOzHHIn
-GW9q6B8W54EdM5HBaiOodQ==
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC8xe5nazpzrywM
+xD6PyYwtbF1sIuHFzVo74Q1svWrL0ZxBTghlipT8MbUYOKasfoYoD1cKtQcKNk6r
+cVqTgaM9/RxpokgJQ9t5Co/l3iUd3NxdzZA8u1DieUcoRSugRrbdZAWC77RuWv34
+AYWpOVeGl1Jx8ZXOocDzczuzf4+j4QzY/q3Idzran1Vb4fWVadVdtfmDpRJofN9e
+DVi2mhEdYEt4M8XktPENsUgrLeIsmzZGSavPbGgxmSqB5z8kpr/SNa4Cze0rh+Xk
+uDsOtc0ksGWQ6PV6/aBiHSasJZucFPF2vTWPmYZLu184Meyy5mzUkbYuBI6uYCp/
+gVeMZCu9AgMBAAECggEAVPvGmEhtyCbUberrP1A9CzX92PDbM3F/bfWjVZDww1Fa
+RwwaO5xn9iFqpbzbTEypmN9PEELvKGnKgORHIqD6HK4WXHfydjlWVOesYI/hpdAI
+ZTJl/PFXOJ3gqwB4427yZDjjQk8nq4bLTxtgUQ6/mJgHRcS87IlllDQMbILA58Vj
+U0FiY7IoPubjjR5Zj3YF39fmia7AFaZ6XoAc1cRkzm0uuhvUz/xrGqTFLZV0WIcl
+C8hHGfHbsx4195hiUoE0SHvQs1QrjRUeptA44fJSvaTXoH/Nx0c7qee56xGFDnRo
+ObmKi7a7TTxXUZLIzWV9f8NMP8SsRxRY7LZoD9SLAQKBgQDdHmH8n5XMGwP6rpsP
+7tg3iEGBPWyWHQEKzKecnD8sL+GaXVzF5m9fnRE2Cq+K/f3lemcZ1cMzCc7xK6YQ
+2piPnFB03+XGbmWBXZ6PUkSUF3SKbWZMpNNKgOxAfQRWY3qotCXR9jAt1rXCRVoa
+vC43cJCYVPmPFxOve0YiJChR6wKBgQDajVAmAmK3n9KWMxdcFymWbMwndlkqEfOj
+qDaS0eA3gZuXxlcl7gSjkLIevWqcMop0ukbrFXzfUO+g/dXHvUCpvYe2Oncnj5e9
+adE0dqcvwB49Yg7Ap1YuBqU0UgP5+eiqGF9D5pbSCV0JHTyol1vuit6VNr6JwynF
++Ywasqzm9wKBgB3EtF5lQa57yJpcHWYUuqknP+JdWZwQBY7lpH8SDfMt8wpsHUxL
+TJ0rsSB8aculjCPzyaORwrjBTknrnWzRcQ6Mdcx2RCHlxOaYqvsSkUb6rWbheY9B
+9WwnVScNbaMPu3iw4BKXOT9Ck6+21H2a7gHqtpy7e+mGqtDKINQB2CfHAoGAZ+bo
+5Lkbn3q/DiNKBsEIR3h/8n7kUwjn0LVnBJP8yca3ZwenZOPslqpy1ARvS8UHaAkr
+MBYuIKkE03/6A5SoyknN3EedYFR26lkFWbDTOPNYLQySQOsNIKKOJfqb41r5Tux5
+VfmpWD+VWIDq1qfmz9h7i2rUWQBMus8x2Xt6ke8CgYAvb3R3gxNjRGZrD8Dz0hSN
+ZljNP2HUcsC9TeD6iqM99LMOJivnfcge9+94zqDbwkDO4pD/D4bMU3YEch2EX6mN
+FW8AQ3Grlqth3eAww4gwlhCF/2KWS9kW/22KhiWQe7EUA5mhQQWPq4oUh7DEE32f
+p8yKFNBy+489YZHAuhbXgQ==
-----END PRIVATE KEY-----
diff --git a/jstests/libs/ocsp/client_ocsp.pem.digest.sha1 b/jstests/libs/ocsp/client_ocsp.pem.digest.sha1
index dfe20c90a04..563b1ac69f8 100644
--- a/jstests/libs/ocsp/client_ocsp.pem.digest.sha1
+++ b/jstests/libs/ocsp/client_ocsp.pem.digest.sha1
@@ -1 +1 @@
-9EC70CC55B234E1D6AC1DCAA937D871388AB620B \ No newline at end of file
+0627534CB56EB75EAB2E5091574699A9B9C7FB2C \ No newline at end of file
diff --git a/jstests/libs/ocsp/client_ocsp.pem.digest.sha256 b/jstests/libs/ocsp/client_ocsp.pem.digest.sha256
index 39d2057df96..165ef4c5b75 100644
--- a/jstests/libs/ocsp/client_ocsp.pem.digest.sha256
+++ b/jstests/libs/ocsp/client_ocsp.pem.digest.sha256
@@ -1 +1 @@
-40311C11FB741BE9DB1057B3A1389316F7B2EF762C5E32A30EDF8460C73C0315 \ No newline at end of file
+092AAFBF5E0A2C52D4C1D690FC6F1B2FEDB28E96F4A24805BADCB39D79D74BAE \ No newline at end of file
diff --git a/jstests/libs/ocsp/intermediate_ca_only_ocsp.crt b/jstests/libs/ocsp/intermediate_ca_only_ocsp.crt
index 1d569169949..01f91cc2fbd 100644
--- a/jstests/libs/ocsp/intermediate_ca_only_ocsp.crt
+++ b/jstests/libs/ocsp/intermediate_ca_only_ocsp.crt
@@ -1,22 +1,22 @@
-----BEGIN CERTIFICATE-----
-MIIDojCCAoqgAwIBAgIEempRCjANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDojCCAoqgAwIBAgIEQSZGhjANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTQ0WhcNMjYwNDE4MTYxMTQ0WjB+MQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ4WhcNMjYwOTA3MTYxNDQ4WjB+MQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEhMB8GA1UEAwwY
SW50ZXJtZWRpYXRlIENBIGZvciBPQ1NQMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
-MIIBCgKCAQEAwz2A1Qy/3fKQoewviKGQitB9BAANd7cbLIGFJaJ29nFXHdxw7uOs
-x2IBy6ptxMWec3k9vWFdIo3A+NkCiOmyz6A3yvY5JQkJbIYsh9iI7OrNRrdIU1ws
-ke831iBiOVEbe87bVwPDXb3dsQoZb54WE//b68zREaMzscW/uteXsL5NQAgLMVpG
-O8uyTwvIssLRLO05562YlvEEg+jCMpHmsbTJOm2CP3S12T0XjhQyoRlUfZVH9O2x
-+d9PFyolHZoEVlofcHVbdEEZT9HoKyrxRYdbXcVmr4cWwaETbroxPjIvGVfYgdRc
-i7nxd3ccuM8l9R+vYdRwpQeQztYL0jgrMwIDAQABozIwMDAPBgNVHRMBAf8EBTAD
-AQH/MB0GA1UdDgQWBBSDmyhHjvx0m/C+iP/Q3Er31hEmTjANBgkqhkiG9w0BAQsF
-AAOCAQEAOrNK0MgTVUJtjePJk/k5IjtyQCLSs8cGU2FXm/CRiRMYcBhXMJwNUxLg
-o3rXpL/I/wnd/z/ZNONpD6kijkTHVDvGHDa9DeGvDEuYU44TalFgfe04Lgo5ptsU
-pJFasoFyO6/wohCC/VBRZlP5chKTBOAw1+W1/zflCO4utESglLFX9E8Y2VVV9enK
-FvuAhIeudwL7bcT3B26V44nGLiwoBPgYgpTRAOxxFAu48zZ2Pi6jmAiXJvxd8mQz
-dsizCb5NItQdMCeq4GH7gL7Rehzw1d+OlrK31ONSw0gZFIOnBE85jlhXfqF8BjN0
-vtoqfZI+nBTZff7y7CpRSHR4h8R5/g==
+MIIBCgKCAQEAwSDVG9MKJmbEAlZA6nEKMQi90dmNO922fhf2I1hHAKwlzi7O67hG
+MBe4hvhCZ7p/vmaTViwq0gBE5s1jy2Xq02IwIbunkyDwjHy56Y1LDvr/HtxPP5sz
+bU0K7SDBoCBAmnL6g5SbEQqRF8jrziyyRduUaZtp2JqQr6UQIYHOQgEKEmiMfSMW
+1q8ssk5rJBims+zOtHG9GVY9EBC8n19UnNI3E8Gyxla3AsN9nbqE40pUYRmO45DV
+11azoGCplqmuyoh1HGbYKiHMQ9E+dmRBJ0JjOdrMQvVrWGojRSI1qpr8w9C6pO3C
+DzHOsPMO0RKRK6A6aM9BThmcO1zERXkUkQIDAQABozIwMDAPBgNVHRMBAf8EBTAD
+AQH/MB0GA1UdDgQWBBTlKkzXC2qP7AZQLBZ+MuG23VQHQzANBgkqhkiG9w0BAQsF
+AAOCAQEAnyJRxd6QwnkyEjTD1/KyvCWZ04pREqZD9HV1db8DrDRXRKPuQ4nyUjst
+A/cmZUXlbgJ52rBSz10bpx+ZBzHEYqMmSKkrjoCM4OyNlSkTSpPOvzQIYBR2LPVP
+m0hl/UBueSeJ59Nh84v2jnbFY7e3izYg/rsMJgZvlTOfWKqbotaWD2Lb8KZ8iQpc
+Ht+5+Pzbf2ZgOEUNKdAPQjw1UV3/qp2XiaYOhBKzEKQ7waDWUmSPNh1tZgQzjZqO
+WPHmDiPpMV2j997+CBeVl7AJShbiElgjb/Pi9D/H9UW9QCtrPRIqYlb+IgwufNU0
+wnvUYw9sbQKn8jKzjgR4ApXXP0cLPA==
-----END CERTIFICATE-----
diff --git a/jstests/libs/ocsp/intermediate_ca_only_ocsp.key b/jstests/libs/ocsp/intermediate_ca_only_ocsp.key
index 2f211302867..107741282c7 100644
--- a/jstests/libs/ocsp/intermediate_ca_only_ocsp.key
+++ b/jstests/libs/ocsp/intermediate_ca_only_ocsp.key
@@ -1,28 +1,28 @@
-----BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDDPYDVDL/d8pCh
-7C+IoZCK0H0EAA13txssgYUlonb2cVcd3HDu46zHYgHLqm3ExZ5zeT29YV0ijcD4
-2QKI6bLPoDfK9jklCQlshiyH2Ijs6s1Gt0hTXCyR7zfWIGI5URt7zttXA8Ndvd2x
-ChlvnhYT/9vrzNERozOxxb+615ewvk1ACAsxWkY7y7JPC8iywtEs7TnnrZiW8QSD
-6MIykeaxtMk6bYI/dLXZPReOFDKhGVR9lUf07bH5308XKiUdmgRWWh9wdVt0QRlP
-0egrKvFFh1tdxWavhxbBoRNuujE+Mi8ZV9iB1FyLufF3dxy4zyX1H69h1HClB5DO
-1gvSOCszAgMBAAECggEAHotntW0aM1H4mKyHvztvjpgRhuevM7R81tioiPvC2sle
-lLhhHq6V4FeP6loOdENqh6xHIXKzDG3a69OfluXg6KSrNeCRjh68z7KqEtKokVAm
-r1KLSSdZfbdMJ/7G/yqWPydcn19iWC8VGNZ4pkK4N4bG1Dwl1TmQI9bJKSUDgU3u
-cgUoe3MM/I18PYHQvuZkqiAGO0i5R0jacwFj4ERNyMZd/ZTAjwSWlcbpgvxd/NvV
-r81i+taU2MtOxuAdasYLMpOzK8i7TO8LMSvAWspCsWMqoYSsSJ9EKCaGw4tCocy+
-0sEGFxnnGxnpkwj7iMKPXdYQCbyYxV8SvbYcv6ILEQKBgQDmXSjQv3pG1KczHBFp
-WDhDgTqQxVkpup8yZyH2VoQhsqRwrxVx4TGAAAcjQt3rVwUqjcovHTunDi9zqKJP
-2w78aSK9J5lueMC7rEn8OwsdYJ3e/SyrkZ0cL1t6fAHiOTVnRkOSSBoK2SLeuAwi
-fOD3Tne9wSSe1AWyF683Tj1nmwKBgQDY97SYSRakdAoV6HI9Ld6VJfNR1lPR3Bdz
-lgBtFqZf32zb+o8qXa9CEuZsS0PWQJH9jVdsoWzjaVLWAlIYDYyBO2tslZ00Bo3F
-Rt//Jmo/BFnEkY1GgexbNpieg6kMc9ZWuwndzhCN8i8Wnn7ptiXbvxB23RG7i6Y1
-YsMx9ArgSQKBgDG/gpX6E+UB/Y2rDROL6rKhUM184PGDDOgsn4f8TRKd6qcvGFl8
-gV0cJG53/UbahxIWhsg/7ub3yEWY8FyAeS8HYWoqCBd0WmLtJRkkgxT4DX/feuse
-SiiRDZdY+mspYaAI64TGr2ESXVZttqkoAMlHl9JRyJ/IN+aq+Lrf2aDrAoGAYJ+f
-u5oBDWfn/e2wwnIlCAMIo09xsKn1f7IzqmFF4rhbgHPLQjDKlgBYwa2bHlVPLr29
-S1Fwbq4/B7Os361Y/0x5ALh4c+zfQhXYN4biFgJX/+RaKCZAHjboLN+xbyw/LgzJ
-zg+w66YJNmeLWYWWwpAKQwUcmosMkAXVq+9k0JECgYA/toqcZWnEWUncZ2BMlSTR
-/TTypP+53YoTdsVJ7kwg0etpYlAEBNPqVv6c3m0rchWL+hfviZGx2/XWjds+oam6
-Y0UnXvbmgH3haPKjtje/Cui4xn1Gvz+3z7W7vsnLArEqBQ9JrY2VV03/XNleYycu
-ESf9ieaplW1k9Bz7UbrMUQ==
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDBINUb0womZsQC
+VkDqcQoxCL3R2Y073bZ+F/YjWEcArCXOLs7ruEYwF7iG+EJnun++ZpNWLCrSAETm
+zWPLZerTYjAhu6eTIPCMfLnpjUsO+v8e3E8/mzNtTQrtIMGgIECacvqDlJsRCpEX
+yOvOLLJF25Rpm2nYmpCvpRAhgc5CAQoSaIx9IxbWryyyTmskGKaz7M60cb0ZVj0Q
+ELyfX1Sc0jcTwbLGVrcCw32duoTjSlRhGY7jkNXXVrOgYKmWqa7KiHUcZtgqIcxD
+0T52ZEEnQmM52sxC9WtYaiNFIjWqmvzD0Lqk7cIPMc6w8w7REpEroDpoz0FOGZw7
+XMRFeRSRAgMBAAECggEAMEXBnrPQXKrhIWhnz3Gzx2/U6mgDWkxfugLJPippjOx6
+gp/Gjrq/qHO1Zt8U0hKWrYO8HhTqGxWAI2SBJizyViW7vCLIjwjzt1nRqmPrt/Ha
+5N7SXCax4wcXzQ+b9ic5nqFQpqT1YXwPqi9JaX5YjQeGgCMdgMuZkJ2ke4uTf4GN
+qlCUAM8crrVr33iNz1mceMFgq7hA54vrF3GowuORnI+3KddMlyixssd+Whd8Qsi+
+KEyVhL7VaVHnOdB9MjD68F1Rh5Rm9gDJKZm/lnRJ+2spIyn82JBUeDsOKulEWcsU
+KfPb+HjHpxHKTCK1vKYVDmUSPjgz5tiQ1bC2T4ydQQKBgQDrTz7SobPrGQyOFAqG
+UXKY5n5FvYfJssVXrE8FpmgWPGW1UmGLosBsCXxsI7S3E/h8qRG6eNBUL9CpxpyO
+V3dTyHQBcHqrGykHapBBW1ixqfeuo3y09fEE5m/XLOw/jKWesJN8ne2JY9Pw3ViI
+etBAjofYFQJs+tBGYazKq0p8qQKBgQDSHBjrzDn/SESz47Fw1ZiB4WgS9P4p2esD
+D7LFc3OqNPUpQwBg7HaSDrdONodKeBW9Ip3cLcw9k7faAKcR2AjQijXNqIxKZrnl
+PToIBr8aKPYuZsdcMgpumB38LJktuFLioVPPZH2aDIimXUzzNe2F0a5WzhjHZnxd
+hQXRn0MhqQKBgQCTBQE4cyXJpu3sO2NUBsF1/NU6V6/mepbIL3V0D0OLWRMnFiCy
+MO7O0aJ2olx/4q9nm+7itidb4kAaQ2h/mvCIXX71g0RxcdfRtWgKHbutzYdeCvGY
+0u1S5XNNWtkE36h/HM4Zl0bZh5DdNj7hjvJc03DWtlG8q3zD7LUcL6ereQKBgQCI
+3BZ7mbb5i1h9GMafKfLCP1IsbvsTxcfoYZRgO1jPONmsu+EGQWDmuME8KBauMlRu
+s5rCLe7I+WybiytIW0E6nZx4Tt67I/jY0q33RnW6k43wIbCgZFQZP+rgNSi9+D+9
+MbrG771E1/825rVWAv2p2jBGiM7pK9+8hwaIScZPqQKBgDvRCQ+RnIoOVf0Dg81i
+Kq71E5SC19gaZmrC+yHyQrwkP+4Y+om20gEigRrijWEcoiYXQ8pPIAX8QCw5RIx6
+47t9K72LHwv/4eNfiD5cbv9JQiiV9ETennbbtt/mHG7LoMQMGSFAEHjikmeX6HMP
+eRC/ysTqGxqkkxWJ8qejvxUF
-----END PRIVATE KEY-----
diff --git a/jstests/libs/ocsp/intermediate_ca_only_ocsp.pem b/jstests/libs/ocsp/intermediate_ca_only_ocsp.pem
index 493ce6a4eaf..b4575552816 100644
--- a/jstests/libs/ocsp/intermediate_ca_only_ocsp.pem
+++ b/jstests/libs/ocsp/intermediate_ca_only_ocsp.pem
@@ -1,50 +1,50 @@
-----BEGIN CERTIFICATE-----
-MIIDojCCAoqgAwIBAgIEempRCjANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDojCCAoqgAwIBAgIEQSZGhjANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTQ0WhcNMjYwNDE4MTYxMTQ0WjB+MQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ4WhcNMjYwOTA3MTYxNDQ4WjB+MQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEhMB8GA1UEAwwY
SW50ZXJtZWRpYXRlIENBIGZvciBPQ1NQMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
-MIIBCgKCAQEAwz2A1Qy/3fKQoewviKGQitB9BAANd7cbLIGFJaJ29nFXHdxw7uOs
-x2IBy6ptxMWec3k9vWFdIo3A+NkCiOmyz6A3yvY5JQkJbIYsh9iI7OrNRrdIU1ws
-ke831iBiOVEbe87bVwPDXb3dsQoZb54WE//b68zREaMzscW/uteXsL5NQAgLMVpG
-O8uyTwvIssLRLO05562YlvEEg+jCMpHmsbTJOm2CP3S12T0XjhQyoRlUfZVH9O2x
-+d9PFyolHZoEVlofcHVbdEEZT9HoKyrxRYdbXcVmr4cWwaETbroxPjIvGVfYgdRc
-i7nxd3ccuM8l9R+vYdRwpQeQztYL0jgrMwIDAQABozIwMDAPBgNVHRMBAf8EBTAD
-AQH/MB0GA1UdDgQWBBSDmyhHjvx0m/C+iP/Q3Er31hEmTjANBgkqhkiG9w0BAQsF
-AAOCAQEAOrNK0MgTVUJtjePJk/k5IjtyQCLSs8cGU2FXm/CRiRMYcBhXMJwNUxLg
-o3rXpL/I/wnd/z/ZNONpD6kijkTHVDvGHDa9DeGvDEuYU44TalFgfe04Lgo5ptsU
-pJFasoFyO6/wohCC/VBRZlP5chKTBOAw1+W1/zflCO4utESglLFX9E8Y2VVV9enK
-FvuAhIeudwL7bcT3B26V44nGLiwoBPgYgpTRAOxxFAu48zZ2Pi6jmAiXJvxd8mQz
-dsizCb5NItQdMCeq4GH7gL7Rehzw1d+OlrK31ONSw0gZFIOnBE85jlhXfqF8BjN0
-vtoqfZI+nBTZff7y7CpRSHR4h8R5/g==
+MIIBCgKCAQEAwSDVG9MKJmbEAlZA6nEKMQi90dmNO922fhf2I1hHAKwlzi7O67hG
+MBe4hvhCZ7p/vmaTViwq0gBE5s1jy2Xq02IwIbunkyDwjHy56Y1LDvr/HtxPP5sz
+bU0K7SDBoCBAmnL6g5SbEQqRF8jrziyyRduUaZtp2JqQr6UQIYHOQgEKEmiMfSMW
+1q8ssk5rJBims+zOtHG9GVY9EBC8n19UnNI3E8Gyxla3AsN9nbqE40pUYRmO45DV
+11azoGCplqmuyoh1HGbYKiHMQ9E+dmRBJ0JjOdrMQvVrWGojRSI1qpr8w9C6pO3C
+DzHOsPMO0RKRK6A6aM9BThmcO1zERXkUkQIDAQABozIwMDAPBgNVHRMBAf8EBTAD
+AQH/MB0GA1UdDgQWBBTlKkzXC2qP7AZQLBZ+MuG23VQHQzANBgkqhkiG9w0BAQsF
+AAOCAQEAnyJRxd6QwnkyEjTD1/KyvCWZ04pREqZD9HV1db8DrDRXRKPuQ4nyUjst
+A/cmZUXlbgJ52rBSz10bpx+ZBzHEYqMmSKkrjoCM4OyNlSkTSpPOvzQIYBR2LPVP
+m0hl/UBueSeJ59Nh84v2jnbFY7e3izYg/rsMJgZvlTOfWKqbotaWD2Lb8KZ8iQpc
+Ht+5+Pzbf2ZgOEUNKdAPQjw1UV3/qp2XiaYOhBKzEKQ7waDWUmSPNh1tZgQzjZqO
+WPHmDiPpMV2j997+CBeVl7AJShbiElgjb/Pi9D/H9UW9QCtrPRIqYlb+IgwufNU0
+wnvUYw9sbQKn8jKzjgR4ApXXP0cLPA==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDDPYDVDL/d8pCh
-7C+IoZCK0H0EAA13txssgYUlonb2cVcd3HDu46zHYgHLqm3ExZ5zeT29YV0ijcD4
-2QKI6bLPoDfK9jklCQlshiyH2Ijs6s1Gt0hTXCyR7zfWIGI5URt7zttXA8Ndvd2x
-ChlvnhYT/9vrzNERozOxxb+615ewvk1ACAsxWkY7y7JPC8iywtEs7TnnrZiW8QSD
-6MIykeaxtMk6bYI/dLXZPReOFDKhGVR9lUf07bH5308XKiUdmgRWWh9wdVt0QRlP
-0egrKvFFh1tdxWavhxbBoRNuujE+Mi8ZV9iB1FyLufF3dxy4zyX1H69h1HClB5DO
-1gvSOCszAgMBAAECggEAHotntW0aM1H4mKyHvztvjpgRhuevM7R81tioiPvC2sle
-lLhhHq6V4FeP6loOdENqh6xHIXKzDG3a69OfluXg6KSrNeCRjh68z7KqEtKokVAm
-r1KLSSdZfbdMJ/7G/yqWPydcn19iWC8VGNZ4pkK4N4bG1Dwl1TmQI9bJKSUDgU3u
-cgUoe3MM/I18PYHQvuZkqiAGO0i5R0jacwFj4ERNyMZd/ZTAjwSWlcbpgvxd/NvV
-r81i+taU2MtOxuAdasYLMpOzK8i7TO8LMSvAWspCsWMqoYSsSJ9EKCaGw4tCocy+
-0sEGFxnnGxnpkwj7iMKPXdYQCbyYxV8SvbYcv6ILEQKBgQDmXSjQv3pG1KczHBFp
-WDhDgTqQxVkpup8yZyH2VoQhsqRwrxVx4TGAAAcjQt3rVwUqjcovHTunDi9zqKJP
-2w78aSK9J5lueMC7rEn8OwsdYJ3e/SyrkZ0cL1t6fAHiOTVnRkOSSBoK2SLeuAwi
-fOD3Tne9wSSe1AWyF683Tj1nmwKBgQDY97SYSRakdAoV6HI9Ld6VJfNR1lPR3Bdz
-lgBtFqZf32zb+o8qXa9CEuZsS0PWQJH9jVdsoWzjaVLWAlIYDYyBO2tslZ00Bo3F
-Rt//Jmo/BFnEkY1GgexbNpieg6kMc9ZWuwndzhCN8i8Wnn7ptiXbvxB23RG7i6Y1
-YsMx9ArgSQKBgDG/gpX6E+UB/Y2rDROL6rKhUM184PGDDOgsn4f8TRKd6qcvGFl8
-gV0cJG53/UbahxIWhsg/7ub3yEWY8FyAeS8HYWoqCBd0WmLtJRkkgxT4DX/feuse
-SiiRDZdY+mspYaAI64TGr2ESXVZttqkoAMlHl9JRyJ/IN+aq+Lrf2aDrAoGAYJ+f
-u5oBDWfn/e2wwnIlCAMIo09xsKn1f7IzqmFF4rhbgHPLQjDKlgBYwa2bHlVPLr29
-S1Fwbq4/B7Os361Y/0x5ALh4c+zfQhXYN4biFgJX/+RaKCZAHjboLN+xbyw/LgzJ
-zg+w66YJNmeLWYWWwpAKQwUcmosMkAXVq+9k0JECgYA/toqcZWnEWUncZ2BMlSTR
-/TTypP+53YoTdsVJ7kwg0etpYlAEBNPqVv6c3m0rchWL+hfviZGx2/XWjds+oam6
-Y0UnXvbmgH3haPKjtje/Cui4xn1Gvz+3z7W7vsnLArEqBQ9JrY2VV03/XNleYycu
-ESf9ieaplW1k9Bz7UbrMUQ==
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDBINUb0womZsQC
+VkDqcQoxCL3R2Y073bZ+F/YjWEcArCXOLs7ruEYwF7iG+EJnun++ZpNWLCrSAETm
+zWPLZerTYjAhu6eTIPCMfLnpjUsO+v8e3E8/mzNtTQrtIMGgIECacvqDlJsRCpEX
+yOvOLLJF25Rpm2nYmpCvpRAhgc5CAQoSaIx9IxbWryyyTmskGKaz7M60cb0ZVj0Q
+ELyfX1Sc0jcTwbLGVrcCw32duoTjSlRhGY7jkNXXVrOgYKmWqa7KiHUcZtgqIcxD
+0T52ZEEnQmM52sxC9WtYaiNFIjWqmvzD0Lqk7cIPMc6w8w7REpEroDpoz0FOGZw7
+XMRFeRSRAgMBAAECggEAMEXBnrPQXKrhIWhnz3Gzx2/U6mgDWkxfugLJPippjOx6
+gp/Gjrq/qHO1Zt8U0hKWrYO8HhTqGxWAI2SBJizyViW7vCLIjwjzt1nRqmPrt/Ha
+5N7SXCax4wcXzQ+b9ic5nqFQpqT1YXwPqi9JaX5YjQeGgCMdgMuZkJ2ke4uTf4GN
+qlCUAM8crrVr33iNz1mceMFgq7hA54vrF3GowuORnI+3KddMlyixssd+Whd8Qsi+
+KEyVhL7VaVHnOdB9MjD68F1Rh5Rm9gDJKZm/lnRJ+2spIyn82JBUeDsOKulEWcsU
+KfPb+HjHpxHKTCK1vKYVDmUSPjgz5tiQ1bC2T4ydQQKBgQDrTz7SobPrGQyOFAqG
+UXKY5n5FvYfJssVXrE8FpmgWPGW1UmGLosBsCXxsI7S3E/h8qRG6eNBUL9CpxpyO
+V3dTyHQBcHqrGykHapBBW1ixqfeuo3y09fEE5m/XLOw/jKWesJN8ne2JY9Pw3ViI
+etBAjofYFQJs+tBGYazKq0p8qQKBgQDSHBjrzDn/SESz47Fw1ZiB4WgS9P4p2esD
+D7LFc3OqNPUpQwBg7HaSDrdONodKeBW9Ip3cLcw9k7faAKcR2AjQijXNqIxKZrnl
+PToIBr8aKPYuZsdcMgpumB38LJktuFLioVPPZH2aDIimXUzzNe2F0a5WzhjHZnxd
+hQXRn0MhqQKBgQCTBQE4cyXJpu3sO2NUBsF1/NU6V6/mepbIL3V0D0OLWRMnFiCy
+MO7O0aJ2olx/4q9nm+7itidb4kAaQ2h/mvCIXX71g0RxcdfRtWgKHbutzYdeCvGY
+0u1S5XNNWtkE36h/HM4Zl0bZh5DdNj7hjvJc03DWtlG8q3zD7LUcL6ereQKBgQCI
+3BZ7mbb5i1h9GMafKfLCP1IsbvsTxcfoYZRgO1jPONmsu+EGQWDmuME8KBauMlRu
+s5rCLe7I+WybiytIW0E6nZx4Tt67I/jY0q33RnW6k43wIbCgZFQZP+rgNSi9+D+9
+MbrG771E1/825rVWAv2p2jBGiM7pK9+8hwaIScZPqQKBgDvRCQ+RnIoOVf0Dg81i
+Kq71E5SC19gaZmrC+yHyQrwkP+4Y+om20gEigRrijWEcoiYXQ8pPIAX8QCw5RIx6
+47t9K72LHwv/4eNfiD5cbv9JQiiV9ETennbbtt/mHG7LoMQMGSFAEHjikmeX6HMP
+eRC/ysTqGxqkkxWJ8qejvxUF
-----END PRIVATE KEY-----
diff --git a/jstests/libs/ocsp/intermediate_ca_only_ocsp.pem.digest.sha1 b/jstests/libs/ocsp/intermediate_ca_only_ocsp.pem.digest.sha1
index 50e567599a1..c071871173f 100644
--- a/jstests/libs/ocsp/intermediate_ca_only_ocsp.pem.digest.sha1
+++ b/jstests/libs/ocsp/intermediate_ca_only_ocsp.pem.digest.sha1
@@ -1 +1 @@
-70EE47631AC81BE17E10117F48DDD55470ABF7E5 \ No newline at end of file
+230662BB96A401DD5A83E197721EBAE20C92574C \ No newline at end of file
diff --git a/jstests/libs/ocsp/intermediate_ca_only_ocsp.pem.digest.sha256 b/jstests/libs/ocsp/intermediate_ca_only_ocsp.pem.digest.sha256
index 4ae11c0677b..ba64ae7dc03 100644
--- a/jstests/libs/ocsp/intermediate_ca_only_ocsp.pem.digest.sha256
+++ b/jstests/libs/ocsp/intermediate_ca_only_ocsp.pem.digest.sha256
@@ -1 +1 @@
-7C98959C6CF9C0D3F764FAFDB611BD56D20DA2DF6471EE49791585F24B616238 \ No newline at end of file
+18B9760DDE07FAC5E6B7053A8167B486F9A4842296CE74DA929905CFA4DC216C \ No newline at end of file
diff --git a/jstests/libs/ocsp/intermediate_ca_with_root_ocsp.pem b/jstests/libs/ocsp/intermediate_ca_with_root_ocsp.pem
index 35dff741069..f610d7799e2 100644
--- a/jstests/libs/ocsp/intermediate_ca_with_root_ocsp.pem
+++ b/jstests/libs/ocsp/intermediate_ca_with_root_ocsp.pem
@@ -1,44 +1,44 @@
-----BEGIN CERTIFICATE-----
-MIIDojCCAoqgAwIBAgIEempRCjANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDojCCAoqgAwIBAgIEQSZGhjANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTQ0WhcNMjYwNDE4MTYxMTQ0WjB+MQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ4WhcNMjYwOTA3MTYxNDQ4WjB+MQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEhMB8GA1UEAwwY
SW50ZXJtZWRpYXRlIENBIGZvciBPQ1NQMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
-MIIBCgKCAQEAwz2A1Qy/3fKQoewviKGQitB9BAANd7cbLIGFJaJ29nFXHdxw7uOs
-x2IBy6ptxMWec3k9vWFdIo3A+NkCiOmyz6A3yvY5JQkJbIYsh9iI7OrNRrdIU1ws
-ke831iBiOVEbe87bVwPDXb3dsQoZb54WE//b68zREaMzscW/uteXsL5NQAgLMVpG
-O8uyTwvIssLRLO05562YlvEEg+jCMpHmsbTJOm2CP3S12T0XjhQyoRlUfZVH9O2x
-+d9PFyolHZoEVlofcHVbdEEZT9HoKyrxRYdbXcVmr4cWwaETbroxPjIvGVfYgdRc
-i7nxd3ccuM8l9R+vYdRwpQeQztYL0jgrMwIDAQABozIwMDAPBgNVHRMBAf8EBTAD
-AQH/MB0GA1UdDgQWBBSDmyhHjvx0m/C+iP/Q3Er31hEmTjANBgkqhkiG9w0BAQsF
-AAOCAQEAOrNK0MgTVUJtjePJk/k5IjtyQCLSs8cGU2FXm/CRiRMYcBhXMJwNUxLg
-o3rXpL/I/wnd/z/ZNONpD6kijkTHVDvGHDa9DeGvDEuYU44TalFgfe04Lgo5ptsU
-pJFasoFyO6/wohCC/VBRZlP5chKTBOAw1+W1/zflCO4utESglLFX9E8Y2VVV9enK
-FvuAhIeudwL7bcT3B26V44nGLiwoBPgYgpTRAOxxFAu48zZ2Pi6jmAiXJvxd8mQz
-dsizCb5NItQdMCeq4GH7gL7Rehzw1d+OlrK31ONSw0gZFIOnBE85jlhXfqF8BjN0
-vtoqfZI+nBTZff7y7CpRSHR4h8R5/g==
+MIIBCgKCAQEAwSDVG9MKJmbEAlZA6nEKMQi90dmNO922fhf2I1hHAKwlzi7O67hG
+MBe4hvhCZ7p/vmaTViwq0gBE5s1jy2Xq02IwIbunkyDwjHy56Y1LDvr/HtxPP5sz
+bU0K7SDBoCBAmnL6g5SbEQqRF8jrziyyRduUaZtp2JqQr6UQIYHOQgEKEmiMfSMW
+1q8ssk5rJBims+zOtHG9GVY9EBC8n19UnNI3E8Gyxla3AsN9nbqE40pUYRmO45DV
+11azoGCplqmuyoh1HGbYKiHMQ9E+dmRBJ0JjOdrMQvVrWGojRSI1qpr8w9C6pO3C
+DzHOsPMO0RKRK6A6aM9BThmcO1zERXkUkQIDAQABozIwMDAPBgNVHRMBAf8EBTAD
+AQH/MB0GA1UdDgQWBBTlKkzXC2qP7AZQLBZ+MuG23VQHQzANBgkqhkiG9w0BAQsF
+AAOCAQEAnyJRxd6QwnkyEjTD1/KyvCWZ04pREqZD9HV1db8DrDRXRKPuQ4nyUjst
+A/cmZUXlbgJ52rBSz10bpx+ZBzHEYqMmSKkrjoCM4OyNlSkTSpPOvzQIYBR2LPVP
+m0hl/UBueSeJ59Nh84v2jnbFY7e3izYg/rsMJgZvlTOfWKqbotaWD2Lb8KZ8iQpc
+Ht+5+Pzbf2ZgOEUNKdAPQjw1UV3/qp2XiaYOhBKzEKQ7waDWUmSPNh1tZgQzjZqO
+WPHmDiPpMV2j997+CBeVl7AJShbiElgjb/Pi9D/H9UW9QCtrPRIqYlb+IgwufNU0
+wnvUYw9sbQKn8jKzjgR4ApXXP0cLPA==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
-MIIDeTCCAmGgAwIBAgIEB9wTPzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDeTCCAmGgAwIBAgIEaS5ADzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTQzWhcNMjYwNDE4MTYxMTQzWjB0MQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ4WhcNMjYwOTA3MTYxNDQ4WjB0MQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwO
-S2VybmVsIFRlc3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCe
-ytoe84QvjltBg5/lNoKxXMUAd8Kg9AUxc9cfnBvdtwpmNSLkiNj/zgwtdCvfHqkt
-16rPBm5XXCb1IdSBS5+IUwfvav8FHdkEc+h/KcLCR3CXwEONtEWCpAhEp/2qz6z1
-TXu3KxYwlsqFFregnk/LSzD1SZEhrostXxH96SjLvwYMtyprzebHBb23ezr1wv3s
-NlE/SVm9X8IvTrosvvVSuKvp4PSa9bqg76GE6CXEUbfTIXwobnqhGcRoWuNXH4MG
-Yp4hs177RNiuSnEvUzxs7K8B3rOyGqmCndYErOD0U8uZy61bG7SZi/ccGRoTmhCa
-KYO4ZVUBQVW/RW6P71kFAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
-hvcNAQELBQADggEBAHyfVvg4s8wTHzJZ5vgopIXbZWzFtgQts8wslTktkt9itpfF
-Oou67JQqn8egFMJt56fRy7BCAIIEDFfrtp1PSic8CZDRB6Ks9+/fIHfYIkm9eHZl
-TbR4Zz0hpk8BNqfsk/CH8pp2/7l9nowh2mLZa+5Zfk+ImZGsib+aqUCkTq+xboai
-YDuq2OWctC+9YqIQBgIu0PB+uwcdqhLAwdwtXuVRYV2ZJgs+ruUvdTKw1ztMI2dn
-+dzMSEKHFTOJl8goRPl0xi5ToJEK5/qfaDTXt2x991VTrnFJGNlS9esaKaDSsWA3
-JNQdt3Ar/o0SRs+MHAhoHFtevq0tU5wXB0mF/Gc=
+S2VybmVsIFRlc3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDD
+2GI3zcFmEpeZhPndIW42gT4VwRkpWLEtogykbFhCrDCXaici313xjXm/TIypRxxC
+K84wKlNYx2AAgRdgehdKkLSEgDYFL64PcF0hXCFocmVrJDr0+BMI+JsA3RxQ6mAM
+xD18flNxx8GhL8zFPXYkMG8cP/X5oaVnTXk8fvyZbKJG1HyVDHXds2T3jI9O04HQ
+oYbm4n27SV09LCMiav7jaXdc+OdwTTnW1E7x9E3XsfWFqY2v8RnlDYA8TK6QyiGG
+XsHVdex41Yg3zqKwgP5h5EjXPr5KD6ChVEMnExitkHUIuI+SxaaE0S+B7jS2jCQv
+6EQP9f8uStHJUQgegycZAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAJEs7uxFM5UudRNEX1Qo+wvp0y7bMJbf6ECjAL9dJ688Cp6I
+GgKXWA5ltJNDXR8aQmVYafA7dDiu6Hs7F7y+MP9ulV+MqCoVuJF82QK4jcwxgx11
+fRxbTGgh9WX2f/w0zVJ6sp4QHYDq3vgE1f+2AV1v4OdDnXV9O+wrUOmDTCt5RNa0
+Qo6FCeFG929+LKjR1VmlCCHNMO0+s4UdxBo9AQRq/+mOiPXw63jXckwGOxgpReA9
+lhQVC4rAHfPiYxegaJwwcU3gGbwxMZPTMHkUbKRaMEJJGHs8vCKZ/pK9ivTx/Sys
+eA+6l3QJeLuhA+Ifs78oJ8emAdCpgMgS5nhjbVQ=
-----END CERTIFICATE-----
diff --git a/jstests/libs/ocsp/intermediate_ca_with_root_ocsp.pem.digest.sha1 b/jstests/libs/ocsp/intermediate_ca_with_root_ocsp.pem.digest.sha1
index 50e567599a1..c071871173f 100644
--- a/jstests/libs/ocsp/intermediate_ca_with_root_ocsp.pem.digest.sha1
+++ b/jstests/libs/ocsp/intermediate_ca_with_root_ocsp.pem.digest.sha1
@@ -1 +1 @@
-70EE47631AC81BE17E10117F48DDD55470ABF7E5 \ No newline at end of file
+230662BB96A401DD5A83E197721EBAE20C92574C \ No newline at end of file
diff --git a/jstests/libs/ocsp/intermediate_ca_with_root_ocsp.pem.digest.sha256 b/jstests/libs/ocsp/intermediate_ca_with_root_ocsp.pem.digest.sha256
index 4ae11c0677b..ba64ae7dc03 100644
--- a/jstests/libs/ocsp/intermediate_ca_with_root_ocsp.pem.digest.sha256
+++ b/jstests/libs/ocsp/intermediate_ca_with_root_ocsp.pem.digest.sha256
@@ -1 +1 @@
-7C98959C6CF9C0D3F764FAFDB611BD56D20DA2DF6471EE49791585F24B616238 \ No newline at end of file
+18B9760DDE07FAC5E6B7053A8167B486F9A4842296CE74DA929905CFA4DC216C \ No newline at end of file
diff --git a/jstests/libs/ocsp/ocsp_responder.crt b/jstests/libs/ocsp/ocsp_responder.crt
index 7ed6052ca5b..338819039ab 100644
--- a/jstests/libs/ocsp/ocsp_responder.crt
+++ b/jstests/libs/ocsp/ocsp_responder.crt
@@ -1,21 +1,21 @@
-----BEGIN CERTIFICATE-----
-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
+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
-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
+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
-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
+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
-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
+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
-----END CERTIFICATE-----
diff --git a/jstests/libs/ocsp/ocsp_responder.key b/jstests/libs/ocsp/ocsp_responder.key
index 5a12b50754c..c93d9eb64a2 100644
--- a/jstests/libs/ocsp/ocsp_responder.key
+++ b/jstests/libs/ocsp/ocsp_responder.key
@@ -1,28 +1,28 @@
-----BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCTxkpn+Y8n6Q1w
-6x2+L9hTRzQ9iz+a4kxs5ltnWYm59jvmHahXq/pneguFmxjuIpQf8CeTLg6muVk1
-uCIUScmbRhayoAuuLlwXyrbMG+7IWj0rgPvZmj1BrJrxr0jjJ+au2099mjnHP6Ms
-sZlF3HWLhpiCAcIY/CfS2GlVNTQx7XGJs9dce1fGFc+nK5zCuaCBAZvMZhsQrhgA
-T0pqqBAN8kP1lK/k+GpGVJ8ZwMjb4AXC9F7xXXJ1xnWaqy3O8xwelLtmecFwdN5G
-0ats4cCWFkY9hrKt29UAFU5CXDMkmMxL1GuekP6OAmPfC+uOJzN+vf1RLtS6QYtt
-DCATmD3NAgMBAAECgf9O9pTXenGhuTJvqhvjUHN8OyGdqgrkSfyvkWg6kYxeEl5Y
-QS9QY/hYu4cybu4vC8smou1reB9/AzpcourYyZUCuwKI2U4es5t2pspBO06/+r4d
-wQMBeGPxxXKR1bVolTVX6M0inFg31HI0Xj33VrlhoL7R/1iygSKAvIwYJK0t6JfF
-7dRNqPOwKSq3U2qtBeYfns1ace8X80PumYQMfcGCDP0wl5IQSEvgA8GHSpwn5wLl
-/K5wmHliEzLtI4ByS5ry0dF7ZVMfhPa/AFuO70VU4rv32OWM2fc64hUuIefdlxb8
-U5z4EvEpqnuuJn9xxwebqsbltc3sRvNfrnO3hdECgYEAxFq60HA69vqiFH1p6+8K
-K80aT61FxfbIeTfSAFjY0fbMAW/LtshztQIZD1XCD94h+TGVFr9V6DHDddhcwPbi
-BbF9EIgP3OCfvNtVbsh5HrOoH1eHjVQM6qKxm9gsmWqL5GFPm3lKD3pMlQXFr3k7
-KQ6PjoLTVAjfPdKz7f0B7V0CgYEAwKnOhBW9f1G6LiUMmJ972io756r6BsUifgqJ
-+fWOG9qFPUQtM5lpiXYttMXR+ZxdD57F2PDnrKveLtbl43n7o8V8pkOJbjPUdRgE
-fD5LmuD9MP8xdYC6g0j1jJzoHRG3akMkSxALLDhiITklk7uZnp8GB6xQPLC4lPHB
-crblGzECgYEAoDi8ubrqkn//Y6LWnJuofAdX0e48wgXWnfsrk/brraCp5P45h4PX
-zrrQgg/jU5lZtYJ8+lvUmKyKpw2O2jJaSnUC7UtpTj3Ieo2rD8Pr+V518GU3Cd6s
-z4VEUju6YNFtJ0U0dVQqV6je9rcIEWBmIuFryMj98lNu/n6BLdBHE00CgYAGtuRH
-nipYgZSnfwsNVqGOXOJxlHfaPIyTL/LXD0PAnMD//ZxFrBcNf1zga/SBan2jybjD
-csHgNq0rnLmuT9YBQySw9rGXcZ755bhiTBl+cFDioEItAit939EO8Xj1amSmA2kE
-ZK6+/8gLuF4i4+raqFghdFPniZElP7eqM82QQQKBgQCl7kdTXAyst5xrr10Hz5lt
-ZOjCJC2OYZP8lfWTRmEKoLD03UHSQ/DryWbtvGPafVp6bZ/ELY2bdX0ncfj0osGk
-HiQMo/KnTbKoCjTl81g4Ipml+B0cBrI6NacAFVR/vAmx6n7uMDg4Q8Lgw2u3gkV2
-Je4OlZooBshiuej7ZcbJiQ==
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCoKWJ7jqajAL+F
+trafse1qBCAmDDUmBY+M9nGhqhSP5Ndwv6Jp55/IjQDe9mHNtrSvwgvZ/nMFvTCt
+TwbdxkU7ukgKHQx/94cP50iJGWPgNGN3Ey8+5BC7146m/aQ0dcpLX4Hz5CN7P14B
+MlWrlhyWzoJ5Y1DOJTVo9dO1QnMvfPVkHpWPFhvxOUr7VH5vR2A5hGVxIjXRJGf0
++tgtYQ8SMXtA1lBjndksEx23EIVtgyhlIAqgMg7R54CQG7jKVWt2YRBcrzeXHuxh
+0o/TY67R/h8PD4qCvFSKzz3l0Rqo9XTb61Wa+cyNpP9AUWBWupp80h3u1IU9yakC
+v52n+gmhAgMBAAECggEAXzsglIxSfhkcXSL+BS4EH3e6pRFgv+mCQ/gEneLtxhd4
+kldUKNmNOUvw5FNvS8peRPKFN6zLgsKDYIJShyGTb6Gszl1pCMcq66y0/T8tuniw
+o2xv4xPRDi+ij5swdK0IJOsvcukN1uwp1k+lCIj4I8dLSGcgCb40ov4kKJA7Hvag
+F0JXji/R0+VDvd909ObTuX/xKtrWwLdHZOTkpa6hQYFiz22K1CoQu9mQ3EhXGhuL
+7Kl9Cl/hUEFORx8vjgxwjc0Wqpxqs04npr6DudMsSV2Y7/GNCAQqv8srOs5zxhKc
+94HRMGOjwxYubRxN07zJoa3OdWKLNsLJvZQMBvsm4QKBgQDRAA8pmP5nF1cIXYpT
+IKn1vsQeoDmtSOcI3Xz8ZhsU9YStugyw6T9XEBHZO67cl3JwRer291MeDRu2Lk/m
+WnkfuYM3KnGzTV1q62hD/5X8Kx/JZZf12IpiBJx85zCsTo7uyBWt5wA4RfB13WAA
+awkz55Q1/zuink+Ixc1YymwftQKBgQDN+knW3xmft/elPsJa9CWHuS1hGr2shvvw
+fk5n3bWkzP0d+aw1pGlDLPic6T0+fCEJ9FJaQFZXXRsmxDO1wwFKcHhzEkvwCBWN
+2DWNq45q+zpOVv7INQlwYRppb5I+1p/yUJj+AVVbyH+0MsO4LtSjaswmE2AZel4a
+qYfo4oa9vQKBgQC6IbFfPJAlQ9YQ7y2HxulWoKSNGekD+I85h/gN2Ol5iwa0qaMv
+0yrD4N3kd5DNiFs0vi/57l4pv0bUwv4Jir2gkVjYwoYsR1RRKoHbPT5YLBfNBxuE
+qWrkzHKJkmP4sKX+5lbYX4gEldUHQzaCaNDzVuTaCgsUUqVGi9LLpssQmQKBgH4V
+qN97/95yKYigiy5L5zFWnD2ltdeHZW9IkcwovkkcJhEURWMsujahr6m1aIT4TO0f
+/s06NuARoU4wqgqoTQD5KfIekBdli3Qhll6bVnmMQZu0yw9Yz+dXuWgzIM2QaaZV
+yeEqhcrCR9HRhVcYa5eBB2iDUb8m1bXycryO9bXtAoGBAJeBzx7H+lPjYGqoUeXX
+BL+t845Ig8ZwLBuu7qvOzgHsKZ3YPuYqlJ+HN2C5rDHCFBrC/cQElfXxXh54x0ZO
+uMlCabF6eu9N/wNeG+NieT0v2kZTQSOyggrMjsUZfYsB2qc5k7LE61W2p4MwVh4t
+WN8oajq6UO2kHcveJPtJn28p
-----END PRIVATE KEY-----
diff --git a/jstests/libs/ocsp/ocsp_responder.pem b/jstests/libs/ocsp/ocsp_responder.pem
index 1ca811d3bc5..736d095ff83 100644
--- a/jstests/libs/ocsp/ocsp_responder.pem
+++ b/jstests/libs/ocsp/ocsp_responder.pem
@@ -1,49 +1,49 @@
-----BEGIN CERTIFICATE-----
-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
+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
-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
+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
-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
+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
-BwMJMA0GCSqGSIb3DQEBCwUAA4IBAQAz7oUkfOIQpWmPX4/HE4u5nZqh2VP9jBuV
-31ZNHBWdR2gSlRLhplxw7lc82tJiChgHQZ5OJhiAnKWQCvoVut5WgvOEZGtfqcgI
-W3RlKIHN0+niLx8p6SYgyskq8toh1QfEzYPf9lYHJGvV9eRBXaCPjxogfCtmVFU4
-WfJ/+x7ye3r3N7WsmV5gNL29tZ+whhL5gUuYNL9C1yV2zFmY3VkUxn/5keVPxG87
-VYcWrSLzWzvOOJAca1ZAIezw0ekzrRImK7BooA8PGdkLeZ2ac77M8ZHiBhwCkLR1
-LFmD6fK7P5AgEytnx04Ote9Iis9Lk2ltEXOZRoXhcB7c2imQ9diG
+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
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCTxkpn+Y8n6Q1w
-6x2+L9hTRzQ9iz+a4kxs5ltnWYm59jvmHahXq/pneguFmxjuIpQf8CeTLg6muVk1
-uCIUScmbRhayoAuuLlwXyrbMG+7IWj0rgPvZmj1BrJrxr0jjJ+au2099mjnHP6Ms
-sZlF3HWLhpiCAcIY/CfS2GlVNTQx7XGJs9dce1fGFc+nK5zCuaCBAZvMZhsQrhgA
-T0pqqBAN8kP1lK/k+GpGVJ8ZwMjb4AXC9F7xXXJ1xnWaqy3O8xwelLtmecFwdN5G
-0ats4cCWFkY9hrKt29UAFU5CXDMkmMxL1GuekP6OAmPfC+uOJzN+vf1RLtS6QYtt
-DCATmD3NAgMBAAECgf9O9pTXenGhuTJvqhvjUHN8OyGdqgrkSfyvkWg6kYxeEl5Y
-QS9QY/hYu4cybu4vC8smou1reB9/AzpcourYyZUCuwKI2U4es5t2pspBO06/+r4d
-wQMBeGPxxXKR1bVolTVX6M0inFg31HI0Xj33VrlhoL7R/1iygSKAvIwYJK0t6JfF
-7dRNqPOwKSq3U2qtBeYfns1ace8X80PumYQMfcGCDP0wl5IQSEvgA8GHSpwn5wLl
-/K5wmHliEzLtI4ByS5ry0dF7ZVMfhPa/AFuO70VU4rv32OWM2fc64hUuIefdlxb8
-U5z4EvEpqnuuJn9xxwebqsbltc3sRvNfrnO3hdECgYEAxFq60HA69vqiFH1p6+8K
-K80aT61FxfbIeTfSAFjY0fbMAW/LtshztQIZD1XCD94h+TGVFr9V6DHDddhcwPbi
-BbF9EIgP3OCfvNtVbsh5HrOoH1eHjVQM6qKxm9gsmWqL5GFPm3lKD3pMlQXFr3k7
-KQ6PjoLTVAjfPdKz7f0B7V0CgYEAwKnOhBW9f1G6LiUMmJ972io756r6BsUifgqJ
-+fWOG9qFPUQtM5lpiXYttMXR+ZxdD57F2PDnrKveLtbl43n7o8V8pkOJbjPUdRgE
-fD5LmuD9MP8xdYC6g0j1jJzoHRG3akMkSxALLDhiITklk7uZnp8GB6xQPLC4lPHB
-crblGzECgYEAoDi8ubrqkn//Y6LWnJuofAdX0e48wgXWnfsrk/brraCp5P45h4PX
-zrrQgg/jU5lZtYJ8+lvUmKyKpw2O2jJaSnUC7UtpTj3Ieo2rD8Pr+V518GU3Cd6s
-z4VEUju6YNFtJ0U0dVQqV6je9rcIEWBmIuFryMj98lNu/n6BLdBHE00CgYAGtuRH
-nipYgZSnfwsNVqGOXOJxlHfaPIyTL/LXD0PAnMD//ZxFrBcNf1zga/SBan2jybjD
-csHgNq0rnLmuT9YBQySw9rGXcZ755bhiTBl+cFDioEItAit939EO8Xj1amSmA2kE
-ZK6+/8gLuF4i4+raqFghdFPniZElP7eqM82QQQKBgQCl7kdTXAyst5xrr10Hz5lt
-ZOjCJC2OYZP8lfWTRmEKoLD03UHSQ/DryWbtvGPafVp6bZ/ELY2bdX0ncfj0osGk
-HiQMo/KnTbKoCjTl81g4Ipml+B0cBrI6NacAFVR/vAmx6n7uMDg4Q8Lgw2u3gkV2
-Je4OlZooBshiuej7ZcbJiQ==
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCoKWJ7jqajAL+F
+trafse1qBCAmDDUmBY+M9nGhqhSP5Ndwv6Jp55/IjQDe9mHNtrSvwgvZ/nMFvTCt
+TwbdxkU7ukgKHQx/94cP50iJGWPgNGN3Ey8+5BC7146m/aQ0dcpLX4Hz5CN7P14B
+MlWrlhyWzoJ5Y1DOJTVo9dO1QnMvfPVkHpWPFhvxOUr7VH5vR2A5hGVxIjXRJGf0
++tgtYQ8SMXtA1lBjndksEx23EIVtgyhlIAqgMg7R54CQG7jKVWt2YRBcrzeXHuxh
+0o/TY67R/h8PD4qCvFSKzz3l0Rqo9XTb61Wa+cyNpP9AUWBWupp80h3u1IU9yakC
+v52n+gmhAgMBAAECggEAXzsglIxSfhkcXSL+BS4EH3e6pRFgv+mCQ/gEneLtxhd4
+kldUKNmNOUvw5FNvS8peRPKFN6zLgsKDYIJShyGTb6Gszl1pCMcq66y0/T8tuniw
+o2xv4xPRDi+ij5swdK0IJOsvcukN1uwp1k+lCIj4I8dLSGcgCb40ov4kKJA7Hvag
+F0JXji/R0+VDvd909ObTuX/xKtrWwLdHZOTkpa6hQYFiz22K1CoQu9mQ3EhXGhuL
+7Kl9Cl/hUEFORx8vjgxwjc0Wqpxqs04npr6DudMsSV2Y7/GNCAQqv8srOs5zxhKc
+94HRMGOjwxYubRxN07zJoa3OdWKLNsLJvZQMBvsm4QKBgQDRAA8pmP5nF1cIXYpT
+IKn1vsQeoDmtSOcI3Xz8ZhsU9YStugyw6T9XEBHZO67cl3JwRer291MeDRu2Lk/m
+WnkfuYM3KnGzTV1q62hD/5X8Kx/JZZf12IpiBJx85zCsTo7uyBWt5wA4RfB13WAA
+awkz55Q1/zuink+Ixc1YymwftQKBgQDN+knW3xmft/elPsJa9CWHuS1hGr2shvvw
+fk5n3bWkzP0d+aw1pGlDLPic6T0+fCEJ9FJaQFZXXRsmxDO1wwFKcHhzEkvwCBWN
+2DWNq45q+zpOVv7INQlwYRppb5I+1p/yUJj+AVVbyH+0MsO4LtSjaswmE2AZel4a
+qYfo4oa9vQKBgQC6IbFfPJAlQ9YQ7y2HxulWoKSNGekD+I85h/gN2Ol5iwa0qaMv
+0yrD4N3kd5DNiFs0vi/57l4pv0bUwv4Jir2gkVjYwoYsR1RRKoHbPT5YLBfNBxuE
+qWrkzHKJkmP4sKX+5lbYX4gEldUHQzaCaNDzVuTaCgsUUqVGi9LLpssQmQKBgH4V
+qN97/95yKYigiy5L5zFWnD2ltdeHZW9IkcwovkkcJhEURWMsujahr6m1aIT4TO0f
+/s06NuARoU4wqgqoTQD5KfIekBdli3Qhll6bVnmMQZu0yw9Yz+dXuWgzIM2QaaZV
+yeEqhcrCR9HRhVcYa5eBB2iDUb8m1bXycryO9bXtAoGBAJeBzx7H+lPjYGqoUeXX
+BL+t845Ig8ZwLBuu7qvOzgHsKZ3YPuYqlJ+HN2C5rDHCFBrC/cQElfXxXh54x0ZO
+uMlCabF6eu9N/wNeG+NieT0v2kZTQSOyggrMjsUZfYsB2qc5k7LE61W2p4MwVh4t
+WN8oajq6UO2kHcveJPtJn28p
-----END PRIVATE KEY-----
diff --git a/jstests/libs/ocsp/ocsp_responder.pem.digest.sha1 b/jstests/libs/ocsp/ocsp_responder.pem.digest.sha1
index d86d076f657..636bb51f757 100644
--- a/jstests/libs/ocsp/ocsp_responder.pem.digest.sha1
+++ b/jstests/libs/ocsp/ocsp_responder.pem.digest.sha1
@@ -1 +1 @@
-4492B09116BA7FEB6030534189F829D375374906 \ No newline at end of file
+5C31FEF898BAA7F64C2547AED1E009D8EAF7827A \ No newline at end of file
diff --git a/jstests/libs/ocsp/ocsp_responder.pem.digest.sha256 b/jstests/libs/ocsp/ocsp_responder.pem.digest.sha256
index 90b8a2d2863..94231dbbb80 100644
--- a/jstests/libs/ocsp/ocsp_responder.pem.digest.sha256
+++ b/jstests/libs/ocsp/ocsp_responder.pem.digest.sha256
@@ -1 +1 @@
-5A9EB9C4D11BE7A41FC1BF5CDBCE10E5EAA6B578B3F8EBE599ED42306B384EB8 \ No newline at end of file
+F16EF3120F5A54C8C65A398A6D12D5F5A360749F5275EC60DAB6F21523E36330 \ No newline at end of file
diff --git a/jstests/libs/ocsp/server_and_intermediate_ca_appended_ocsp.pem b/jstests/libs/ocsp/server_and_intermediate_ca_appended_ocsp.pem
index 35ecfb750bd..9250130d902 100644
--- a/jstests/libs/ocsp/server_and_intermediate_ca_appended_ocsp.pem
+++ b/jstests/libs/ocsp/server_and_intermediate_ca_appended_ocsp.pem
@@ -1,75 +1,75 @@
-----BEGIN CERTIFICATE-----
-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
+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
-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
+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
-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
+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
-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
+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
-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
-NUTIsjVGepHoVmIdGFb3gJrxwQ==
+AQEAIf+MN6Hu0i7l/GMSl95fRaZxVZ9Ny61rD8phGd6LKL6UN03mdoNb+RjlXNkm
+VPNX+7otbQZNCkYtwaCy1EM4SRzSQJIH1bezaB1x4PKneyS1O1WeGO2QUEcs9a/Q
+izLGhAVjVU2+AtwzE2JlAeibuw2vFAbJYEuLH7oqQA1wk7KIDRIALtZAXrXx64de
+saSkzwSvyBuF7PWNw25fAwaZN3xZkDk3jtNXQ0phPgW6/cOUIJLCJ2U8NpO9OWqZ
+8T5Uytj6xEgcsgaTGx/snI7Hjn8ruf429OnC/Rb9lHjVJOfwfSb/J1hwi7Xw1xCv
+qNMwWSwsyuUVv73mem8J/4nyIw==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDBpyNVW5uJT22/
-w5pAfveFpR1FAObhv0fgMQefxwyqsJHyUwKfU5N6TDKrR8N+RLt0esUWpeSg7sGq
-2X3kJTEOMpLRaaDTzHHvKaPRqnCc7rJIAPZpiaLmAcP86aX1C40akJsosVXGinXF
-Og3o4LE8o94xhfrmwiT2Qn7Vmg0pAZ/piwKsKk1FQ/ghHF5wk5CHJtlmYRBQ/PbS
-oT1GrFtkRd2lzI2h7iR+SiAuizrkFxQszYftR79YR3yUA698OxETadZVUk9fwnAa
-MNc9TwZan1YNGf363kXj6gN2V9tUNslMWPJITBMw84p6hw+g57GdPkQYCMZ1BoRy
-+KpUqDSBAgMBAAECggEAAeRITDR1Q3e/tdaQc9DsXv/5oO5PsxTE0W/31/kwRUfC
-XznYHgFpdgcB8jTPjYot7hxSafnuzt3SOBaV5slbDl1TBuxsxlDk694ODtWRnM4t
-9pXa0mBbs4/rb8BXueTLXl8bWEALkKv9gfLC8XDQzmu34eeMskh4fGGH1BNEOGUF
-L/zk592rAj7RtXcrh9w98k1y/PA8iAGfx6HcBCaLe155dtQZywv4XQkYIUUBPUFQ
-GT7SliMfz6owqU4dh25EsljAJjJzIspoHSusNd3ojfoOoNwIrcSuBJwfy0BL5JLI
-pO9NI3Tr8ST1BgsKYsfgW+sNHLehn+s2910UTSu1yQKBgQDTfJQu0pSLVA72TYz5
-mLiCoQD/E1neHdGPlzmytVWxu3elLG84mAt6WhWLhn784Noqhuli+RYlweNBgYgv
-hTEn6IJ4ka6kPJgY8wExmQGHAOj7iRHb6c0O1SArgVw7zf/Fl0avicxYr9r6xUPz
-ItF+f6eXqiTLM4BKrNk49dcA6QKBgQDqaaHynoZUVEbnJ5CHRRPlekqXX9nOayfj
-0n/kAFP160SdjaYPUageni6/7h7/z+8L6d4DexlP1EVX+zq0Nn/Ff/a/CW1R1kG4
-kuLra4HLklDceTQnRwXe9DT2vy5Q0ZHZDOocdBDWpuyKtacsfftaPCodCQJigJWu
-688aXYeX2QKBgEZzkcmnTOS9M97JJtVfEtgxWmuevqlHta/n6Minr8xtbwYPL13j
-CK/RoqvAOj1zijnwh375C2+4j0QbKorqC94Hjq8rmMoNhX2KNjOXjPK0Uui4WMKx
-uCXgyb60cU1a6oGgS2Peu7wvmPtBC8nLJ47EZ8gWXftzRKGbwyE+hElBAoGAemBn
-Qahs7H2K/oZzN4tilbzAUEKkDNV4X8G3LqrVKl+G1NHsTbcNk950/ZIs8NP3MjsH
-wr1zO2/QO9xWi1qgXdUuVhFv1veKG/fjK5BWlJZwTImiJpc3g2vucprgbSTbhXru
-hag6WjWO6+NlwR6MKFGcksfvTMlgW4+T8Wm+rhECgYEAgIBwE5bPYjfOx/LvtEss
-yI1aoGKrbB6MOYZnGfkwDE6vHXJR0OBVpvB5o6n6fcz/bMeSj0+oT4HCJFFowJ95
-jAllq1v1p7e61zrG7xavIXWriMq1tu2UVVNysR/ZYx6dnO1Y5hnCgjHG6TSYwuui
-tFs89pAm3v2zhhFfnVSdxLA=
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC2/lz2nBWxS4zI
+YwKM0CDFOJjvA1kh2B0OWxYRPwGnhTzDSN/nQ7QSYvBa0uFrMarzuFnP2e9D6j3P
+eEmNZLkvCaF3wc8IFrMxud1KpHCFxQHEJIndODMkP41+dYFTU6RiNXfQljj27LG1
+r8GxvCF7r2+Zjeoo+LqPXPLo7ejYDnRLdMwVMOZHcV/8tQF4Mq3HIe/xwZwFn0eP
+TSUUTn6a8RclsXkptfrYljrs5R1SL2rFgiNh0pnOdORuXLMdVTTk7dSv91wjyVT8
+epxMdyMz+1SxHGjKf4adOusWI+Ig3V7600OWSz7Z4PmFgqRRfP2Fy1RRQJqLlslT
+Zhfkjs2ZAgMBAAECggEBAJHlbQLlYNoxDPZ7Ef5otafoPu5Y8ghswIXAk3B+lngU
+X2SnRnSg4wHBxjXzaevH9q9H7Lst23h/WnZ+Rc4oXwikmgrcB49AYfAkas1nG5tb
+fdP++bfZZdThopMPZmOkDSyLypIQIyyje/AKR9jH0L5HGigIIIg3/q3sgnK5s+oF
+CPr/9f6Jqqk8HlRc8iQPajcfwBQNCgPEQD0nqnQgKzVpmK7OWOn7BV0tZgd6S9NU
+gxmJ7gq4RXU1tSF96FhljJDiPQ4Oh6BStH2r1SFiLiwULDBtnwPzaYoIF8/5oBq/
+OOaZskD5tIdGaobtfSDod+W+sw+6SGb15KEnigvv9wECgYEA8XV0p0RqJPjyXAu3
+huO0lQJy9kW3t3SC3i7gv1q9ZA/nKEPZMEkDo+izuYOE5R6dVXscR9DpwxHz80hz
+SQks2w5PNF3Z1TXz9IEj6FKQRGP790y5HpmrfSKubXRKLEkF1HHgSqsEvM1CrPKa
+pjFvTGRY8x5xiPo0UHq4bgamQDkCgYEAwgOORDVoSwyz6+rH/oRHEyfjJLWml0ZA
+Vs+MPZwAKEm+vbvsUyAvCcPjm1wOwBgDvOyeJ3b9cedc8bhozN/MRrL2ahyvKMIC
+6wBgTA2o4o3sEc5D8iyza0xq5qpzoV8aj+kWcKSgOU69xiWFgk4Po1AvNaAyWto0
+ElNdNsWkOGECgYEA4P9PJXKV6j/kLytn6BUVN+khUSUkDZpPPFS4bvdSFgTPpPCc
+WOcgskLr/ol0c8A0YewnLTCaM4DuLpwreTpIhxNtcOGnU4tD+WnBGQKelmwI5aej
+tMUDTMbdfPbpCx08hntawplb/8bRQ7GJtCXKjYfQbzPGHhrwVrIUW8psbtkCgYAo
+BvXGCsK+oRtJtAGY+A9120fYngWFtj+16VIEr/e0WCqbGHdUWxJ5UEnYFrEQXqP+
+yU6D09/MLTCWyjYM9qs9dtSx5cMZhJV3iHdVmYfbXe5zafvIrgJCQ9zWRBphE672
+O9+eU8ieqikrBTi7PoGpbvSeerOI3PXbRgm4MCSGYQKBgGz9zu8y1v74dduf5LLJ
+JWcYg/Gw+w2NgPKhfGqo3T+UcI8m0+6rB2yOvqe3hO180QQwXEkAfSItGC//JNXk
+wr0NXpPfgnLfKbRvxEbDZIFCpVM4ONpckZAPH3SB6LoXl2d2lWCe0gZVUE0DwWk/
+PLe4+/b/d0nkGdsO19VKMGjD
-----END PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
-MIIDojCCAoqgAwIBAgIEempRCjANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDojCCAoqgAwIBAgIEQSZGhjANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTQ0WhcNMjYwNDE4MTYxMTQ0WjB+MQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ4WhcNMjYwOTA3MTYxNDQ4WjB+MQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEhMB8GA1UEAwwY
SW50ZXJtZWRpYXRlIENBIGZvciBPQ1NQMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
-MIIBCgKCAQEAwz2A1Qy/3fKQoewviKGQitB9BAANd7cbLIGFJaJ29nFXHdxw7uOs
-x2IBy6ptxMWec3k9vWFdIo3A+NkCiOmyz6A3yvY5JQkJbIYsh9iI7OrNRrdIU1ws
-ke831iBiOVEbe87bVwPDXb3dsQoZb54WE//b68zREaMzscW/uteXsL5NQAgLMVpG
-O8uyTwvIssLRLO05562YlvEEg+jCMpHmsbTJOm2CP3S12T0XjhQyoRlUfZVH9O2x
-+d9PFyolHZoEVlofcHVbdEEZT9HoKyrxRYdbXcVmr4cWwaETbroxPjIvGVfYgdRc
-i7nxd3ccuM8l9R+vYdRwpQeQztYL0jgrMwIDAQABozIwMDAPBgNVHRMBAf8EBTAD
-AQH/MB0GA1UdDgQWBBSDmyhHjvx0m/C+iP/Q3Er31hEmTjANBgkqhkiG9w0BAQsF
-AAOCAQEAOrNK0MgTVUJtjePJk/k5IjtyQCLSs8cGU2FXm/CRiRMYcBhXMJwNUxLg
-o3rXpL/I/wnd/z/ZNONpD6kijkTHVDvGHDa9DeGvDEuYU44TalFgfe04Lgo5ptsU
-pJFasoFyO6/wohCC/VBRZlP5chKTBOAw1+W1/zflCO4utESglLFX9E8Y2VVV9enK
-FvuAhIeudwL7bcT3B26V44nGLiwoBPgYgpTRAOxxFAu48zZ2Pi6jmAiXJvxd8mQz
-dsizCb5NItQdMCeq4GH7gL7Rehzw1d+OlrK31ONSw0gZFIOnBE85jlhXfqF8BjN0
-vtoqfZI+nBTZff7y7CpRSHR4h8R5/g==
+MIIBCgKCAQEAwSDVG9MKJmbEAlZA6nEKMQi90dmNO922fhf2I1hHAKwlzi7O67hG
+MBe4hvhCZ7p/vmaTViwq0gBE5s1jy2Xq02IwIbunkyDwjHy56Y1LDvr/HtxPP5sz
+bU0K7SDBoCBAmnL6g5SbEQqRF8jrziyyRduUaZtp2JqQr6UQIYHOQgEKEmiMfSMW
+1q8ssk5rJBims+zOtHG9GVY9EBC8n19UnNI3E8Gyxla3AsN9nbqE40pUYRmO45DV
+11azoGCplqmuyoh1HGbYKiHMQ9E+dmRBJ0JjOdrMQvVrWGojRSI1qpr8w9C6pO3C
+DzHOsPMO0RKRK6A6aM9BThmcO1zERXkUkQIDAQABozIwMDAPBgNVHRMBAf8EBTAD
+AQH/MB0GA1UdDgQWBBTlKkzXC2qP7AZQLBZ+MuG23VQHQzANBgkqhkiG9w0BAQsF
+AAOCAQEAnyJRxd6QwnkyEjTD1/KyvCWZ04pREqZD9HV1db8DrDRXRKPuQ4nyUjst
+A/cmZUXlbgJ52rBSz10bpx+ZBzHEYqMmSKkrjoCM4OyNlSkTSpPOvzQIYBR2LPVP
+m0hl/UBueSeJ59Nh84v2jnbFY7e3izYg/rsMJgZvlTOfWKqbotaWD2Lb8KZ8iQpc
+Ht+5+Pzbf2ZgOEUNKdAPQjw1UV3/qp2XiaYOhBKzEKQ7waDWUmSPNh1tZgQzjZqO
+WPHmDiPpMV2j997+CBeVl7AJShbiElgjb/Pi9D/H9UW9QCtrPRIqYlb+IgwufNU0
+wnvUYw9sbQKn8jKzjgR4ApXXP0cLPA==
-----END CERTIFICATE-----
diff --git a/jstests/libs/ocsp/server_and_intermediate_ca_appended_ocsp.pem.digest.sha1 b/jstests/libs/ocsp/server_and_intermediate_ca_appended_ocsp.pem.digest.sha1
index 554571aa9bd..34307bc416a 100644
--- a/jstests/libs/ocsp/server_and_intermediate_ca_appended_ocsp.pem.digest.sha1
+++ b/jstests/libs/ocsp/server_and_intermediate_ca_appended_ocsp.pem.digest.sha1
@@ -1 +1 @@
-BE6BF654B94AA00BE3C41CBD54BCFF6ACA361CE8 \ No newline at end of file
+640EA5B863F80989B8C41497C7AC98E876CC4606 \ No newline at end of file
diff --git a/jstests/libs/ocsp/server_and_intermediate_ca_appended_ocsp.pem.digest.sha256 b/jstests/libs/ocsp/server_and_intermediate_ca_appended_ocsp.pem.digest.sha256
index 23eaef58fbc..4bf4ef24799 100644
--- a/jstests/libs/ocsp/server_and_intermediate_ca_appended_ocsp.pem.digest.sha256
+++ b/jstests/libs/ocsp/server_and_intermediate_ca_appended_ocsp.pem.digest.sha256
@@ -1 +1 @@
-0DBB4965C6DF006C97CF0936EDB7B3245EB2BF0A5A0EB7FC32F757BEA1CCBC81 \ No newline at end of file
+38E588CE357E838030CEE16598A0915D3BC096EE68AABE0B6F510207A4108059 \ No newline at end of file
diff --git a/jstests/libs/ocsp/server_ocsp.pem b/jstests/libs/ocsp/server_ocsp.pem
index d4b98d981d5..cb5a78ed359 100644
--- a/jstests/libs/ocsp/server_ocsp.pem
+++ b/jstests/libs/ocsp/server_ocsp.pem
@@ -1,52 +1,52 @@
-----BEGIN CERTIFICATE-----
-MIIEBDCCAuygAwIBAgIEFuneFDANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIEBDCCAuygAwIBAgIEfzBBMTANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTQzWhcNMjYwNDE4MTYxMTQzWjBiMRAwDgYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ4WhcNMjYwOTA3MTYxNDQ4WjBiMRAwDgYD
VQQKDAdNb25nb0RCMQ8wDQYDVQQLDAZLZXJuZWwxEjAQBgNVBAMMCWxvY2FsaG9z
dDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMQ8wDQYDVQQHDAZPQ1NQLTEwggEi
-MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvRIeCpyLm8UBRoJEBZGQ4mFH9
-Vt8EBkvW6NHmlUwDBQhjZq1P6mjBTC/I2b+Q6FPf1siNBdwFKw9F4MZmZ24U9YFG
-h5K4lpgFqlh10SEOpI1excs0j1U4E0PDGn1dTRd/2/B7YiavDr/SoIiTsJb+3eNM
-rzJ5Z3DzNV7+qTF7jpBQsG1caCgSQNtcKKP58+IklsLrywYLXqIGlBsrnDZZeBBr
-ZeFroZjnwgl6BkoS7tI3VEAAVgmSQeDOVqCLjyvGDCIVTPNIRZjYwTc+dCW6yBSw
-4jmsNAAD0YtrcE+DRUQDKr7uTUUuhyB4OBgo220wlmuSToUFIAw7H5UVEfy5AgMB
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmQjvxjtjsaBiYW9bPljYUUMd6
+LVPeFHExY5EXR1bKFWaoEYUQXMDaVIf8UhxNlpAABteJdOOw3vgQrRJ7CdM1WCBm
+k6Wo0SAUURpAAsU1ZWskethD6d+g03EjJH/QRPDeJUvoMOkgi+3SPqwFqS7+w8hb
+VlMgsgwl6g+typ/T8INSl5F/o9Jdk0r+7ig27FR09I6FGadQ5oaDnSxDvbG1gubg
+BP6E8qUOSzhh4S2jBp/87muqzjopO0tNr9Lr0PeIc6/okHqck3GNhbBZXphCJYP1
+cSfWRrgIdJSUhQ2ziVBPeO1lOAxh3Vdx8ZRaZ/m/gjL5RvOF2nQY9qAfJnkfAgMB
AAGjga8wgawwCQYDVR0TBAIwADALBgNVHQ8EBAMCBaAwHQYDVR0lBBYwFAYIKwYB
-BQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBT13L5qYabN/bwzwsZzQrpm11YOOzA4
+BQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBT2XEzVBjmtNB/p3tPDM6tT1Ds17jA4
BggrBgEFBQcBAQQsMCowKAYIKwYBBQUHMAGGHGh0dHA6Ly9sb2NhbGhvc3Q6ODEw
MC9zdGF0dXMwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEB
-CwUAA4IBAQAgZk7WDlwwleyBlAXpWD5euEsFeyOvv2h6rTJ/k2sIPvoK2yju4Dxz
-5+jscGJmW0hLXqowMxghw4aol9HZBVeO068RsbvkTeRDdpVptqe/Tin+BANQ8fOA
-dlZJnSUp1p9I/qO5QIMLaZEunytew6zLkHt0GzM+WoZ0inEDMpIEi/YM5GC/JphJ
-v1dbSAo0Oc5p4hVBYf48Po7mjV88M3FOtUpMMUxNs3Ie71ixYXLJiTgLAGGsb2GP
-N9LZnWVotcArdUpB1Mt2MrNv3H5d8JhCNoO7QRLG+0MnOzf52jIpfodBvQeUrioW
-/vdFyqPfHNngbvdHFh1ZsQy/pxxkgqrU
+CwUAA4IBAQBoUXokq9fhDnGCHDnVhnbJVHNQQoKUS/z1rWzCZu3/xRomMnS73YyI
+ceG4KSVrNJWiERUlSnp5VWNXNmfp/VizKsBjGtyvqzWe8tkoXpEjkJ3B8Oxw6+qE
+FvBXNnGtnYoRqIn75JXPSrmJF4i9IeM9ysK7m16L6ok4KnLxcf0WvHNiDCtIDCfm
+dE/787x2h041O9mbCmzTM1zO/KFQ7BjSFhYtDmdCiVO/8v1nytqpBGmNfEu8rBzh
+FDQjRVBpzUYxejz2JfbjAAx8JnOR9Sm2w1b5671R8AGgkI0WyDxxFhNZRrSGFKb7
+udNXxvvH7TIlJO/sgiGBTge+XXXb5QHu
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCvRIeCpyLm8UBR
-oJEBZGQ4mFH9Vt8EBkvW6NHmlUwDBQhjZq1P6mjBTC/I2b+Q6FPf1siNBdwFKw9F
-4MZmZ24U9YFGh5K4lpgFqlh10SEOpI1excs0j1U4E0PDGn1dTRd/2/B7YiavDr/S
-oIiTsJb+3eNMrzJ5Z3DzNV7+qTF7jpBQsG1caCgSQNtcKKP58+IklsLrywYLXqIG
-lBsrnDZZeBBrZeFroZjnwgl6BkoS7tI3VEAAVgmSQeDOVqCLjyvGDCIVTPNIRZjY
-wTc+dCW6yBSw4jmsNAAD0YtrcE+DRUQDKr7uTUUuhyB4OBgo220wlmuSToUFIAw7
-H5UVEfy5AgMBAAECggEAPxgb8khJs7qIjXoQiWBDBe6roVgrC49asOB6Y5g+V13x
-8ZqubHT1xhQvpY3hvQAt5Yg0BTRlSsUACAdNVOMKCWiB48p9Yo7v5iY3Fx60WEmb
-jNEGgILSyk+BFtTL6ZENkx0xmrEwPNfB7UiWMhihmtl08I+nS3YV/q+pZWKyKgiD
-5A+HZD6eJORSWVU0cSS/F98kLJXu83G0nNb+X1ipRs2RUBeeCDwAnwH0YXXNKHe7
-OuwSWYm8vj7cbfpuBQLWBrkNT2FA+XLwaVcFwmavp2MNeu9P6TatZ/xNLZHaCYDW
-Ypvh83ShE5nNJNuBn6345571oeuQNfOsw9T2xhW0EwKBgQC4QiCOkRlF/2P3ReHU
-pAPBIkr5egu+c/wMF8MU6wtINhRG0DH0F89j1/Qx3D0/6t47d6f3SB5Uy+7xPX/U
-o4wqjKbM93cQwt0rNrK4WfaTqAst5V4Dkr78UbKNQQ2N2xpHvuun/gDts+O288Yq
-iGejWmOi6i0Sw17Z/rWWdzIZmwKBgQDzgkQdfkAVa4ltuUGyNqiBRYEGv937XXSx
-+f9I8vRkyxTVx3x0Aq7fdBIwGdpDouHJaPGfswN+dIuEFXigf3WbMUdL/Hqm6ja6
-KVSFWubQHMn9OrgCgi8Dkbky3qxaAVTHZWjJ+vmBa7V0XzmMEHLp/KfMF6YR8a0d
-QXUM7xaiOwKBgGxYNdye5UWLjrRvmwL2Dl8aUwuvAAjVGnfh4QwDyXaElhethDIL
-bh8/dI98+WcEK/i7u0BkX7Fs2OtxRiE6qci7O7l6KcDpVDN8zkooXB0myqwKGuXu
-++5R+7OjdNzc4O8fDGKTsOgUxullHjkUTBx5oezB1g8aYkO8yfnXzNXRAoGAG/TE
-pS4tZUgnSvWN2Uv1JII6QfAdKBKepyAwcsuRy1CVX8W7QAZe1UCaJfOR31n/2gO2
-WcNPj2EJ82wToTmA4wRRTyP5YNha2ByOm5DIFvR3LB9lqMQRabN9M53k46Brf0jh
-Mu8hXf5joqycCryItNxQ11mPs1evrEArlASO8KkCgYBnp06+3vMfDYUXA0Do59bM
-RjjIGK5ShjjumHBtofyKC3tlyN5IMYJUd33iZ0jbC8Z3txJgua8e3HR+5ycxbcYa
-8ivBV+X8uDWHSIM1xTdLzigMnVEAQDkn9rakR+ptCkDGvv9GzLpS0cBj1O1bPQmO
-Rbq/HBjqocrU26vjyMnJRw==
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCmQjvxjtjsaBiY
+W9bPljYUUMd6LVPeFHExY5EXR1bKFWaoEYUQXMDaVIf8UhxNlpAABteJdOOw3vgQ
+rRJ7CdM1WCBmk6Wo0SAUURpAAsU1ZWskethD6d+g03EjJH/QRPDeJUvoMOkgi+3S
+PqwFqS7+w8hbVlMgsgwl6g+typ/T8INSl5F/o9Jdk0r+7ig27FR09I6FGadQ5oaD
+nSxDvbG1gubgBP6E8qUOSzhh4S2jBp/87muqzjopO0tNr9Lr0PeIc6/okHqck3GN
+hbBZXphCJYP1cSfWRrgIdJSUhQ2ziVBPeO1lOAxh3Vdx8ZRaZ/m/gjL5RvOF2nQY
+9qAfJnkfAgMBAAECggEBAIqq8Z4uu4Sp6eGhr8+iBGb7XPTtO2cd+67q0Yft61hP
+czi4rBgSlJNFL8pmnc6kxmQPUNQH1ySdQ599Cs3uSufSIewMN35PNgdcAZ3j8aHw
+feWGRDyYovlbgaCC/8uwxIkz6FS3/qkzrF7QAOAT1OuOVdzAakL53aH9z6fvOVEl
+j68ScjkuCDZz3twxPUy8iSYIrLfCZVNSMd9gQ/WnajmAGudl/sQqbuibfG0o7VMl
+ji/3J1sk5YvTnFVo+IlJuZBGGwYcK0sxAtEooAtfhfmd3fy5hJ6jn2GuzhWQwG4U
+8mwQ1VZ4dJYk9PsB2HucT/tEg8cOY/teF3ZPhGs2kmkCgYEA1jnphgYiCsUr0Z2b
+KTImu5yagN7b2xlbK+M4kennleH9TajxFb/8EYDMNEjhFvJMoy8I18faAc3ZYs5b
+8jrtZcQt2rYtzfBg+QyhzJEKh/2RYMWZjquuwf44GNF8YNuK8+uxXVjx+ly0280j
+POkidNhCJkPqxu8otDXpPP0BsNMCgYEAxq3NxNTwpMDOvyFDlxIG1TT7KyXt7lxB
+U7wMQhZ0UJ9tPiwEGhqMA6xlPQROsCWM1Bf30WzYtOBK0qnIBs2poH3Ix5TE3D/v
+GFj4rbGdqDTco3Z4aTi3tuuStfmVFXoDtP2RS0oSgqwRVkQALh5bfa73oTxJ0wr+
+E2/mvbFuxwUCgYB92swMxvGc7jVOEo+jZilHMzu51jPHxl+/quADKS266meMBmKM
+apvGFKrjVKWYe4T2oZ1KV8kGIk9CMwXliyUJEnX19e12/W+bIQa1TcioGBoehjgu
+j0I+CgIe4oN1y8UYhDFRK/4NHgXK0/uNv1FU3/AM1v3JHZwGM13xTJp/rQKBgQCb
+Ow7rvEhtIWwn75CEx4PpL6US+GandxNfniyhsjOdDoNnMTLfRmChOiA7hVMJ07zt
+tfBdg8Lpx9kOMbNkhWoESGMIdRc+0wE3r8RUydLZqru9SAIajEMWO4b8gY3XIuck
+kX3lKnG+ATzmfuj5H6TyVTOLmbRAnXUYsLTC/5ADFQKBgAvrhsa+YoQO2DszRLDL
+FCIUaI9etUgJcRsc58kgijkbfeDV0g3sLVkNZispnKgduZ7zZ3iViZNG5vGNQSVq
+R+AgUfEnzcrw4pC7gaEYKxnA9TUbtty3m+aJpDT7oU+WpMaPKp/dcpvOmAZsx2Wk
+Nz04w2kDwvXiOeddaBcQSWNd
-----END PRIVATE KEY-----
diff --git a/jstests/libs/ocsp/server_ocsp.pem.digest.sha1 b/jstests/libs/ocsp/server_ocsp.pem.digest.sha1
index 063ef5cf714..78d1c532bea 100644
--- a/jstests/libs/ocsp/server_ocsp.pem.digest.sha1
+++ b/jstests/libs/ocsp/server_ocsp.pem.digest.sha1
@@ -1 +1 @@
-0EB21F38A058E3021888FFC46FA0EB179CDF183C \ No newline at end of file
+445A10F977E888089A4F5C8D2CB142C0A6C77EDC \ No newline at end of file
diff --git a/jstests/libs/ocsp/server_ocsp.pem.digest.sha256 b/jstests/libs/ocsp/server_ocsp.pem.digest.sha256
index df05dd513f7..189f57ae6a9 100644
--- a/jstests/libs/ocsp/server_ocsp.pem.digest.sha256
+++ b/jstests/libs/ocsp/server_ocsp.pem.digest.sha256
@@ -1 +1 @@
-EEDEC1C5522D494CE50488D036D51E2E2E81C821A016CA824CC2A4DF33C6C5E5 \ No newline at end of file
+B80F50BAEF00ED90D4CC357061D0746A3145248D76F320EECF96B3F413C76734 \ No newline at end of file
diff --git a/jstests/libs/ocsp/server_ocsp_invalid.pem b/jstests/libs/ocsp/server_ocsp_invalid.pem
index 0c42248ef5e..c01103c25e5 100644
--- a/jstests/libs/ocsp/server_ocsp_invalid.pem
+++ b/jstests/libs/ocsp/server_ocsp_invalid.pem
@@ -1,52 +1,52 @@
-----BEGIN CERTIFICATE-----
-MIID+jCCAuKgAwIBAgIEAYxVRzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIID+jCCAuKgAwIBAgIEZhA5qzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTQzWhcNMjYwNDE4MTYxMTQzWjBgMRAwDgYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ4WhcNMjYwOTA3MTYxNDQ4WjBgMRAwDgYD
VQQKDAdNb25nb0RCMQ8wDQYDVQQLDAZLZXJuZWwxEDAOBgNVBAMMB2JhZEhvc3Qx
CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJOWTEPMA0GA1UEBwwGT0NTUC0xMIIBIjAN
-BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAypNSD02Blza1AGLn0s9XIhAZb1Fm
-1aES8Xa/EgIy5rkActkACsxHM6ZGZvrr9VvYQGPK+cLa0QIHXAn7cuXVEsio4/xm
-fdOdU3Jmg3nRzb5voIC7KuG7++reBQuWue06omLgCqk4JeR7ERL7be0jt9e3FUjr
-BigXCiRGtgdsF677GeJ5UbxMBlG308j3vKAlPBomOJckrnMfH/QtXjLHbiv79HZS
-kK+5vBMCT1Ury0BAJMER+5DyzWP5g4+fyGq3QQpmuBVKkZ6cvu1d7bgk6oOH2Chb
-GDUEvmTt8ObYC7+VDEcFAsxM/7IPAfGYFr8JAbveZYP+KenUBrMfkIKJVwIDAQAB
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAslHfZS7o1cezdHAEfDEbr5y9sC7C
+ZW6V2it+EuLP5B9yB24KxUc8lQyp0cmbtCQ/4GHYBKZI5UkysMvYagN9rQJ+cYGs
+mi+brfBlsC908E9hgUo4ZNZx7wXk2BkyKfNv9z+W5aiau212umuQ1D3cS1iPhvNH
+9biO/SeHo/rIam83Ydrug4s32VbeV7j2L+Lj0kNcPNHT1MNPcW0Q5Q32jce8MKw9
+CWGZtelVPuJzM6KgIV2ZFjhWnKwxKbN3l4RnMF+qZ0x++ZXh5W7G8QFaimnzOxBS
+bv8iKSegZ3GZkDH6/DIIi/o5OINj1N9nLiXSQbnIeugQD//Scb/msva5QwIDAQAB
o4GnMIGkMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF
-BwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUSdlyJfTIwXKA3boA2Sxz0iCw998wOAYI
+BwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUMTnQoY/B4uZ7zL9XHL9TkNOGTXYwOAYI
KwYBBQUHAQEELDAqMCgGCCsGAQUFBzABhhxodHRwOi8vbG9jYWxob3N0OjgxMDAv
-c3RhdHVzMBIGA1UdEQQLMAmCB2JhZEhvc3QwDQYJKoZIhvcNAQELBQADggEBABu+
-SBuK9nZOg1am0WW7kmv6ZN4801gIuDjXezN0PHDjOYIHJfjLRedVp5LBiyqjxSZX
-aJModrEMJSlFlDZ9LO6719D5wUgZCFjVloPnEllL2SUUqDmJhHGEe/5oNu9LCx23
-sYNusHVO6/6wY7MqYFZfUK1H/LW5aLo/VrTsR5junkqkZ10qiSvV0d7fRzwThAED
-za5/9selmdthZPJ00ouWulSmQcfcwfYt5VsbQWGOyV0FUdsHfzzhtgB6v/3PJL/x
-giKfqdKDVjTHh1zrTgiqFQtAj2b0cMvqWmRHFSD2ettTNz31q1Z1l5MKMCHuX9qk
-vxCsUnSSB5C1tNAqk64=
+c3RhdHVzMBIGA1UdEQQLMAmCB2JhZEhvc3QwDQYJKoZIhvcNAQELBQADggEBAA9s
+DusBny28T/6zh2z1RGa1GnI+MiX1/I8/EGw/VamtVTf0a2ROp89iyb7uviUT0FYA
+YxqF/ky7JQlY7Z3/SSmy+7KpTyRSqW53GRIjcoRrGQj9VjLUqPy6jFaP7XRHGroY
+CLceMcn7EvZx0rZrOHMcLItBKPwSnF93GBedE0p+a7d92TvyoNLdv46L7BQzZtat
+kNQckgbEBLj29dwx0y5Abyxy067qdinyOlfFesCDGNw0Is+DQG9vgrrjhq6gKwBZ
+RihTZePFh0xVy4OGjrZJl73RO2F4IZfBVYb2rc8pWzUszI05jVeM3cn6q+9X0p88
+enh+sBcekIgOGLs1KN0=
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDKk1IPTYGXNrUA
-YufSz1ciEBlvUWbVoRLxdr8SAjLmuQBy2QAKzEczpkZm+uv1W9hAY8r5wtrRAgdc
-Cfty5dUSyKjj/GZ9051TcmaDedHNvm+ggLsq4bv76t4FC5a57TqiYuAKqTgl5HsR
-Evtt7SO317cVSOsGKBcKJEa2B2wXrvsZ4nlRvEwGUbfTyPe8oCU8GiY4lySucx8f
-9C1eMsduK/v0dlKQr7m8EwJPVSvLQEAkwRH7kPLNY/mDj5/IardBCma4FUqRnpy+
-7V3tuCTqg4fYKFsYNQS+ZO3w5tgLv5UMRwUCzEz/sg8B8ZgWvwkBu95lg/4p6dQG
-sx+QgolXAgMBAAECggEAF5GmZYNmBXrm+kGHqV5YS+1FmE8HQOm5s4BWYLkCxRdX
-NwWKXLdBvX+mB0tAcs6ZzXwO3JpQLSsoQgwjRk35SXMxOz1di1w4nMHdrYRZ5a83
-e5weqrGS1o+P/1RG2CECxmvslzDzCG2Z5/WmbTa/Bh/B/Gb8eT3m2FY6J+mbKPIM
-3hkEW86SWmW9MhP80LC7HXiFjUCOVO9LoMf64XJlotEFi3T9e4y7DqoLT6+/wPGF
-vRI2XJYuRBIt7reJJunWSPpN4RVLrCzJgqWMPMYJc996NxNnykoF1QSd5z9klTH1
-cE+ZxgKIfvoxWGF5r28TRKpZxM3KBRyoWT+Yt2MP+QKBgQDrRRmMQSoZDtciTFzn
-GYAZ7bK4wnRbPABy2dH7I4w1GhfD2+/KWFF+o6fg+DDO3hQeauESefAix8HIcxgK
-P9HTVIyXQ42nfIs762LK96xgnsTCKec/2kC+MysAXEnbmwoZcvmuqAV1kNcX1a//
-r1uD1uXwDbo11UFG02ap7TXdAwKBgQDcbL5eWTohNQzPwIZj8c3C6hkINefYZ4yK
-F+HQJVJu1XNBHG+JPitQCDuGAOwt5mGXhDnLGr1sIa+wLZfriNUmCWmJX6y171te
-9xgOzdC8ixnsCXQTbfiRpaI+kKQ+ZJqrbrIW4TIgVo7xlJNyKpg9so27m5an1ajf
-MNDow02AHQKBgQDUDPLq7C0CatLS0hsGHIDOXeSxDGsNdDY/Tj4pai/MCNmUqZ4m
-NZY2W1FLvsdXHOjrRY/ZNFiRMJRjlAD98+mt3U3eZH+/jsx71Du2Dqeqak+TZWtN
-rOyfwcSnTYcwTTw8FdofZseM4GBN1kcMYEROvxl+VREZxj1Qlee5jtj2ewKBgQCM
-pi7K0TCQY+Nq5TRbrb1XtDyIyqzHnztEGn0Sbd4trrG+SEC7WBoXFUm19fy+RRTc
-s5iVCtj3mH8ccdtQhZ1MihD3gT8ZUEQDUrPdLmMVC8VcoaOZikBj30apmW3UCinP
-XfDxPHzZuaG4cM+st5UxOS/LGDqHmYQJ9oI3I/fd2QKBgGCxc+KQzkDgQTgLiQUj
-snQaaqbHKql3jGwIvQ60OUKhClAwVeX0Y8b8VGf9jVyhr0dn5BCjzlZrHUYrEOPT
-13mjMeb2bBRnMlbyS9BuMrF8bESKEy3wixgc09uf1ZYcsQGaa5rdmOFB5MxH9m2v
-e/HYO70G9O26DnXBhDC2YQIX
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCyUd9lLujVx7N0
+cAR8MRuvnL2wLsJlbpXaK34S4s/kH3IHbgrFRzyVDKnRyZu0JD/gYdgEpkjlSTKw
+y9hqA32tAn5xgayaL5ut8GWwL3TwT2GBSjhk1nHvBeTYGTIp82/3P5blqJq7bXa6
+a5DUPdxLWI+G80f1uI79J4ej+shqbzdh2u6DizfZVt5XuPYv4uPSQ1w80dPUw09x
+bRDlDfaNx7wwrD0JYZm16VU+4nMzoqAhXZkWOFacrDEps3eXhGcwX6pnTH75leHl
+bsbxAVqKafM7EFJu/yIpJ6BncZmQMfr8MgiL+jk4g2PU32cuJdJBuch66BAP/9Jx
+v+ay9rlDAgMBAAECggEAVZjNdoGdDLmu3+7BiGf+VT8VIxRfBleeITsNar1rc6LQ
+ltZw3yAB6b5JakWvszpPW0M8cYbsqPuJFKrVOJZyZnEzBwNrOhwuS8GA3qD5Lj28
+nVZmWalCyaz3m/AET3TmwzXIFnfnxp6WBoiJ3gfPzm81fl8bpM0x/j1SdBl2yPfK
+BFY7vTAq4skIf7QXXoc9BPfMEWEbfGMFXFDoiEHQlUsXOlbyejcYQ2nPi6h9jSh9
+sC0OPGHKgO5HNcoDJ+TylsUxapPj63hodL1L6uYLuBNV1Ud1lhmiqRSExi6W5LSW
+eYeNVpo1Be2xUa3P1NkbLwWntBWrDtsziDtlQDfN0QKBgQDqqizQxSOrtw3r1+W6
+TnEluiTFbAdmiD0p7/VixzYN7NNVpdpZ5aO73mVup6q87bK0YxcwO5P3iYvUjaPx
+1VPjVy93uX2ma1ejOP9KbBaAgOPbzb9GbKJZcVdZNLOCxfzrRwoSdvx3KQHGTekG
+6VJyuFdFFQMg+SpZTwuqV7fF+wKBgQDCiETCJM75stmCTPG3eBceOMLDsWDVuXMQ
+4eMv2C7T1AVIIwP5vIDz8pBeKyZ7qT1b+rsuMeKCxsoiheZz3WJrOfQ24ToSGgUF
+oMKU/MBq2CkrVayvbGjWdva6tqp8KEHovF+4k7JuenogcxsMRosP+5CAPiW3TUWr
+wYJp4ZSfWQKBgAgTCO26CssqxkjaKeZqMox4xjEg0XRetbQOtKPMdPivsGnfBg9X
+znV1ZooTLNXJW//G9RJMyn+W9P/AS+bTT0qgQlrdQAyM3vwXxvj5lSCgzrZOcwlq
+TX/EXZwNKywRwe0aiacu/uret1fqcF0zhAm8fAw9d9kXmbRu+tjGoeUnAoGAaWCB
+xp1D1TVR5+igY59U/pUGxBUY/I1pzHJgq/EyZKMMfWgiZiz7uanjFG/Rd9lUmLe4
+n6x8JBVlN9BK5ua8wpLxPK1C1L1tjP/ph+VmojoYCxZs5dYW8F4fB0OeFIWGNnmc
+bJLtbDVCZMOVmk+4Ut8WBrIjoijkncbES3DcHnkCgYA1hnopmCNfsyHt4QpjCsjC
+eZxIn5DRIMQXDNnoW062TsH4E3JjpvpuKlk1bnrmMHBCelvCiULwFIwCL+8+p0Uo
+bcnr12vM1Qoj36Qy4JjiH/2n3xcjNWglccdatEp5vDv6UK9VifSCC7SKmKu3j991
+cmLDGkcivEg0isF1b15AXA==
-----END PRIVATE KEY-----
diff --git a/jstests/libs/ocsp/server_ocsp_invalid.pem.digest.sha1 b/jstests/libs/ocsp/server_ocsp_invalid.pem.digest.sha1
index 037bdfb7c26..d02d599241c 100644
--- a/jstests/libs/ocsp/server_ocsp_invalid.pem.digest.sha1
+++ b/jstests/libs/ocsp/server_ocsp_invalid.pem.digest.sha1
@@ -1 +1 @@
-1ED0DA455BA14EB0AD5A2CAFE9F5F91FA9CBCE44 \ No newline at end of file
+4F66BEFAAE9CEF233F18C383F9215812E1803EEF \ No newline at end of file
diff --git a/jstests/libs/ocsp/server_ocsp_invalid.pem.digest.sha256 b/jstests/libs/ocsp/server_ocsp_invalid.pem.digest.sha256
index b84dabf0275..0e45fa784e4 100644
--- a/jstests/libs/ocsp/server_ocsp_invalid.pem.digest.sha256
+++ b/jstests/libs/ocsp/server_ocsp_invalid.pem.digest.sha256
@@ -1 +1 @@
-53E0AF484D959854A4267346EA2F82187F63F9D2415F958043E2FD0DA56F3DEE \ No newline at end of file
+7278F37DBA02E5C0B58DFF2FCBCEC6811D30B2A5AE39EFBA3C2C72E537A663F1 \ No newline at end of file
diff --git a/jstests/libs/ocsp/server_ocsp_mustStaple.pem b/jstests/libs/ocsp/server_ocsp_mustStaple.pem
index 060c1c3c807..eef33b69585 100644
--- a/jstests/libs/ocsp/server_ocsp_mustStaple.pem
+++ b/jstests/libs/ocsp/server_ocsp_mustStaple.pem
@@ -1,52 +1,52 @@
-----BEGIN CERTIFICATE-----
-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
+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
-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
+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
-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
+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
-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
+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
-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
+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
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDF2VUDWCHeuXCM
-U4nePjjKFwR6pc9u8qCcec+KpXg91/nEiGRgfowAyYxWQ4qAcM/sZJH7d46A9iie
-s3Ofvab1NNDpb3zsxFLRXs8Xvqffvu1+9i2Ym/Xw+2GNsrTyPYuyz1j6kVJX2nh1
-lDOacaH/Y8XftJZzbVTnJ9XEIVPIyGCpzYNpiz1lCx7c4RwvvJOHqkWrju2Dufxz
-4YKQyt7iWOAc5sD5o2dtVsOnec2UsxYzdMnRaOas//Ut8zyzvXS11W/3Y+T6/HCr
-0WyT9AL0OvNHeL60ApvXXmrcDiBBKQBdB1BJfEYRilSot6NmIC6l6o+iEGAxfuIj
-MMLWIFnPAgMBAAECggEAOjddAILqVHMUXvYl1zNP2oczVjN7+hWClQhyvUU7QFdQ
-sze+8XXLFGA53xg4pNqNE+3z1p6zW9cS1L/RAev4OKa14jpf8/tAs0LGhSIgm4G+
-uGEPwZwCnkoZxmwTOkRJ2u+QKwqfxCIQ1+gn1wYguNlO3ChzLLu7A9mA2RlFYgqv
-j9VdFPfhybM7k7CoMkiA3oY1oqDMMjVcfcoKy3WBDVeTrZFun8p0M+rozSdPtw2x
-3ma1QR33k6BCNcRJlDotJl/llyey83mlB9RFJrFNCEsSmcgG27kSokNbI4a8EZHm
-G41qGizz2nBSsLd4HjY6uX9+z2qLKd9TELjzWvOpYQKBgQDlAjGLLBFizZv+k/aB
-7RLALJw6+XdHhD6OP23fgktDyJlZqfJcoaMnCLa37W/UKpPJ3PiZ2YiCp2+mV1Zw
-zvkv7tdCrpQgeIBXf/14mzKAKuEHcpR012MlKeLQ4F0UtthBpwzNDMf0H6TDPuvC
-So1bOEBwp7dgYeo/XaOmddG+iwKBgQDdKvgI4gXza/vhRKpMe0KAlYgDQBr00CYC
-Gj1A9Yl50lGlSRioS/xgEBmjORuyz9hXzm7B5GYXAQ1ju7XQ0z8gSiN0SwZT1x6v
-2jHE/bcAIwmYFHjNtwc+qjedE+8Si6t/trpzayCQ7kiWIB3bMPEsiRaaL81qYQtb
-dNZjo5leTQKBgQCzyKcQdUYo5PXERHDPy0hfKiZ0fghQUtexYMZnI6jmzALny22D
-nzmwmTyo5HRYghyH6zwXvBlZSQ1z7zjjUvl50e2YYenUHAXVq5tYJa7dw8vpxuAZ
-YkZplJqGFL2+V1UrJXP9Pj1zv6vfw/PeEh0rMdwVFPX3aqc1m9OwCOrixQKBgQCW
-KSZeYZdIvng1ajl10/pC80N1cYDb1rb3lnkgMZU1cOaeIhLrsSuYzVWazJtRvGxW
-sYHhgwENfVlp7Xh0X/jsI2oO+yFAqz3ah3pjFR+6qA9LghrDERGKKme37mDTZqD6
-BUZyNrnVrPL7erLKr2APrMP7y5jcMSdU4O7ul5T5wQKBgQDORHDEaeGt+/5RXeR3
-NWe6uTeKxt5L4zSWoHtR21aPPCEfCPj72grFCT31AoAzc8KZ291Q+qsJ6cAvLfH2
-qA7CJItIYxPBAs39yGEZlh8Hqn6VJmt2PUkLWEdJONMoI+7yCRdNxKWQH/RBmigr
-8UWfY2Xsrxpwp4Vi/u+cLIbz0w==
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDhDJyhIP29anYs
+NVP1F6e+9dft37EZyRVDAb9oYy20VPQYTHgczZf/kqDkYgBaFJMqalzCsvgsTYxI
+OdBpoAw6/3oIQ8qrf2Q4awVS7Tg1k8nhvFY5/sme/HX3zktnBSEOR4tcY46t0TmL
+ATYoJoBLhfF7M2Jvg9AJjRbqUq7+Z2fhOEDUamxSKpEbC8FydXbL0hYr4ZvXDzEY
+tUT4eFnrwKv8bF+wlkrBMWUGZxsYHOvBuzDSaC3w6oB53BFK8S9zJmrKpmDcbl4U
+ZMp9a7wYA03fyf1E81aFY7ubsOV334oSKHF+B66heZcuiQGS3CH5eXFt8ZMt+BCZ
+AmnKiFnfAgMBAAECggEAL14aMYfiIFYiHVf0HegmtHjGRBkLC6RZR0s84FnPqt8e
+qWae+WEElxRjrO47qLof55OPhqNovNptpl4U0caQDHLtWoP6SnJ7w6wy6KtpY02B
+9nNPqtFH2qDEq63ODRb1SC4i1QVXaJpbBDjzDyxbYIoGs6mzFEmoJfp+Uj+o+X6h
+KTOsY2XIWjrCAVVXnBC7cdXpSG57+d8e3msx9/x2WYSjsn6R2eXXH+gwJ3rBeZH8
+A5ec8byK6VJa6LbN/HPu9OgEWOgwIIWSE+Q/3NHxbjdmqQySV5egUr8UeU4Ww2ZU
+PH/+Yt5ZDtq8oNh2E6VxJMhW19Bz/nm3Z7ND3gK5sQKBgQD6y963cIgpcW8NAe6X
+mdos6aRWE9JmkKhCcBLvq29gNGXlaX11IgIlzoizaFWn3cM3wqg3k57alWK64F8U
+8BP/8IBdg4D7f6KU94Y9hoKAGTkUsGZFl/VuNXCeiWKz07rAn6XY1cnB4u1UQvxS
+cxdbkNQMx4Adjm6VfuCvXiOlywKBgQDlt/vJBuau0MnWy11cAMLwdOqe+o4kh0Nl
+oQ+Zpkt741IRTsfJsv8sJ0RwJfBS0XdUpi81y85ADxTs/6QhvwI9afKHJ6kR6LKl
+V2XPyx2tRnLVEhS0l4nXo7wxqiSe9kO/7giACEBgO2DOam8yEqzRzLmEkYWeLOxd
+RTZ8J055vQKBgQDroIEWLbbv4PAp82e7rUPLMJRCfwsNa9l52hwgaxwP8grN+Edz
+tkj4Rkwu6taXCYYxLESpOptj2DhTRRxv6oOP0eB4e2XCZI9WkBviUC7ptUjoxDbC
+Kdvf+Htfp8pBE6sA8L17tJiC/fZmVS0FNbZ7Q93GR+V5X2lMMVFd0f+B8wKBgAKt
+jmXdirrm/DNg04nLCHq9Ii8QRK/wU7zPj9r+sUqUb9R70qBrUcY1/vo/tvmAL5/x
+AAPkiFb+1gOdR1CNZX1JyuYAdFwdFlgPGMS/XW0zsQsC1vL0AUteQUdi8GJaBJgs
+MjUr43Q7vPkrDHjM9u7LMC53c9NQOsErmWMBIk0RAoGBAJFHxVO7zN4ZxttOjmUC
+0jd/ao+EeFwXALbIuSTk2S81cEjkw7TJh0UXDoqquhEyhPoyLESUGIYIcV5Hjjwz
+QTLNZaDOdCEjF1rGAYAeBQqPyYrIhoUzgSqwqlvSFucKzCG1qJSeiyK9cVbJbcvA
+SxQ1fiUidf/EsQ4lUgcOC/XJ
-----END PRIVATE KEY-----
diff --git a/jstests/libs/ocsp/server_ocsp_mustStaple.pem.digest.sha1 b/jstests/libs/ocsp/server_ocsp_mustStaple.pem.digest.sha1
index 0becbe1a52b..730cc32e186 100644
--- a/jstests/libs/ocsp/server_ocsp_mustStaple.pem.digest.sha1
+++ b/jstests/libs/ocsp/server_ocsp_mustStaple.pem.digest.sha1
@@ -1 +1 @@
-69C5352555E22FE5C1031FEA0ADFD77F740333B6 \ No newline at end of file
+2E1D20D83FA8232E23D2D55842950D91F35BB093 \ No newline at end of file
diff --git a/jstests/libs/ocsp/server_ocsp_mustStaple.pem.digest.sha256 b/jstests/libs/ocsp/server_ocsp_mustStaple.pem.digest.sha256
index 868b1cfbf95..8584a5a3a3a 100644
--- a/jstests/libs/ocsp/server_ocsp_mustStaple.pem.digest.sha256
+++ b/jstests/libs/ocsp/server_ocsp_mustStaple.pem.digest.sha256
@@ -1 +1 @@
-8401B6C34E8154CE560253DE07B3E20FD35F2BAB3E4F004EE530C9B56BDA48EF \ No newline at end of file
+FDDE08379C1A7B03C5F6488282DACC6153AFD87A9656135C9B81AAC40DE6A8C1 \ No newline at end of file
diff --git a/jstests/libs/ocsp/server_ocsp_revoked.pem b/jstests/libs/ocsp/server_ocsp_revoked.pem
index e0d5054f812..677030d88ac 100644
--- a/jstests/libs/ocsp/server_ocsp_revoked.pem
+++ b/jstests/libs/ocsp/server_ocsp_revoked.pem
@@ -1,52 +1,52 @@
-----BEGIN CERTIFICATE-----
-MIIEBDCCAuygAwIBAgIES1x6QzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIEBDCCAuygAwIBAgIEcgPZ3jANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTQ0WhcNMjYwNDE4MTYxMTQ0WjBiMRAwDgYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ4WhcNMjYwOTA3MTYxNDQ4WjBiMRAwDgYD
VQQKDAdNb25nb0RCMQ8wDQYDVQQLDAZLZXJuZWwxEjAQBgNVBAMMCWxvY2FsaG9z
dDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAk5ZMQ8wDQYDVQQHDAZPQ1NQLTEwggEi
-MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDBABJCzU3sc1nUGphwQTQgrV7w
-My1pRwNYTDXrXGJKUKWRKYhlBtfv8AquB8DxP6zcDx1HD4WUfgUCIQOC0vBz7Dig
-FirhQU2ow4jUE1GBigi7NeftrNQtm4s/z/v50BT5HNlf02Q+Yr9fj7Nhrhb+f2o7
-SURv1qSq1fZk/qX/ryc1E5YKrt+34mda1Y47ienmzWWQEqrUbpimCWK3jvielt65
-K7RuHywaKEhENiwB8uSsuFH+y2rBV7zhimdu/gXNGsiRTcd5xo/NHDGVe3B2jjZu
-Rn0Uu3svzDi2IZS3QJChHubqdUCD9NLgDE6L1cw1duW8zTwo2bWEG2IAgPTDAgMB
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC8n4ln4wruffzjOeWpycIWcZf
+RLpIL+tWroi4oflCO5PmrRl7NNZVmg/qXrxM12x+BMvwQhQ1/FiojJmhaiMzwGxx
+SB2xFr7LzGMp5mDw3CJDMf/CAQti61YehlfG9vi3ljn5Wsj+0TfOIBTVCGJ1XAzX
+26geCH0RlXluD4j2bPIV4uERpn8QMqSSfoPWHAJ+TTELbQ2AkeEp/rFOQCK6yVjJ
+dg8oZcHhiOrgWWWZ3qTBO+HlOdgARrGJr17YO8IRw757BPihMjF7xzpU0NoczGS4
+mluzJU9HYo9hxSrIB9TVIJefh55B1cyqmLk/lSPIaY2xbnGBGb+nDsOAD4fhAgMB
AAGjga8wgawwCQYDVR0TBAIwADALBgNVHQ8EBAMCBaAwHQYDVR0lBBYwFAYIKwYB
-BQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBTAFr3qMkflWBL0OaRX3QVwJBSH6DA4
+BQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBSfszMNdqXgoUecbQBJnXBy6mAkATA4
BggrBgEFBQcBAQQsMCowKAYIKwYBBQUHMAGGHGh0dHA6Ly9sb2NhbGhvc3Q6ODEw
MC9zdGF0dXMwGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEB
-CwUAA4IBAQATvrwHyAqkKomA/WGbEl1+8P54Crum/kkfMLF2KrRKqgIZA5z4cS8I
-D6B99GwdXU+9kyZb1b/hGSkpZ/yc+8BFyHwysJ3mFUBLDPG9kxMJc49TwLHIBF+t
-uNZwDQRuDE39cyC/yQm5xnvX2S1A+oGs51TTqB6/UU5NV7LxkMzHGywgdW37VLqF
-qtYdY3NSyKi5FXA2jsMaP3julT6kMTSamMdfH5HWLPbXmuodzUvKARmHFBHsU/0Q
-ESYL+wP8d5RBLlpx/abT2ShOz/A5SflR/fJ0dUXzsO4ZbRDaP8skpfM+G2DzQ7g/
-t3DykMBR3vhXS5OH5G0YawowKf48Q8ZD
+CwUAA4IBAQBmTj3LAURsI8psC+n+UnYAcDQhrhclH/bTYPYu8Vw7kZlLwy/7ERCo
+C364VfWv5D/mouKs3TIUXKKaMIHcxap1DrdEz/oXoJxxDyYdnIK0iCgNBtF4JdlT
+SovS96XtIWIJ5J9968O8p4v68XS+UgHxWUsxk5SXtkMv2somQqpoLiN4ItwmG89+
+aDfWAK0DeO25PQ2bGbHJNHUG40Oo9vFdeeq/YAKYebn4kfDzZTIH6CeqUxUSk97S
+6Q9thpFM62B8nj8/EBPHp/YcN3N/DNW+fr5hBrrtcPD1qOrcxE5fq3bESw1rugrr
+SSMMGicPTCD6nWjxkikl6wFMkdIAdmC6
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDBABJCzU3sc1nU
-GphwQTQgrV7wMy1pRwNYTDXrXGJKUKWRKYhlBtfv8AquB8DxP6zcDx1HD4WUfgUC
-IQOC0vBz7DigFirhQU2ow4jUE1GBigi7NeftrNQtm4s/z/v50BT5HNlf02Q+Yr9f
-j7Nhrhb+f2o7SURv1qSq1fZk/qX/ryc1E5YKrt+34mda1Y47ienmzWWQEqrUbpim
-CWK3jvielt65K7RuHywaKEhENiwB8uSsuFH+y2rBV7zhimdu/gXNGsiRTcd5xo/N
-HDGVe3B2jjZuRn0Uu3svzDi2IZS3QJChHubqdUCD9NLgDE6L1cw1duW8zTwo2bWE
-G2IAgPTDAgMBAAECggEARBzbVPoRyyX2iNWOAOfyFqo4/DqDh0kJlCrpSJQFGEcX
-94AZ49WjdclYa4zO+hVH0y3+XirLMNm8uMCf9ZauR6sRXOYV4gNi/fFsI7Rhqn7l
-j/R5UrcQ9ruTTEUBn2thS31z9c6r7Rx6f6Y+X3XKJa0f96Zm4bV1zdjPKVt5iB9S
-e1LsmINPqB/wulu1dOzL6YXuB4nwylVfPxujNBwlFGThqfxESZ8uVsNV54aVDWbv
-4JJ2vmqd665sDdACy3gvJh6YdfYWQ5Z6T6YHIfkUZmMnL48tS7CrR8C7gjCZQPhM
-kZWMnElkpC0jbyxF1Z5UyweDILQ3NyY5lkJXZhqriQKBgQDpJ1Y6+YxrOq7GNqbQ
-cXmNF31qMrISbKjAZ8h2PPQF47ySRXVb4URMynmBnrcgeoo0DCaE4USzoSUOsub6
-48FHTjSHISOko4YnJ7+iom5gAlozjQ5ig93TQaWGLJhLexJauWYcM01XAN7u2eEH
-+kaTVKLkT5QDDPNSfMtc8Rs8nwKBgQDT6Xx+/W8XJ+b+aTu0V0sX0TT1Okp8+ZXm
-txw6i/1jVVhjgkSX6B6T77ZtiWNpejGFrSaF8ndhxj3cxCvQCDMCGQ0fCue8CaI+
-OwkBfBjZEuJSCGLUSIYBiPbQFF2PqB/CqakHQtxTwDrDg0zQDMJuT/CjPl4MY4eL
-hbbIPA6xXQKBgF0w5uuNoU2e2ArL/2MjaBU4BV30Q27P1aeKE/sGo/bSryW784u0
-/4q+B1EC8mld8W2aSa8lJ0OxLlGwulgfvrpUjPRSD6AX6GAwKA3GZN2lMw6V2+EO
-mhR9kb6OhpTs7Uor/p9Y9hnHdFP97E82/wyWcMFW+W86tusKjHJqwJs7AoGAH5qc
-1Juba8qpqpurKdQzANRUn5YX8dePQZ9heGHUYnIiAoU1EaqulMWVYXSx/NMae6M9
-MZDduRlFtJ0VI6t1YAS4bj7EHMkbB0jqqOwHEKi+VBmoE5zVT3lLxfCjm38pbXC8
-IrcYAO2UVgBI/mZIwQbvDomIoTRezLIednJuhokCgYEApcT5bo+g2fLS4lJvqPmT
-gadJyf6E7vt80DqF32NM5PPrpqwMun7qBr/Z7yipjP82vtTKJhG/ywFUYY7Muwki
-G2K7Wmyf4SZ1d4zJAGQ1y+hAvOXPNsQO+QJLxPsEPJtWkL4xph7vI2moM4xnyuAD
-o/iYWoSLlx7J77jAJMVuB+0=
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDC8n4ln4wruffz
+jOeWpycIWcZfRLpIL+tWroi4oflCO5PmrRl7NNZVmg/qXrxM12x+BMvwQhQ1/Fio
+jJmhaiMzwGxxSB2xFr7LzGMp5mDw3CJDMf/CAQti61YehlfG9vi3ljn5Wsj+0TfO
+IBTVCGJ1XAzX26geCH0RlXluD4j2bPIV4uERpn8QMqSSfoPWHAJ+TTELbQ2AkeEp
+/rFOQCK6yVjJdg8oZcHhiOrgWWWZ3qTBO+HlOdgARrGJr17YO8IRw757BPihMjF7
+xzpU0NoczGS4mluzJU9HYo9hxSrIB9TVIJefh55B1cyqmLk/lSPIaY2xbnGBGb+n
+DsOAD4fhAgMBAAECggEAb7JdENV/jLY7GTLMpocTWDeH76IDUcUTBFFwSMmVdZuJ
+PIxFo1A81kM1h0XMggKUSQgaiYhy6BO0AK6+f7u+e7Ju7+EwEf1ESKTM1H8JYDfg
+8bs+HTxX9897QnYa6QcsrpPGl9aqf0YEwXekOANb1n5tZWiXxM18S4znTGZeRUJa
+1Xvs62zOqSDEcqvxIl5aTQF9nLH0znkjOQBQ2Ma117t2a+zS0o6n/YqiPLsZn6Gd
+HPyyZRawydnejruEZdcWdAlUbVLOzmrBeMhKGqd5GrKWYGj+y2FGm74hYwGhKbs6
+Gl85k6T3D3pJaoyvDelPQr+O4TfmfDzbjCtsFphxoQKBgQDiSM9QL0gP3/ulvTt7
+X7TeG4u3Wk0fASDUKDmzeVjzlDdXBmmY0wDU0CSOdn0WZ5uU/mDb4DKfAFbSAqus
+vfkTDa6pV20ynnpo7k+S+DPA6UHO2InmE+8Cc74Nixh3Xg47jY21qLSBFweKx0lP
+xYkh+F0rmSF+1K46tgMMnO28ZQKBgQDcjDH4N0NhsKJ0/EhykbQ3kyX50fYMPy30
+TI+70QGlUtI2uZrLZNUxtLko1ghjr1smWbrVyyc5popbTZ+iHOjCAIZqMM9/3PAY
+6919GZmKk5Np6KGm6RLA2t08QCmxcPQa23AdBpVNDQRv+BNriBawZZRa/9VzlE3L
+z2M5GlLPzQKBgG6XoyrPUOrhTz4blByiE+WRlOFRsut6Q68s0baTkhPJ1pojuixE
+w90+tP8jjdMLZBCXmoMbueHX6pbNU1Yjqr3TLA/7eJUKu0zZW+66e6DG37DWR984
+0tFh+/rmhligkVgtwJqOD1ogBUGgUIY6RuFhXzfVqXcxPs3W8vqRH+e5AoGAZKoU
+0L+goME3lX/lLW31vPwL9FfyHyrjNcOQQ2CliKkhy9qxna57ZMGhVdNDZwSN7RY9
+ogGk+LpcIkpu11asoogM0gFPZIQajrVxlf0OSOMNAOUui3mMlrwPCMYcgaIVuQB5
+zrXHhbCwWs73RjiKap8itNpaufNyAtm450Jtk+0CgYEAhMQX66F0OvbG4cO3Z7Tm
+2BXFf1jYWEXpWRbW1I8WnJ3XQ4SVzXaAzDwYgfZqwWl6vCI67GiN3cCI2yeTFmwd
+LQyytp83ClxhXU+WosfNu85PlgMOd6K2h09DUG9E0iQKojHqEUQoQMefD5A/sDSh
+MVPj+/4r7usV+61ph2tleug=
-----END PRIVATE KEY-----
diff --git a/jstests/libs/ocsp/server_ocsp_revoked.pem.digest.sha1 b/jstests/libs/ocsp/server_ocsp_revoked.pem.digest.sha1
index ea21bad952b..bcd54829750 100644
--- a/jstests/libs/ocsp/server_ocsp_revoked.pem.digest.sha1
+++ b/jstests/libs/ocsp/server_ocsp_revoked.pem.digest.sha1
@@ -1 +1 @@
-6803B3D0A420C2CEDEDBF9959682912AEA39E132 \ No newline at end of file
+77FEAAF02C6BD0EB1A38F71B6BB5856C4CFA1149 \ No newline at end of file
diff --git a/jstests/libs/ocsp/server_ocsp_revoked.pem.digest.sha256 b/jstests/libs/ocsp/server_ocsp_revoked.pem.digest.sha256
index 6738c0e778b..787cf74ee2a 100644
--- a/jstests/libs/ocsp/server_ocsp_revoked.pem.digest.sha256
+++ b/jstests/libs/ocsp/server_ocsp_revoked.pem.digest.sha256
@@ -1 +1 @@
-11707AC2C19EE321EAB3D7E3561F10928A084601745D0294337773E433DB7694 \ No newline at end of file
+7E757666A72CD4373DDC3FD601080D6C250C0A59F8A06F64D92A3E78BAC36F5B \ No newline at end of file
diff --git a/jstests/libs/ocsp/server_signed_by_intermediate_ca_ocsp.pem b/jstests/libs/ocsp/server_signed_by_intermediate_ca_ocsp.pem
index c0b81588907..e3608401c7e 100644
--- a/jstests/libs/ocsp/server_signed_by_intermediate_ca_ocsp.pem
+++ b/jstests/libs/ocsp/server_signed_by_intermediate_ca_ocsp.pem
@@ -1,53 +1,53 @@
-----BEGIN CERTIFICATE-----
-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
+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
-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
+ZWRpYXRlIENBIGZvciBPQ1NQMB4XDTI0MDYwNTE2MTQ0OFoXDTI2MDkwNzE2MTQ0
+OFowgYIxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazEWMBQGA1UEBwwN
TmV3IFlvcmsgQ2l0eTEQMA4GA1UECgwHTW9uZ29EQjEPMA0GA1UECwwGS2VybmVs
MSUwIwYDVQQDDBxTZXJ2ZXIgT0NTUCBWaWEgSW50ZXJtZWRpYXRlMIIBIjANBgkq
-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
+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
-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
+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
-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
-6nhLQM8EjLMDRt+V6WHIHFI2pg==
+AQEAEqnp5qwXTuiWL9STiigM0RxUKcnEwVVjXbNxwarz4FyF8JCib8ytcbbSJHQq
+1QWlubP1Ovr4H1BZMkbmEQ0SMvPmtIooN9sXwHE+L+ugSbyynTkjZdhicNFEnDxI
+GqPtXIrLuIP3j8LOfNXopRhjvHO42aR61YWclgBysb8m7KL8CMKd6SYmRROHwi+a
+oYRUlczo2xNy9S+C6uLQ6Wixq1BG2xMOA7Ook6P/gJK/dp9Kq7uYWV1cpZRFYu9U
+HQT/KLtqPh+d09AvMVFIKZg/LtfyDfUN0u1LWFUn+61uuKcESXoIiB+xCUp4f8+W
+1A2VgnQvYrYDf81DxR7r2RttBg==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCvZ/EnMbKqBCM1
-6Bkoa11LbaD9RcWj5C5fu24Ckn4bh8wqFoI33AvO53lmfKsSFiveYxXQxL22UPjv
-2Kw0tCLV3237F/nCIbsr2fmuY+BjuIV3QXWHFOSRj9CRYegTb7/cbpuf9FRKUJ/D
-9tzAv1Qt9AMsOXBJK8gFcTQ/E/PT7RdDHpOU3XtNG7JsvrPJII80JmR1dd2ny2EU
-lh/hoAyrBtsH6QZu7fNvqB3LPT+07y9IwEAnEs3i6PPZvg1UDosZosJ2I8bI86xp
-sHD+MkXLKynt4GlGJRv2WIrY5/skis6ehEEu8RswTqJTrV61fGQb8xTUA/lFye8m
-EMqdNr+vAgMBAAECggEACsRvqj9Dv2oHm0yHFtMYZAPzyPhafIgKTLgdtay2bwwz
-/TVqgvFQDEBrVF48xhx0Tu94LFuXZbSsw1Ripc2VAdn4T1yWaVNWwQdda1YYNSbj
-koGDLGqc6U6RuArxixfmCCsGBJij//fZBteFj5NvIG8FLtbLzMISQjtDwMeBxTWD
-euwGTeGh76xzH2DAZATg1qgc96vikbnuvS8g9jCPYrNrQ/FcJl4qiyLgz9U1/BPf
-T2pwQJJ/unR8RMDFSL35/hjAp0X6AgFQckPA9SuTtwntBce5FxMa4hGFiWC2T6uj
-TeVQpkZx55NvmW3aE1SaXQ8gpLO0f/FcfriODX7iqQKBgQC+/ONfyM/63YKD+8gq
-ZAeXOmt26Ej0V4xMQQ7d/1u8ZRuEMZsw+QsLmK5BQedUVt2yPc2JxJRfMQE8T4im
-6xhA5LGbBn+baGMvHNk3N1sqslTbh+5yyUsPgcMRwzZbzdLOwtgxe/GnOeC6k8yC
-Yh8ethBwx1skginAkP07kxigmwKBgQDrHTgBmINdGXoTyh9XRA3nx0V7uUiDZXfg
-gvnaZQBxaO40c6GiUOUTJ8O2T43t1LD+lV5Gc6CVtKC4CKWl8qZRlW1yhc87Wbwt
-ZwuVGLQM/qSKXDmvzZdMlmlWB1w+yA3oN0QMapOEoif10j1qiUhrJ45of7ASk0XL
-Lj2SWGQ8fQKBgBK1i0CS12znziVHwPAGJIg3/NcFIkBtYx0FMoOkxEPMU8m7YkyF
-2QMlzcwuvI6Sg902GLBqRW6dylUyJVzUoueYf52EIXQD4dN3q/+wuImSNqXaxw0P
-kv7N42IWEXkkzIXcqHkQfze2f8FHQT10hz/m7e1eWhtVdOmcSnJPkpYJAoGBAOpX
-wz0D8NtYy27yJW7rrBh7bGw3b2lYN7YVlkfyKBDiD5tELbUFgG4pUk9i2ApX1trJ
-sp/yG/tbgF4ucD0JsHDcyaw+ZyG2/XMbpFXFu6DAJuypo+3ws39o5DEVQQJqkEIG
-49KkX8jxf3brSL/peb8kPDM4Ih1BoW0097XoWHBZAoGAMErndn7csxniE21xn0n9
-eCsEQK3j8EmrRxqZeBa4RnGcCMv9bnq7RuevztbejjAlCoGneJgP9zBFp+kZICLQ
-r2WjkDCR+UlY9wL3V7Kqg4/4DlPb5zkNFN0HpvK8SR62+QENHgmMUbKXa2rmJ+p8
-pBkxyirju8uHMfv10p6CrD8=
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCtnCKlds98bISl
+8OqzsbFZ4tSE9OXSi5S/V92p5CMY5hVrURW7hFuCevmp+aCU2YoparuL55AadpqU
+mSecE1MAxt+i5+/oeurx8Zr2Z+heOBsPJB7NN1kDUAP2+zLkHQkz/hiS8z8TmewW
+5ZqXdU2+8gsGRMWWIF6p2Fd5/30bBi1/1SNiIyknt+WMNXNmjczEYHzmIlmaD0UG
+7rK8o+jOpFN+AjFjZI3QJeD0eQjW2klDyooF3z9vN7gyjFEQPZyX/Ya8uYPFsI1q
+yRpteZFye7Pvk7SIyxT+EIHR5M6s2GTcoZ2UBrxY81HH+kewTRlM0eKkaqQAoEgz
+8+AYFarpAgMBAAECggEBAKxi1Bg+wEoJKzHm5fYmJDdfv6yBzE7jIIFayxTuHleT
+54LXUeAPzhni6FN6NpR26fS0MaP6/CD60gVpimY03f9wehG1gofyvaYeRMQVaytb
+RKslL5yQL8fVRQqSZfcSSdghn98Sv/hDp6UYugdYiClpB79ivFuUqsq1si7GnUAd
+n5BiqmN5qhkVHGZ5TfPCfDpcUbyGrbhzT5zWd+G4hAaIKB30Bw81szSTPGYbJ5CO
+sRnIsKg2sYmXK/V4SVFhZesXUE0NWdrKYgDjiuXOrhIFi7SWr5L+DY9kL+UXeFDw
+uk5NXjjN5hkHM7Z4mg2Z+NhfuZQSpJv8yDOuJHgOfrECgYEA4hjAHIiF5ss/wnDB
+WMAVcVgT7VwMJ8WcKQSb9e+UokP5ijRFOW0C53l506mPeIGlGqSMLumGoArlYWTH
+Xc2qdHV5olGbIV8GTC+mLk5VCjaFMJDd8KitNRNzmIjgpOLqxN4LEQxM+fhESOkZ
+HRfSdGE6UZFkDCEJeXV8KhagBj0CgYEAxJJFkn7x7kNHkSkM4lkEcbOSXCKsjlnu
+cw3sjA8Yy/DXmVZHaD9YSA2cCnyEVmAgluGD5+n/m1e+++ZuHRlABiHLXLpngiy9
+tXgvT6UDBQPDsiHIqLyROxhcjBfrYsMdT57Sa9KnkbgiNopyz1fzavXfgq1NMFF6
+gZcRaqWOLh0CgYEAzDpLHfr76LNjDoHHRCGNvOowZdElca+AFVUCg647di8scvgw
+J2UeoHQL5XNeEx4YQu6raZyrbFkrRURBCaxC8htDGanZFNW+3IaV93HuQuFogav5
+re7PNggx/HB3arlGEzn2iRmxVoI5PBrCApOIGHPSt+c6lfIpmrrSwznYpokCgYA6
+PHuQIzvZsuUJBHhktqqyZNj/ouYsZkhWndFuzSozgW7eZslRATNOZXnNQYaTcHc3
+PCiwFIs9oolaZ7JHvKtTJb/yAOeZkVfC45BgsCps2eioZYnlM7hzIYyJlKyP3e5Z
+IFyGxSoP6dV5AxtwgkYDckR9moo7vmfk7LSkO9gboQKBgQCHdvmgfqGOtTyXk84X
+bdnZ3zXGkCB10+jkIcEFnEJM8+iyzd1mgr8i1DLShU5MsAGgwXgt9GQkd6w9exov
+9kkKiMbvpLsFZBLYHPM60tgyaTv1r6EEpzJ6ihYCcEZljH9NKdrIiYdcyfRf2NoM
+sTPuS06jE5OSMqqh4yATmzR/SA==
-----END PRIVATE KEY-----
diff --git a/jstests/libs/ocsp/server_signed_by_intermediate_ca_ocsp.pem.digest.sha1 b/jstests/libs/ocsp/server_signed_by_intermediate_ca_ocsp.pem.digest.sha1
index 0edd448beab..66553ac3137 100644
--- a/jstests/libs/ocsp/server_signed_by_intermediate_ca_ocsp.pem.digest.sha1
+++ b/jstests/libs/ocsp/server_signed_by_intermediate_ca_ocsp.pem.digest.sha1
@@ -1 +1 @@
-A2623367A965AF55AD313546DBF3CE710AC067B4 \ No newline at end of file
+89383925C0E7D8EFF9E2F802329144EBB68E572A \ No newline at end of file
diff --git a/jstests/libs/ocsp/server_signed_by_intermediate_ca_ocsp.pem.digest.sha256 b/jstests/libs/ocsp/server_signed_by_intermediate_ca_ocsp.pem.digest.sha256
index 4a49afddc3f..c24c7ea2361 100644
--- a/jstests/libs/ocsp/server_signed_by_intermediate_ca_ocsp.pem.digest.sha256
+++ b/jstests/libs/ocsp/server_signed_by_intermediate_ca_ocsp.pem.digest.sha256
@@ -1 +1 @@
-7398F299F55216816AD1CD4883A680DF204C0034A5ACDF501C19118BB533666B \ No newline at end of file
+1338256C52160E21CEC363E7E9959594B2698B5D6FDBF10B3D763A487BD27045 \ No newline at end of file
diff --git a/jstests/libs/override_methods/validate_collections_on_shutdown.js b/jstests/libs/override_methods/validate_collections_on_shutdown.js
index 6d08f3ed2e0..fddacd444ad 100644
--- a/jstests/libs/override_methods/validate_collections_on_shutdown.js
+++ b/jstests/libs/override_methods/validate_collections_on_shutdown.js
@@ -128,7 +128,6 @@ MongoRunner.validateCollectionsCallback = function(port) {
const validateOptions = {
full: true,
enforceFastCount: true,
- warnOnSchemaValidation: true
};
// TODO (SERVER-24266): Once fast counts are tolerant to unclean shutdowns, remove the
// check for TestData.allowUncleanShutdowns.
diff --git a/jstests/libs/parallelTester.js b/jstests/libs/parallelTester.js
index 6ae5c470dad..a20a2c46751 100644
--- a/jstests/libs/parallelTester.js
+++ b/jstests/libs/parallelTester.js
@@ -128,248 +128,6 @@ if (typeof _threadInject != "undefined") {
assert.parallelTests(this.params, msg);
};
- // creates lists of tests from jstests dir in a format suitable for use by
- // ParallelTester.fileTester. The lists will be in random order.
- // n: number of lists to split these tests into
- ParallelTester.createJstestsLists = function(n) {
- var params = new Array();
- for (var i = 0; i < n; ++i) {
- params.push([]);
- }
-
- var makeKeys = function(a) {
- var ret = {};
- for (var i in a) {
- ret[a[i]] = 1;
- }
- return ret;
- };
-
- // some tests can't run in parallel with most others
- var skipTests = makeKeys([
- "indexb.js",
-
- // Tests that set a parameter that causes the server to ignore
- // long index keys.
- "index_bigkeys_nofail.js",
- "index_bigkeys_validation.js",
-
- // Tests that set the notablescan parameter, which makes queries fail rather than use a
- // non-indexed plan.
- "notablescan.js",
- "notablescan_capped.js",
-
- "mr_fail_invalid_js.js",
- "run_program1.js",
- "bench_test1.js",
-
- // These tests use getLog to examine the logs. Tests which do so shouldn't be run in
- // this suite because any test being run at the same time could conceivably spam the
- // logs so much that the line they are looking for has been rotated off the server's
- // in-memory buffer of log messages, which only stores the 1024 most recent operations.
- "comment_field.js",
- "getlog2.js",
- "logprocessdetails.js",
- "queryoptimizera.js",
- "log_remote_op_wait.js",
-
- "connections_opened.js", // counts connections, globally
- "opcounters_write_cmd.js",
- "set_param1.js", // changes global state
- "geo_update_btree2.js", // SERVER-11132 test disables table scans
- "update_setOnInsert.js", // SERVER-9982
- "max_time_ms.js", // Sensitive to query execution time, by design
- "autocomplete.js", // Likewise.
-
- // This overwrites MinKey/MaxKey's singleton which breaks
- // any other test that uses MinKey/MaxKey
- "type6.js",
-
- // Assumes that other tests are not creating cursors.
- "kill_cursors.js",
-
- // Assumes that other tests are not starting operations.
- "currentop_shell.js",
-
- // These tests check global command counters.
- "find_and_modify_metrics.js",
- "update_metrics.js",
-
- // Views tests
- "views/invalid_system_views.js", // Puts invalid view definitions in system.views.
- "views/views_all_commands.js", // Drops test DB.
- "views/view_with_invalid_dbname.js", // Puts invalid view definitions in system.views.
-
- // This test causes collMod commands to hang, which interferes with other tests running
- // collMod.
- "crud_ops_do_not_throw_locktimeout.js",
-
- // Can fail if isMaster takes too long on a loaded machine.
- "dbadmin.js",
-
- // Other tests will fail while the requireApiVersion server parameter is set.
- "require_api_version.js",
-
- // This test updates global memory usage counters in the bucket catalog in a way that
- // may affect other time-series tests running concurrently.
- "timeseries/timeseries_idle_buckets.js",
-
- // Assumes that other tests are not creating API version 1 incompatible data.
- "validate_db_metadata_command.js",
-
- // The tests in 'bench_test*.js' files use 'benchRun()'. The main purpose of
- // 'benchRun()' is for performance testing and the 'benchRun()' implementation itself
- // launches multiple threads internally, it's not necessary to keep 'bench_test*.js'
- // within the parallel test job.
- "bench_test1.js",
- "bench_test2.js",
-
- // These tests cause deletes and updates to hang, which may affect other tests running
- // concurrently.
- "timeseries/timeseries_delete_hint.js",
- "timeseries/timeseries_update_hint.js",
- "timeseries/timeseries_delete_concurrent.js",
- "timeseries/timeseries_update_concurrent.js",
-
- // These tests rely on no writes happening that would force oplog truncation.
- "write_change_stream_pit_preimage_in_transaction.js",
- "write_change_stream_pit_preimage.js",
-
- // These tests convert a non-unique index to a unique one, which is not compatible
- // when running against inMemory storage engine variants. Since this test only fails
- // in the parallel tester, which does not respect test tags, we omit the tests
- // instead of manually checking TestData values in the mongo shell for the Evergreen
- // variant.
- "collmod_convert_index_uniqueness.js",
- "collmod_convert_to_unique_apply_ops.js",
- "collmod_convert_to_unique_violations.js",
- "collmod_convert_to_unique_violations_size_limit.js",
-
- // This test sets a server parameter.
- "group_lookup_with_canonical_query_prefix.js",
-
- // This test requires latches to be enabled, which isn't true for all variants.
- "latch_analyzer.js",
- "currentop_waiting_for_latch.js"
- ]);
-
- // Get files, including files in subdirectories.
- var getFilesRecursive = function(dir) {
- var files = listFiles(dir);
- var fileList = [];
- files.forEach(file => {
- if (file.isDirectory) {
- getFilesRecursive(file.name).forEach(subDirFile => fileList.push(subDirFile));
- } else {
- fileList.push(file);
- }
- });
- return fileList;
- };
-
- // Transactions are not supported on standalone nodes so we do not run them here.
- // NOTE: We need to take substring of the full test path to ensure that 'jstests/core/' is
- // not included.
- const txnsTestFiles =
- getFilesRecursive("jstests/core/txns/")
- .map(fullPathToTest => fullPathToTest.name.substring("jstests/core/".length));
- Object.assign(skipTests, makeKeys(txnsTestFiles));
-
- var parallelFilesDir = "jstests/core";
-
- // some tests can't be run in parallel with each other
- var serialTestsArr = [
- // These tests use fsyncLock.
- parallelFilesDir + "/fsync.js",
- parallelFilesDir + "/currentop.js",
- parallelFilesDir + "/killop_drop_collection.js",
-
- // These tests expect the profiler to be on or off at specific points. They should not
- // be run in parallel with tests that perform fsyncLock. User operations skip writing to
- // the system.profile collection while the server is fsyncLocked.
- //
- // Most profiler tests can be run in parallel with each other as they use test-specific
- // databases, with the exception of tests which modify slowms or the profiler's sampling
- // rate, since those affect profile settings globally.
- parallelFilesDir + "/apitest_db_profile_level.js",
- parallelFilesDir + "/geo_s2cursorlimitskip.js",
- parallelFilesDir + "/profile1.js",
- parallelFilesDir + "/profile2.js",
- parallelFilesDir + "/profile3.js",
- parallelFilesDir + "/profile_agg.js",
- parallelFilesDir + "/profile_count.js",
- parallelFilesDir + "/profile_delete.js",
- parallelFilesDir + "/profile_distinct.js",
- parallelFilesDir + "/profile_find.js",
- parallelFilesDir + "/profile_findandmodify.js",
- parallelFilesDir + "/profile_getmore.js",
- parallelFilesDir + "/profile_hide_index.js",
- parallelFilesDir + "/profile_insert.js",
- parallelFilesDir + "/profile_list_collections.js",
- parallelFilesDir + "/profile_list_indexes.js",
- parallelFilesDir + "/profile_mapreduce.js",
- parallelFilesDir + "/profile_no_such_db.js",
- parallelFilesDir + "/profile_query_hash.js",
- parallelFilesDir + "/profile_sampling.js",
- parallelFilesDir + "/profile_update.js",
- parallelFilesDir + "/cached_plan_trial_does_not_discard_work.js",
- parallelFilesDir + "/timeseries/bucket_unpacking_with_sort_plan_cache.js",
-
- // These tests rely on a deterministically refreshable logical session cache. If they
- // run in parallel, they could interfere with the cache and cause failures.
- parallelFilesDir + "/list_all_local_sessions.js",
- parallelFilesDir + "/list_all_sessions.js",
- parallelFilesDir + "/list_sessions.js",
- ];
- var serialTests = makeKeys(serialTestsArr);
-
- // prefix the first thread with the serialTests
- // (which we will exclude from the rest of the threads below)
- params[0] = serialTestsArr;
- var files = getFilesRecursive(parallelFilesDir);
- files = Array.shuffle(files);
-
- var i = 0;
- files.forEach(function(x) {
- if ((/[\/\\]_/.test(x.name)) || (!/\.js$/.test(x.name)) ||
- (x.name.match(parallelFilesDir + "/(.*\.js)")[1] in skipTests) || //
- (x.name in serialTests)) {
- print(" >>>>>>>>>>>>>>> skipping " + x.name);
- return;
- }
- // add the test to run in one of the threads.
- params[i % n].push(x.name);
- ++i;
- });
-
- // randomize ordering of the serialTests
- params[0] = Array.shuffle(params[0]);
-
- for (var i in params) {
- params[i].unshift(i);
- }
-
- return params;
- };
-
- // runs a set of test files
- // first argument is an identifier for this tester, remaining arguments are file names
- ParallelTester.fileTester = function() {
- var args = Array.from(arguments);
- var suite = args.shift();
- args.forEach(function(x) {
- print(" S" + suite + " Test : " + x + " ...");
- var time = Date.timeFunc(function() {
- // Create a new connection to the db for each file. If tests share the same
- // connection it can create difficult to debug issues.
- db = new Mongo(db.getMongo().host).getDB(db.getName());
- gc();
- load(x);
- }, 1);
- print(" S" + suite + " Test : " + x + " " + time + "ms");
- });
- };
-
// params: array of arrays, each element of which consists of a function followed
// by zero or more arguments to that function. Each function and its arguments will
// be called in a separate thread.
diff --git a/jstests/libs/password_protected.pem b/jstests/libs/password_protected.pem
index 689043d1c9b..9a70f6631ed 100644
--- a/jstests/libs/password_protected.pem
+++ b/jstests/libs/password_protected.pem
@@ -4,58 +4,58 @@
# Server cerificate using an encrypted private key.
-----BEGIN CERTIFICATE-----
-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
+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
-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
+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
-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
+c2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA54WS1z9Lh9pe
+xGB4+3xAG8ZPc7kUDdNpE8eypK253akV8TVfw4Gm8Bcc/1GZuflZfNexLyM6JA6m
+8+IEHG2VjxcTVpqgaqUiPpJbcT/2uHG/8wOyV7JpfuUZY7PWzbWZ8HwLBli80J1o
+2X0pzRxY5njXUPADuK576C/s3Tu7TwMFiFlo2+fpsH/bzMxeSuBmEAMttN9j50W2
+0EcI42QOQQRGO/r1Ku4M9H0eKuk51EAjgl2TW3ZnvUI+H1v/vmBuCmQ75TiVpvdc
+nHpx8ng62zeHd6FCLrHYpxC8/G7bOtAe6ey4c2dUanmoZu+e9r5FlEIqadeQuPyq
+HVcBBBXtQQIDAQABo4H5MIH2MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMBMGA1Ud
+JQQMMAoGCCsGAQUFBwMBMB0GA1UdDgQWBBSBa3Py6ztz7rJc0ZGdgQQEgubFjjCB
iwYDVR0jBIGDMIGAoXikdjB0MQswCQYDVQQGEwJVUzERMA8GA1UECAwITmV3IFlv
cmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAOBgNVBAoMB01vbmdvREIxDzAN
-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
-pre6yWvmcfWQWPJJ
+BgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVsIFRlc3QgQ0GCBCBp1p8wGgYD
+VR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEBCwUAA4IBAQAvmZ4k
+r06ElL2ADQMzrgnSXyD4ODDYScG2PQ7UyoZYXchtGyAJbnZgBEBlF5nXN8u7Y2lI
+UD3RT9f6RHd1weHwtj8U+dxVwH2J38E/Y9PRW2taJwEtngKfdZpJeA9+Nxl9FZqG
+0SllNXQhnQ7fJlEneMGViPiAzjqBmctLdlcatAPK6LLtWrZFw+ss7OaTmseqYJtt
+/FPEp4AAOFozfIUXkH2qVjzCUEogEVS7+Yl0eKn2F6mnQR6B/OwEXkridxZ7qt/u
+5qLwNiJFQUII6Yl91SlhWjcmyIhNoywcdsE1RyO6No5/LN8953Cc9BaOvCRwOyAL
+8g9Z2N2IVvRCI4QE
-----END CERTIFICATE-----
-----BEGIN ENCRYPTED PRIVATE KEY-----
-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
+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
-----END ENCRYPTED PRIVATE KEY-----
diff --git a/jstests/libs/password_protected.pem.digest.sha1 b/jstests/libs/password_protected.pem.digest.sha1
index 5731a516135..a9674bc9354 100644
--- a/jstests/libs/password_protected.pem.digest.sha1
+++ b/jstests/libs/password_protected.pem.digest.sha1
@@ -1 +1 @@
-455FB9070ABADB1C3B3080960E8BC31A3F9541C5 \ No newline at end of file
+C3FC87D646089FBAAFF6B5D9D52C2982C46B5F54 \ No newline at end of file
diff --git a/jstests/libs/password_protected.pem.digest.sha256 b/jstests/libs/password_protected.pem.digest.sha256
index 998d53ea04f..6936a141729 100644
--- a/jstests/libs/password_protected.pem.digest.sha256
+++ b/jstests/libs/password_protected.pem.digest.sha256
@@ -1 +1 @@
-C219188BCD14DF0A17378F03A0162BFAD6883CE4A0D2913DDBE2D492F72FD3D6 \ No newline at end of file
+D5203BBD7CAEACF2C1DAE5F4C68F7624A97960C5A45D3CD74D862CD2A3C51FE8 \ No newline at end of file
diff --git a/jstests/libs/query_stats_utils.js b/jstests/libs/query_stats_utils.js
new file mode 100644
index 00000000000..bea8f55341a
--- /dev/null
+++ b/jstests/libs/query_stats_utils.js
@@ -0,0 +1,490 @@
+load("jstests/libs/fixture_helpers.js"); // For FixtureHelpers
+const kShellApplicationName = "MongoDB Shell";
+const kDefaultQueryStatsHmacKey = BinData(8, "MjM0NTY3ODkxMDExMTIxMzE0MTUxNjE3MTgxOTIwMjE=");
+
+/**
+ * Utility for checking that the aggregated queryStats metrics are logical (follows sum >= max >=
+ * min, and sum = max = min if only one execution).
+ */
+function verifyMetrics(batch) {
+ batch.forEach(element => {
+ if (element.metrics.execCount === 1) {
+ for (const [metricName, summaryValues] of Object.entries(element.metrics)) {
+ // Skip over fields that aren't aggregated metrics with sum/min/max (execCount,
+ // lastExecutionMicros).
+ if (summaryValues.sum === undefined) {
+ continue;
+ }
+ const debugInfo = {[metricName]: summaryValues};
+ // If there has only been one execution, all metrics should have min, max, and sum
+ // equal to each other.
+ assert.eq(summaryValues.sum, summaryValues.min, debugInfo);
+ assert.eq(summaryValues.sum, summaryValues.max, debugInfo);
+ assert.eq(summaryValues.min, summaryValues.max, debugInfo);
+ }
+ } else {
+ for (const [metricName, summaryValues] of Object.entries(element.metrics)) {
+ // Skip over fields that aren't aggregated metrics with sum/min/max (execCount,
+ // lastExecutionMicros).
+ if (summaryValues.sum === undefined) {
+ continue;
+ }
+ const debugInfo = {[metricName]: summaryValues};
+ assert.gte(summaryValues.sum, summaryValues.min, debugInfo);
+ assert.gte(summaryValues.sum, summaryValues.max, debugInfo);
+ assert.lte(summaryValues.min, summaryValues.max, debugInfo);
+ }
+ }
+ });
+}
+
+/**
+ * Return the latest query stats entry from the given collection. Only returns query shapes
+ * generated by the shell that is running tests.
+ *
+ * @param conn - connection to database
+ * @param {object} options {
+ * {String} collName - name of collection
+ * {object} - extraMatch - optional argument that can be used to filter the pipeline
+ * }
+ */
+function getLatestQueryStatsEntry(conn, options = {
+ collName: ""
+}) {
+ let sortedEntries = getQueryStats(
+ conn, Object.merge({customSort: {"metrics.latestSeenTimestamp": -1}}, options));
+ assert.neq([], sortedEntries);
+ return sortedEntries[0];
+}
+
+/**
+ * Collect query stats from a given collection. Only include query shapes generated by the shell
+ * that is running tests.
+ *
+ * @param conn - connection to database
+ * @param {object} options {
+ * {String} collName - name of collection
+ * {object} - extraMatch - optional argument that can be used to filter the pipeline
+ * {object} - customSort - optional custom sort order - otherwise sorted by 'key' just to be
+ * deterministic.
+ * }
+ */
+function getQueryStats(conn, options = {
+ collName: ""
+}) {
+ let match =
+ Object.assign({"key.client.application.name": kShellApplicationName}, options.extraMatch);
+ if (options.collName && options.collName) {
+ match["key.queryShape.cmdNs.coll"] = options.collName;
+ }
+ const result = conn.adminCommand({
+ aggregate: 1,
+ pipeline: [{$queryStats: {}}, {$sort: (options.customSort || {key: 1})}, {$match: match}],
+ cursor: {}
+ });
+ assert.commandWorked(result);
+ return result.cursor.firstBatch;
+}
+
+/**
+ * @param {object} conn - connection to database
+ * @param {object} options {
+ * {BinData} hmacKey
+ * {String} collName - name of collection
+ * {boolean} transformIdentifiers - whether to include transform identifiers
+ * }
+ */
+function getQueryStatsFindCmd(conn, options = {
+ collName: "",
+ transformIdentifiers: false,
+ hmacKey: kDefaultQueryStatsHmacKey
+}) {
+ let matchExpr = {
+ "key.queryShape.command": "find",
+ "key.client.application.name": kShellApplicationName
+ };
+ if (options.collName) {
+ matchExpr["key.queryShape.cmdNs.coll"] = options.collName;
+ }
+ // Filter out agg queries, including $queryStats.
+ var pipeline;
+ if (options.transformIdentifiers) {
+ pipeline = [
+ {
+ $queryStats: {
+ transformIdentifiers: {
+ algorithm: "hmac-sha-256",
+ hmacKey: options.hmacKey ? options.hmacKey : kDefaultQueryStatsHmacKey
+ }
+ }
+ },
+ {$match: matchExpr},
+ // Sort on queryStats key so entries are in a deterministic order.
+ {$sort: {key: 1}},
+ ];
+ } else {
+ pipeline = [
+ {$queryStats: {}},
+ {$match: matchExpr},
+ // Sort on queryStats key so entries are in a deterministic order.
+ {$sort: {key: 1}},
+ ];
+ }
+ const result = conn.adminCommand({aggregate: 1, pipeline: pipeline, cursor: {}});
+ assert.commandWorked(result);
+ return result.cursor.firstBatch;
+}
+
+/**
+ * Collects query stats from any aggregate command query shapes (with $queryStats requests filtered
+ * out) that were generated by the shell that is running tests.
+ *
+ * /**
+ * @param {object} conn - connection to database
+ * @param {object} options {
+ * {BinData} hmacKey
+ * {boolean} transformIdentifiers - whether to include transform identifiers
+ * }
+ */
+function getQueryStatsAggCmd(db, options = {
+ transformIdentifiers: false,
+ hmacKey: kDefaultQueryStatsHmacKey
+}) {
+ var pipeline;
+ let queryStatsStage = {$queryStats: {}};
+ if (options.transformIdentifiers) {
+ queryStatsStage = {
+ $queryStats: {
+ transformIdentifiers: {
+ algorithm: "hmac-sha-256",
+ hmacKey: options.hmacKey ? options.hmacKey : kDefaultQueryStatsHmacKey
+ }
+ }
+ };
+ }
+
+ pipeline = [
+ queryStatsStage,
+ // Filter out find queries and $queryStats aggregations.
+ {
+ $match: {
+ "key.queryShape.command": "aggregate",
+ "key.queryShape.pipeline.0.$queryStats": {$exists: false},
+ "key.client.application.name": kShellApplicationName
+ }
+ },
+ // Sort on key so entries are in a deterministic order.
+ {$sort: {key: 1}},
+ ];
+ return db.getSiblingDB("admin").aggregate(pipeline).toArray();
+}
+
+function confirmAllExpectedFieldsPresent(expectedKey, resultingKey) {
+ let fieldsCounter = 0;
+ for (const field in resultingKey) {
+ fieldsCounter++;
+ if (field === "client") {
+ // client meta data is environment/machine dependent, so do not
+ // assert on fields or specific fields other than the application name.
+ assert.eq(resultingKey.client.application.name, kShellApplicationName);
+ // SERVER-83926 We should never report the "mongos" section, since it is too specific
+ // and would result in too many different query shapes.
+ assert(!resultingKey.client.hasOwnProperty("mongos"), resultingKey.client);
+ continue;
+ }
+ if (!expectedKey.hasOwnProperty(field)) {
+ print("Field present in actual object but missing from expected: " + field);
+ print("Expected " + tojson(expectedKey));
+ print("Actual " + tojson(resultingKey));
+ }
+ assert(expectedKey.hasOwnProperty(field), field);
+ assert.eq(expectedKey[field], resultingKey[field]);
+ }
+ // Make sure the resulting key isn't missing any fields.
+ assert.eq(fieldsCounter, Object.keys(expectedKey).length, resultingKey);
+}
+
+function assertExpectedResults(results,
+ expectedQueryStatsKey,
+ expectedExecCount,
+ expectedDocsReturnedSum,
+ expectedDocsReturnedMax,
+ expectedDocsReturnedMin,
+ expectedDocsReturnedSumOfSq,
+ getMores) {
+ const {key, keyHash, metrics, asOf} = results;
+ confirmAllExpectedFieldsPresent(expectedQueryStatsKey, key);
+ assert.eq(expectedExecCount, metrics.execCount);
+ assert.docEq({
+ sum: NumberLong(expectedDocsReturnedSum),
+ max: NumberLong(expectedDocsReturnedMax),
+ min: NumberLong(expectedDocsReturnedMin),
+ sumOfSquares: expectedDocsReturnedSumOfSq
+ },
+ metrics.docsReturned);
+
+ const {
+ firstSeenTimestamp,
+ latestSeenTimestamp,
+ lastExecutionMicros,
+ totalExecMicros,
+ firstResponseExecMicros
+ } = metrics;
+
+ // The tests can't predict exact timings, so just assert these three fields have been set (are
+ // non-zero).
+ assert.neq(lastExecutionMicros, NumberLong(0));
+ assert.neq(firstSeenTimestamp.getTime(), 0);
+ assert.neq(latestSeenTimestamp.getTime(), 0);
+ assert.neq(asOf.getTime(), 0);
+ assert.neq(keyHash.length, 0);
+
+ const distributionFields = ['sum', 'max', 'min', 'sumOfSquares'];
+ for (const field of distributionFields) {
+ assert.neq(totalExecMicros[field], NumberLong(0));
+ assert.neq(firstResponseExecMicros[field], NumberLong(0));
+ if (getMores) {
+ // If there are getMore calls, totalExecMicros fields should be greater than or equal to
+ // firstResponseExecMicros.
+ if (field == 'min' || field == 'max') {
+ // In the case that we've executed multiple queries with the same shape, it is
+ // possible for the min or max to be equal.
+ assert.gte(totalExecMicros[field], firstResponseExecMicros[field]);
+ } else {
+ assert(bsonWoCompare(totalExecMicros[field], firstResponseExecMicros[field]) > 0);
+ }
+ } else {
+ // If there are no getMore calls, totalExecMicros fields should be equal to
+ // firstResponseExecMicros.
+ assert.eq(totalExecMicros[field], firstResponseExecMicros[field]);
+ }
+ }
+}
+
+function asFieldPath(str) {
+ return "$" + str;
+}
+
+function asVarRef(str) {
+ return "$$" + str;
+}
+
+function resetQueryStatsStore(conn, queryStatsStoreSize) {
+ // Set the cache size to 0MB to clear the queryStats store, and then reset to
+ // queryStatsStoreSize.
+ assert.commandWorked(conn.adminCommand({setParameter: 1, internalQueryStatsCacheSize: "0MB"}));
+ assert.commandWorked(
+ conn.adminCommand({setParameter: 1, internalQueryStatsCacheSize: queryStatsStoreSize}));
+}
+
+/**
+ * Checks that the given object contains the dottedPath.
+ * @param {object} object
+ * @param {string} dottedPath
+ */
+function hasValueAtPath(object, dottedPath) {
+ let nestedFields = dottedPath.split(".");
+ for (const nestedField of nestedFields) {
+ if (!object.hasOwnProperty(nestedField)) {
+ return false;
+ }
+ object = object[nestedField];
+ }
+ return true;
+}
+
+/**
+ * Returns the object's value at the dottedPath.
+ * @param {object} object
+ * @param {string} dottedPath
+ */
+function getValueAtPath(object, dottedPath) {
+ let nestedFields = dottedPath.split(".");
+ for (const nestedField of nestedFields) {
+ if (!object.hasOwnProperty(nestedField)) {
+ return false;
+ }
+ object = object[nestedField];
+ }
+ return object;
+}
+
+/**
+ * Runs an assertion callback function on a node with query stats enabled - once with a mongod, and
+ * once with a mongos.
+ * @param {String} collName - The desired collection name to use. The db will be "test".
+ * @param {Function} callbackFn - The function to make the assertion on each connection.
+ */
+function withQueryStatsEnabled(collName, callbackFn) {
+ const options = {
+ setParameter: {internalQueryStatsRateLimit: -1},
+ };
+
+ {
+ const conn = MongoRunner.runMongod(options);
+ const testDB = conn.getDB("test");
+ var coll = testDB[collName];
+ coll.drop();
+
+ callbackFn(coll);
+ MongoRunner.stopMongod(conn);
+ }
+
+ {
+ const st = new ShardingTest({shards: 2, mongosOptions: options});
+ const testDB = st.getDB("test");
+ var coll = testDB[collName];
+ coll.drop();
+ st.shardColl(coll, {_id: 1}, {_id: 1});
+
+ callbackFn(coll);
+ st.stop();
+ }
+}
+/**
+ * We run the command on an new database with an empty collection that has an index {v:1}. We then
+ * obtain the queryStats key entry that is created and check the following things.
+ * 1. The command associated with the key matches the commandName.
+ * 2. The fields nested inside of queryShape field of the key exactly matches those given by
+ * shapeFields.
+ * 3. The list of fields of the key exactly matches those given by keyFields.
+ * /**
+ * @param {string} commandName - string name of type of command, ex. "find" or "aggregate"
+ * @param {object} commandObj - The command that will be run
+ * @param {object} shapeFields - List of fields that are part of the queryShape and should be nested
+ * inside of Query Shape
+ * @param {object} keyFields - List of outer fields not nested inside queryShape but should be part
+ * of the key
+ */
+function runCommandAndValidateQueryStats({coll, commandName, commandObj, shapeFields, keyFields}) {
+ const testDB = coll.getDB();
+ assert.commandWorked(testDB.runCommand(commandObj));
+ const entry = getLatestQueryStatsEntry(testDB.getMongo(), {collName: coll.getName()});
+
+ assert.eq(entry.key.queryShape.command, commandName);
+ const kApplicationName = "MongoDB Shell";
+ assert.eq(entry.key.client.application.name, kApplicationName);
+
+ {
+ assert(hasValueAtPath(entry, "key.client.driver"), entry);
+ assert(hasValueAtPath(entry, "key.client.driver.name"), entry);
+ assert(hasValueAtPath(entry, "key.client.driver.version"), entry);
+ }
+
+ {
+ assert(hasValueAtPath(entry, "key.client.os"), entry);
+ assert(hasValueAtPath(entry, "key.client.os.type"), entry);
+ assert(hasValueAtPath(entry, "key.client.os.name"), entry);
+ assert(hasValueAtPath(entry, "key.client.os.architecture"), entry);
+ assert(hasValueAtPath(entry, "key.client.os.version"), entry);
+ }
+
+ // SERVER-83926 Make sure the mongos section doesn't show up.
+ assert(!hasValueAtPath(entry, "key.client.mongos"), entry);
+
+ // Every path in shapeFields is in the queryShape.
+ let shapeFieldsPrefixes = [];
+ for (const field of shapeFields) {
+ assert(hasValueAtPath(entry.key.queryShape, field),
+ `QueryShape: ${tojson(entry.key.queryShape)} is missing field ${field}`);
+ shapeFieldsPrefixes.push(field.split(".")[0]);
+ }
+
+ // Every field in queryShape is in shapeFields or is the base of a path in shapeFields.
+ for (const field in entry.key.queryShape) {
+ assert(shapeFieldsPrefixes.includes(field),
+ `Unexpected field ${field} in shape for ${commandName}`);
+ }
+
+ // Every path in keyFields is in the key.
+ let keyFieldsPrefixes = [];
+ for (const field of keyFields) {
+ if (field === "collectionType" && FixtureHelpers.isMongos(testDB)) {
+ // TODO SERVER-76263 collectionType is not yet available on mongos.
+ continue;
+ }
+ assert(hasValueAtPath(entry.key, field),
+ `Key: ${tojson(entry.key)} is missing field ${field}`);
+ keyFieldsPrefixes.push(field.split(".")[0]);
+ }
+
+ // Every field in the key is in keyFields or is the base of a path in keyFields.
+ for (const field in entry.key) {
+ assert(keyFieldsPrefixes.includes(field),
+ `Unexpected field ${field} in key for ${commandName}`);
+ }
+
+ // $hint can only be string(index name) or object (index spec).
+ assert.throwsWithCode(() => {
+ coll.find({v: {$eq: 2}}).hint({'v': 60, $hint: -128}).itcount();
+ }, ErrorCodes.BadValue);
+}
+
+/**
+ * Helper function to verify that each of the query stats entries has a unique hash and returns a
+ * list of the hashes.
+ * @param {list} entries - List of entries returned from $queryStats.
+ * @returns {list} list of unique hashes corresponding to the entries.
+ */
+function getQueryStatsKeyHashes(entries) {
+ const keyHashes = {};
+ for (const entry of entries) {
+ assert(entry.keyHash && entry.keyHash !== "",
+ `Entry does not have a 'keyHash' field: ${tojson(entry)}`);
+ keyHashes[entry.keyHash] = entry;
+ }
+ // We expect all keys and hashes to be unique, so assert that we have as many unique hashes as
+ // entries.
+ const keyHashArray = Object.keys(keyHashes);
+ assert.eq(keyHashArray.length, entries.length, tojson(entries));
+ return keyHashArray;
+}
+
+/**
+ * Given a query stats entry, and stats that the entry should have, this function checks that the
+ * entry is the result of a change stream request and that the metrics are what are expected.
+ */
+function checkChangeStreamEntry({queryStatsEntry, db, collectionName, numExecs, numDocsReturned}) {
+ assert.eq(collectionName, queryStatsEntry.key.queryShape.cmdNs.coll);
+
+ // Confirm entry is a change stream request.
+ const pipelineShape = queryStatsEntry.key.queryShape.pipeline;
+ assert(pipelineShape[0].hasOwnProperty("$changeStream"), pipelineShape);
+
+ // TODO SERVER-76263 Support reporting 'collectionType' on a sharded cluster.
+ if (!FixtureHelpers.isMongos(db)) {
+ assert.eq("changeStream", queryStatsEntry.key.collectionType);
+ }
+
+ // Checking that metrics match expected metrics.
+ assert.eq(queryStatsEntry.metrics.execCount, numExecs);
+ assert.eq(queryStatsEntry.metrics.docsReturned.sum, numDocsReturned);
+
+ // FirstResponseExecMicros and TotalExecMicros match since each getMore is recorded as a new
+ // first response.
+ assert.eq(queryStatsEntry.metrics.totalExecMicros.sum,
+ queryStatsEntry.metrics.firstResponseExecMicros.sum);
+ assert.eq(queryStatsEntry.metrics.totalExecMicros.max,
+ queryStatsEntry.metrics.firstResponseExecMicros.max);
+ assert.eq(queryStatsEntry.metrics.totalExecMicros.min,
+ queryStatsEntry.metrics.firstResponseExecMicros.min);
+}
+
+/**
+ * Given a change stream cursor, this function will return the number of getMores executed until the
+ * change stream is updated. This only applies when the cursor is waiting for one new document (or
+ * set the batchSize of the input cursor to 1) so each hasNext() call will correspond to an internal
+ * getMore.
+ */
+function getNumberOfGetMoresUntilNextDocForChangeStream(cursor) {
+ let numGetMores = 0;
+ assert.soon(() => {
+ numGetMores++;
+ return cursor.hasNext();
+ });
+
+ // Get the document that is on the cursor to reset the cursor to a state where calling hasNext()
+ // corresponds to a getMore.
+ cursor.next();
+ return numGetMores;
+}
diff --git a/jstests/libs/rollover_ca.pem b/jstests/libs/rollover_ca.pem
index f47f454efc9..51bc6dc35f2 100644
--- a/jstests/libs/rollover_ca.pem
+++ b/jstests/libs/rollover_ca.pem
@@ -3,53 +3,53 @@
#
# Separate CA used during rollover tests.
-----BEGIN CERTIFICATE-----
-MIIDxzCCAq+gAwIBAgIEKW01kTANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJV
+MIIDxzCCAq+gAwIBAgIEFWtNBzANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxETAPBgNVBAcMCE5ldyBZb3JrMRYwFAYDVQQK
DA1Nb25nb0RCLCBJbmMuMQ8wDQYDVQQLDAZLZXJuZWwxIDAeBgNVBAMMF0tlcm5l
-bCBSb2xsb3ZlciBUZXN0IENBMB4XDTI0MDExNTE2MTE0NVoXDTI2MDQxODE2MTE0
-NVowfjELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMREwDwYDVQQHDAhO
+bCBSb2xsb3ZlciBUZXN0IENBMB4XDTI0MDYwNTE2MTQ0OVoXDTI2MDkwNzE2MTQ0
+OVowfjELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMREwDwYDVQQHDAhO
ZXcgWW9yazEWMBQGA1UECgwNTW9uZ29EQiwgSW5jLjEPMA0GA1UECwwGS2VybmVs
MSAwHgYDVQQDDBdLZXJuZWwgUm9sbG92ZXIgVGVzdCBDQTCCASIwDQYJKoZIhvcN
-AQEBBQADggEPADCCAQoCggEBAJ+sJVgoyUJF385V+niODOypGJlKO+atBCQept+Y
-Ob7RWYkT0134S/C+WEhFTiSnWeQviAbBPMQHVKCNTfq0nON8BJUU7Yr+RyLDjM73
-ZQMDAXlcHBknYZs21f9w81Rcow7b4f4m7L7LflFZFqdi8fOocNWtmWj0wlOADmYr
-Iwfx4P6yv6yqzKBxpPOIyNj6PqiI5jxFmDnagRk5PVSMfljSrwUad7/2nLNmP9VH
-pt74ygngifbGpy+Ne9S/e/cqccLj6e6JCyJFWJscJqDBUiYhNW6Zcf2IkEaZS4l5
-tpLSm4h27l+DlxbdtCtgrBB+HE2w+7N4fzvtF3QpM2s7l4MCAwEAAaNNMEswDwYD
-VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFPv7Ltp/bmJI
-ah87Q6O3oMcTm7bHMAkGA1UdIwQCMAAwDQYJKoZIhvcNAQELBQADggEBAIjIO9ju
-U7XxbCwIr9J2dOHc8P+L3kMx35A2p7mf+HBc56eRLAou5qFN2fUa0csFLqeZIHgz
-48/6RXEBSVy5nakkBwpceFNoqtB8Xry65BFDurUpXmrMFYFaiXK8BdOOhPiNtegQ
-Qj3XiopkiuuECYDCHwvHVavhYXIGpvFrPxi+pQSUKeQsHGfMrCp3LFPGrTXwAenW
-Ct6uiWPCuaidfPa2PlRlzWzrqeFvOvw5D6oPCNukIXf4w7b34wA1acBZDR7urmS8
-FkDX1CUGmB7isnufcmPzu3s50g9HJhyQx4WJ+dJP/p6sUQD8RgfMfygTip12D232
-msxGFHJ5jI2sNgg=
+AQEBBQADggEPADCCAQoCggEBAL8LbPMQ3NDaQ63c0gzrFHMMPLEuqkTMrgB1tZyP
+jReoFepvnS69vtFRAHH2o8belcsErvbSdymS/HaqBkGDU4zujvf3PqSNC8YckiSG
+hgVAUUFmbxuGKYWBnyftypx2M2VhaiRiHzX9wE/Gvmq4kkQLm0hD+RgltbcuZrgp
+red95OxJo8+XfmeQJhCtksS/PNnm/fedXeI2iYLap3bvpH3Fj78GuQO20GRpf+kN
+3Rt4lPTMLrua2kXCyk264o6LAjoteG49ydZW9aqq76+TT4keVf+olsnn6RzjsG5E
+UyjxU2D3rvwhA/1HLgJFboGgBsPBXCTutEQvcCWsV2cZZV0CAwEAAaNNMEswDwYD
+VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFI54l4o3TQZY
+fHBkR+qPEOpCzvx2MAkGA1UdIwQCMAAwDQYJKoZIhvcNAQELBQADggEBACO/I0lM
+Cjl8a31307m0c096T5I0EBUUD+XzlmwWNCK/CC2EaSBeOPZ/bzSw+vyrUVKn4ZcS
+7hnkcEwZQ3BvYdj0xmP/pYQrxsvYJeGas1dfr433U8VZJwo3apapm4k+9tJYx77F
+vkICdD+sOK/7xGDv+Z+spLmIui81w0qdVKej6160dhzCoaK1WLpdHqKtCsC27gjN
+79wb0BNHYdRqgBaBM/O/+Xi0fbW+SckV9lsI23k7FEFbPDfkgOIsl5tvw1OzAjdt
+t5F7cLz0hXAB4UhjiQmDF1cQnpu0ggaPdsliW9BztiZxkeHPlxnAnk+m4W1aH+Qk
+0NoC+8kLh4RZtnM=
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCfrCVYKMlCRd/O
-Vfp4jgzsqRiZSjvmrQQkHqbfmDm+0VmJE9Nd+EvwvlhIRU4kp1nkL4gGwTzEB1Sg
-jU36tJzjfASVFO2K/kciw4zO92UDAwF5XBwZJ2GbNtX/cPNUXKMO2+H+Juy+y35R
-WRanYvHzqHDVrZlo9MJTgA5mKyMH8eD+sr+sqsygcaTziMjY+j6oiOY8RZg52oEZ
-OT1UjH5Y0q8FGne/9pyzZj/VR6be+MoJ4In2xqcvjXvUv3v3KnHC4+nuiQsiRVib
-HCagwVImITVumXH9iJBGmUuJebaS0puIdu5fg5cW3bQrYKwQfhxNsPuzeH877Rd0
-KTNrO5eDAgMBAAECggEASQ35NCHNG25e3MgHxlqv3SPs5k3JpFwq1d/UV98NJJoi
-Tg5tGcR98lMUj1RuUWTkQvvgT77f74yvEpo0QG2cjpRygEdH+90lbOltplAYvk0E
-wqL7FCMpjFuFg88I9eNAk47VEnR6wzzVuaB6NfGWY/YAUjOQSi4aLxwa+nHoIDy4
-AbelGbWZBnBhvw233F7iET+n2BIWhsGYgVT+7tCRRgHxf9WptxCOhbjAYK/yKFmx
-F76a1vX006k02jDQDd9+2fJ9cyPOIluGo+T0rA0vj9cebNwYwTH22trifL/iiza1
-/UCVS2CUqpayMLEGUH83/uiV6vcCN3lfg7Muncgx4QKBgQC4r2VffdkXemzAevbL
-D8rA/Ce9eVq3ei4w+K/9L9xIEfccOrjJhXWO253yxVQFEPtAK8FRC4iKWkc/rJC3
-jEqD17jhtIVF/U0vmbFmrsTX/zcVmREgJZoFfumEJfcv084gSBdRVCBiPImrNXjd
-BnIubDX2Agn6Beqf6IIC6uxIcQKBgQDdVC4hMH6//96gFvBXU9aeiJEQG21pquZq
-7V/iNKhsywJoGIzrOTZuL/cI9nBGGYhJsgCRPn6ZVOlF8ArSZW5767haB07HdOsb
-MCfAGU/IJrzsjIXjyGMhlMvUm6iTcNP15Pk8AaWuCuvTsO/Z4tZeXwMyz0NCPxav
-Ihr05og5MwKBgEJ6L/0taYU/9gFawZbaOls46H0VP4gnnJTYD1ENdzch8Fbi9Dzl
-oykm+DW4vcONF0ND/LPVePKECH1s+jJ3dyL59XyY5BgLU0s9AVQ6uHQfU46cqENw
-BX7Q7fE5UT6P+PQ5vtrxcy6pJ8zO1JCKj3MSVGIW3cx3cLrakGHIegChAoGAASsi
-mzZAVQ8qw7mbRzrAFVIvQeCDMV2fncznBrC0eu6PcrE+fTduHCLQsRFsAlK8L3dr
-HVkxHeoe2SmtRPMYJDtYW9FSDyeE3j3g19jKXQonUTBkvJEgRNseQF8aAr1DwTaW
-QkTX9RVFrXZvrbzO2OyzfZ8ugbkHi6Eod0aITZUCgYApfZIboPQp1Qk13B7JlG4/
-AQ118lR+su8MLFuwbeDKldjgSlHq7RpBI1yQNZ0TkitmUNiLMMxHSmbVzujITQlw
-BhZiqZLqwSEIYOfE04gnwt/dipO3dkhaVycIntrwiCVMvjLHup+LuWZJI+Yr6wa6
-fKKA6Cl4jUjn1tReryVn6g==
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC/C2zzENzQ2kOt
+3NIM6xRzDDyxLqpEzK4AdbWcj40XqBXqb50uvb7RUQBx9qPG3pXLBK720ncpkvx2
+qgZBg1OM7o739z6kjQvGHJIkhoYFQFFBZm8bhimFgZ8n7cqcdjNlYWokYh81/cBP
+xr5quJJEC5tIQ/kYJbW3Lma4Ka3nfeTsSaPPl35nkCYQrZLEvzzZ5v33nV3iNomC
+2qd276R9xY+/BrkDttBkaX/pDd0beJT0zC67mtpFwspNuuKOiwI6LXhuPcnWVvWq
+qu+vk0+JHlX/qJbJ5+kc47BuRFMo8VNg9678IQP9Ry4CRW6BoAbDwVwk7rREL3Al
+rFdnGWVdAgMBAAECggEABOB8yoOur2IzAhg2AIBryDgSwI8pZ5I2Cur2VOXROz5e
+ONraj1vmqB9CPKaILcZ22nTnJoPe6N/ItBrJCBkbI+jfG3NjVP4Iw+jsziPk/fNT
+X7EGuxQksTTK5FEMsAvQahEfjYg3tcAhjafMKptFmJkXQLQDgttLlT6I/sCJoPQp
+d+m33RE9zpXeCX2cEK4+0G7ehUFY+Wv+sC5gnLuLQ10V0eEuJKhZeCyhnIx68Ma/
+S0V/0BHWB70xV48Dt+fCKOjNfbagc0jmal7/guukkpQ0hXBOlKD+bEqQSINsvKmR
+GilC7kVhAvpE4L6nJQTjzN4sMi4WrFNm1/EPAAVxQQKBgQDsc0WhImtbxaAAQ6Pm
+vAvSrEUNVZGj5GVzvVPigHBtFhaZCSnvCd9A6PdR1Wv7ZfXLrLJPvy5SVC4Gt4ci
+rVRCtMXmhDPRAXu9L4YpRI0BM7wjvj6CPQjWWPPQGFcSLbuwHVNlahD2ugAlKCnN
+5HX2Qlx8d+/v+8BaD3WrNY9krQKBgQDO1xfv41MsmvL1ssXMvEwNMTNQjnrIaRZi
+toVFVB7QvmRDOZyEh8SRFdOIVH+H2Q8X7ihlGKISfY8XBRYFg/Pee0+jR4PnGEis
+u86kxDX46k37h4XtO/1c74yh5G6EJKGNRWwdkqCcbv9xquWg+FurjN/kDzCFLQg7
+XumPae9pcQKBgDCzBTJM3oPGTk//nnBVZrH7XTWD3D0/O039Ppu2DHHLTNg0NPjQ
+tbSuxtGJ/XWH6HoMlaUrISU/xUMI5cJUpLggd2ok7G8tuQicEyvIvKn0t9k8w68b
+VwiexYikmrpZxQBe6eBHWjsW0BTXEtUfKtSPknDoWvi4h0OFT5z1qRT5AoGAItSd
+t0u0ieJd33oHTP64X9BVL8+OZYkst9q8fnw35Dbrc1aUQM0MENJ4GJECGMI4hHMa
+YkvPnwV9vwagOrWJr4FcW8aDM7snIc9OcPiJji0GjMC5kMV1WN0N9YUeByqT+dIi
+7qfuW+llIqMAoCayaSUD3segCA0ZQcYt1nSkWEECgYBwLI3uedyDeLwl2eg/0sAn
+61wo1jOqfBBymiYz2IGALbxQo8irCQ1n3SCYLrZbFWiHC6bvSRq3Ry5wD3vz95Z1
+5Ytmltg1O2hKEkOY7zGDkMQqiF+LAXH7bUfG7LG26V+Uiur/2YNttsQrb8QC/h86
+RM6CIbARwiySNATz++CEcg==
-----END PRIVATE KEY-----
diff --git a/jstests/libs/rollover_ca.pem.digest.sha1 b/jstests/libs/rollover_ca.pem.digest.sha1
index e03e7c3230f..d2611766f8f 100644
--- a/jstests/libs/rollover_ca.pem.digest.sha1
+++ b/jstests/libs/rollover_ca.pem.digest.sha1
@@ -1 +1 @@
-A834F032288D9ADFFAE22CC70FCFB34E5869BC26 \ No newline at end of file
+CB23F2F1E54E4F8B28BCB3D1D8A2A86C47D3E83B \ No newline at end of file
diff --git a/jstests/libs/rollover_ca.pem.digest.sha256 b/jstests/libs/rollover_ca.pem.digest.sha256
index eb6748ef9cc..19ef02876ef 100644
--- a/jstests/libs/rollover_ca.pem.digest.sha256
+++ b/jstests/libs/rollover_ca.pem.digest.sha256
@@ -1 +1 @@
-6EAD6601618956EA8015FB134340169E0720AAE86E1EF813CECFF550F762C8BB \ No newline at end of file
+3C11F93033A50BEA4A402FDFB85E68998FF3525EB03F795CF03D7424BFBAF367 \ No newline at end of file
diff --git a/jstests/libs/rollover_ca_merged.pem b/jstests/libs/rollover_ca_merged.pem
index a81e996be90..5ba5f155af6 100644
--- a/jstests/libs/rollover_ca_merged.pem
+++ b/jstests/libs/rollover_ca_merged.pem
@@ -5,47 +5,47 @@
# Certificate from rollover_ca.pem
-----BEGIN CERTIFICATE-----
-MIIDxzCCAq+gAwIBAgIEKW01kTANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJV
+MIIDxzCCAq+gAwIBAgIEFWtNBzANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxETAPBgNVBAcMCE5ldyBZb3JrMRYwFAYDVQQK
DA1Nb25nb0RCLCBJbmMuMQ8wDQYDVQQLDAZLZXJuZWwxIDAeBgNVBAMMF0tlcm5l
-bCBSb2xsb3ZlciBUZXN0IENBMB4XDTI0MDExNTE2MTE0NVoXDTI2MDQxODE2MTE0
-NVowfjELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMREwDwYDVQQHDAhO
+bCBSb2xsb3ZlciBUZXN0IENBMB4XDTI0MDYwNTE2MTQ0OVoXDTI2MDkwNzE2MTQ0
+OVowfjELMAkGA1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMREwDwYDVQQHDAhO
ZXcgWW9yazEWMBQGA1UECgwNTW9uZ29EQiwgSW5jLjEPMA0GA1UECwwGS2VybmVs
MSAwHgYDVQQDDBdLZXJuZWwgUm9sbG92ZXIgVGVzdCBDQTCCASIwDQYJKoZIhvcN
-AQEBBQADggEPADCCAQoCggEBAJ+sJVgoyUJF385V+niODOypGJlKO+atBCQept+Y
-Ob7RWYkT0134S/C+WEhFTiSnWeQviAbBPMQHVKCNTfq0nON8BJUU7Yr+RyLDjM73
-ZQMDAXlcHBknYZs21f9w81Rcow7b4f4m7L7LflFZFqdi8fOocNWtmWj0wlOADmYr
-Iwfx4P6yv6yqzKBxpPOIyNj6PqiI5jxFmDnagRk5PVSMfljSrwUad7/2nLNmP9VH
-pt74ygngifbGpy+Ne9S/e/cqccLj6e6JCyJFWJscJqDBUiYhNW6Zcf2IkEaZS4l5
-tpLSm4h27l+DlxbdtCtgrBB+HE2w+7N4fzvtF3QpM2s7l4MCAwEAAaNNMEswDwYD
-VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFPv7Ltp/bmJI
-ah87Q6O3oMcTm7bHMAkGA1UdIwQCMAAwDQYJKoZIhvcNAQELBQADggEBAIjIO9ju
-U7XxbCwIr9J2dOHc8P+L3kMx35A2p7mf+HBc56eRLAou5qFN2fUa0csFLqeZIHgz
-48/6RXEBSVy5nakkBwpceFNoqtB8Xry65BFDurUpXmrMFYFaiXK8BdOOhPiNtegQ
-Qj3XiopkiuuECYDCHwvHVavhYXIGpvFrPxi+pQSUKeQsHGfMrCp3LFPGrTXwAenW
-Ct6uiWPCuaidfPa2PlRlzWzrqeFvOvw5D6oPCNukIXf4w7b34wA1acBZDR7urmS8
-FkDX1CUGmB7isnufcmPzu3s50g9HJhyQx4WJ+dJP/p6sUQD8RgfMfygTip12D232
-msxGFHJ5jI2sNgg=
+AQEBBQADggEPADCCAQoCggEBAL8LbPMQ3NDaQ63c0gzrFHMMPLEuqkTMrgB1tZyP
+jReoFepvnS69vtFRAHH2o8belcsErvbSdymS/HaqBkGDU4zujvf3PqSNC8YckiSG
+hgVAUUFmbxuGKYWBnyftypx2M2VhaiRiHzX9wE/Gvmq4kkQLm0hD+RgltbcuZrgp
+red95OxJo8+XfmeQJhCtksS/PNnm/fedXeI2iYLap3bvpH3Fj78GuQO20GRpf+kN
+3Rt4lPTMLrua2kXCyk264o6LAjoteG49ydZW9aqq76+TT4keVf+olsnn6RzjsG5E
+UyjxU2D3rvwhA/1HLgJFboGgBsPBXCTutEQvcCWsV2cZZV0CAwEAAaNNMEswDwYD
+VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFI54l4o3TQZY
+fHBkR+qPEOpCzvx2MAkGA1UdIwQCMAAwDQYJKoZIhvcNAQELBQADggEBACO/I0lM
+Cjl8a31307m0c096T5I0EBUUD+XzlmwWNCK/CC2EaSBeOPZ/bzSw+vyrUVKn4ZcS
+7hnkcEwZQ3BvYdj0xmP/pYQrxsvYJeGas1dfr433U8VZJwo3apapm4k+9tJYx77F
+vkICdD+sOK/7xGDv+Z+spLmIui81w0qdVKej6160dhzCoaK1WLpdHqKtCsC27gjN
+79wb0BNHYdRqgBaBM/O/+Xi0fbW+SckV9lsI23k7FEFbPDfkgOIsl5tvw1OzAjdt
+t5F7cLz0hXAB4UhjiQmDF1cQnpu0ggaPdsliW9BztiZxkeHPlxnAnk+m4W1aH+Qk
+0NoC+8kLh4RZtnM=
-----END CERTIFICATE-----
# Certificate from ca.pem
-----BEGIN CERTIFICATE-----
-MIIDeTCCAmGgAwIBAgIEUuls7DANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDeTCCAmGgAwIBAgIEIGnWnzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTMzWhcNMjYwNDE4MTYxMTMzWjB0MQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ2WhcNMjYwOTA3MTYxNDQ2WjB0MQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwO
-S2VybmVsIFRlc3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDl
-0p4T7cqWDu/0AZ+5LTrt7U66WVm0Fm4yU8ZJgYpQ7BLuIGb664/BqpvitrKzogwh
-4O61sO1UtKOiD/KiyTjq8SzA1Go9WtdsIfDQkz6lU1cgy4HChOw/kLI6i012tg9E
-UzSoH+bvLxr18LtpOvyY6yLiT824AqN/Q/NjvRNrihh5HOcDkRR8+XzcWcg4fgKo
-8RvnEHxZ3jY7gpT5URfaisyOzNImWvB3hWjQseo7BpMIJLes7Sp2TSFtaHw0+Koe
-t2e/Ex9ls5X1fmN2Y5N9hUNN641eMMXUqIPdPq6mSeF7CCHWBETG+908TFBuQQJp
-ZJ8CmKeP7qJLxciseL7lAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
-hvcNAQELBQADggEBAHtFJmKTdyEGJlnl+zKNbOWK6+H8VglYQdWFojNXrWCnqiuK
-4NdEv8lTpEaUuV83Dz4neueFGiw9w0UIpspRPPahR5CVkVs1Oxy/LD3qAKPmxcJy
-nfj3eEYY7CSpc7TmNXHRFIWrv+40m7UJvfi+ns2MKL7IppY4A1bAwjoozvAI4rD+
-CkU61xGLYAD8YjzhNEu88LrIkV0JluBmsMen8tUce3rzVrNRouWpcc29am6JWyB6
-FLsPhUfHDZnxKl/SosXd2JvEDj27NvNtAEydpPQB4084KjDqfVzyJgMXLflkXBDS
-pdhzraLljLpRKZt6FvfDBDw4DzsW1abYUEUGJNg=
+S2VybmVsIFRlc3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDU
+tM92EQ+UJAvDZHjcHGCM5M2E/wHRXWV6z3pXNT+cZliEsUbCBqwA+rs3KYyT0NxM
+2bxDo7/yplFGEb8Kz3gZJGiXcp0WEqZKN8yfTd6p2OTzSlQ/Yw4wcsfnhDX/i2HK
+NQVh258vf1e4t8spr3udsPnfQo0ap/28F3Jq2QxGmKiTPQ2xdyWvk/K5zABHX4mu
+3c29FdViZpcYoKCdYhIsO7IWPBvvPQEqRDPRU/UDweYbJFyrlWNWMCislj0EfGIn
+LBhtXxeZHIXh9fWO8DfMzER+r1fIhxX7lvzdpyT+t3NcOGSWYRKcG8q2+iUnCK4H
+2a2Vg5YKQYGGWmkEQ++XAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAMjiHKAOjasqJPeqSaibtcpClQ2qK6xVMvAdX2YofNzO9/WD
+T1vqF06nuUlUTN+onacW9bT/cABzX2WmBlXH3N0kkr3bQ3dZy6KJpZnLhat3TLYd
+pYWbbVvHUJ31DGnZXNpWzvH/7KSK/IUixfjlYXaKocRNacXtRlidKN1IgTjaMNvL
+gTGaeiaylRYQ0wwirxVJWUzCkRahVlu8nHipl4oWoRfzCxeKGLpXWPBBVJPmupxJ
+qeU0X4fppEYMfXBZLoA5XFPeGcA+epZxNCOEP9f+0CxLmJibe/IUWRcNPS2WWznT
+MV/vxlcqKt0YqxFFk8LzbYMfKa4RXKvk/xpy87g=
-----END CERTIFICATE-----
diff --git a/jstests/libs/rollover_ca_merged.pem.digest.sha1 b/jstests/libs/rollover_ca_merged.pem.digest.sha1
index e03e7c3230f..d2611766f8f 100644
--- a/jstests/libs/rollover_ca_merged.pem.digest.sha1
+++ b/jstests/libs/rollover_ca_merged.pem.digest.sha1
@@ -1 +1 @@
-A834F032288D9ADFFAE22CC70FCFB34E5869BC26 \ No newline at end of file
+CB23F2F1E54E4F8B28BCB3D1D8A2A86C47D3E83B \ No newline at end of file
diff --git a/jstests/libs/rollover_ca_merged.pem.digest.sha256 b/jstests/libs/rollover_ca_merged.pem.digest.sha256
index eb6748ef9cc..19ef02876ef 100644
--- a/jstests/libs/rollover_ca_merged.pem.digest.sha256
+++ b/jstests/libs/rollover_ca_merged.pem.digest.sha256
@@ -1 +1 @@
-6EAD6601618956EA8015FB134340169E0720AAE86E1EF813CECFF550F762C8BB \ No newline at end of file
+3C11F93033A50BEA4A402FDFB85E68998FF3525EB03F795CF03D7424BFBAF367 \ No newline at end of file
diff --git a/jstests/libs/rollover_server.pem b/jstests/libs/rollover_server.pem
index 63d6e33a451..b294697245f 100644
--- a/jstests/libs/rollover_server.pem
+++ b/jstests/libs/rollover_server.pem
@@ -3,52 +3,52 @@
#
# Server rollover certificate.
-----BEGIN CERTIFICATE-----
-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
+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
-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
+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
-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
+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
-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
+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
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDw2RvdfLPSGti+
-CLObj8PGAAYhRBca2dhYnzT7gENIbFM1zd2TroejxGDqVq0cqCR6ieccjL70oXyC
-ko55ZJFSfTxMkAtPhuAegv3XP1HlSbwMLMxgDFRX+dCcn7+47JcS/BN8z5u+zRqO
-AgVnSEiSkQS3UWX3KvSFHJNyzTSgglDQn4jOwZsmhuezqXIVx0AZy3ls3MIJBwFk
-nWm8+7jzcyZr9lxgpig+5qjE2cv91+yKVQRTx334b9av4qgDMhDBjYVUZsv+oK67
-Pd96s+uI0YXhul1ri4I4s/Q9GleY7d1GsmUr6EULaGlw4GYP3jWuOgo4PoiNf66a
-YwrBvQ11AgMBAAECggEADuE27muLIi6m7TH/7gXchZclnyNZXb8PivAbwkhVv9Ee
-IJuX9iJeU8Do75QMd2da85ghUhCkUTGd4zpB46A8izEHYJU19wNBRZlNrKFHQmgY
-XlSGiY48HWr8F1prlPWcTXULO4GJtijD8c86/WXIQrKDbP5Hff+md4fWWI1y1CdX
-ko2+qBu6svKe9Wc3JOU9BA7Fwd9E/cBQk/4O9uIdfAfJemrrNkjnJTZLw3JeEV0m
-ZiwmhD3cr38rQtbWn91Wdd6pWPaBRfhTao89BLpo9yaR/t7r7aMk+kgW7vfmW/wV
-C8+Z4Ojb5SGgN6upDKJLL6IirguMMCMI/R5PUBT/sQKBgQDycRhFHz62oylbsdW9
-G98bFK5rIoDbUPX9hTX8YCsqxvwabiQQ5YHswwKkgBjp5qj0vFSAKwqi79wHnqV8
-2YKNevaQUC7Z9xi3043silBZO/oOmhXYXZ7+Qwj+un7Y4XOAZcNRs7oTe0tmVqNz
-OOb3pvOVZzWD78mUP+EYURDfhQKBgQD+UTKvbZVgqIXFNGx7HzfSPMWPx8MqHLhQ
-PzyVT0zYtXiJksOSE6ByIC29m5pcf7Gxnk4H53wcVwOeopX1BckkKLO42oTuIHJd
-KRifC2F6YCJVQHNY5w5O5V3qA9p+3cP3phY3nmLSOQsfi91Fxk9oWlMI0ayXkd5Z
-cbVxv7PBMQKBgQDCwQMEE9NnF67TkAno/gi9UmHCglcM1v6kh2wUrpQ+qtY9zRh/
-0j4KmaT3zEc3LimvX9JpmynSNeiE3naF0pzDVnHW//KC+bILiZBK4dkltb5sGG9P
-/fUIv4TsS5g2VPVZwWWjrkLd/39UWGi42I8BhkXKULx2nhtKUf5acFSjmQKBgEwP
-2vnu63tiS8gEeuGEH7zoYiozk+J3foS5tRPvCMvT0r5Kv+Vjq1wW1bdc35kEtA+s
-iigBCvSq7bE3bWRAG72N0trZuGJEIBBO50dCLyBbukkHIriXOodMQH9qMaI6D491
-BDYUT/gSCYqg2UgyHLPYN/duRpF6liboRF1F+awxAoGAJOOocK5YMFUl537qysMK
-3pCPD/+8GNim0JO3mrkUEx1uBv22XMLXTM4FEgmcJei3lz+Xj94eAiBVos3ldriv
-MEOFM3r1jqYwPVWUU9SccjnFLZVc1DsDywnKbSTZu3jcpiXydNERVKvik95BMBcz
-kiDLvflv9lu/6N0vJzdLtYY=
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCnCUgOimy13ERv
+KybpdK3haOqemaZuc7o4s1fqD5PGvIqIeuW8eKdlN8Iqom8Zg7iNSXVFNEZhzw46
+Gd5HTaCIt2u6k9AYVMrHDWxYl7DoPCRkFpetUufSXjZlkgp4Z88ACXx76I3N2Igj
+Nf+mDWlPhgzSqP1b5Z51mKjfGcNKoC1tUmguX3emeGbG84Ob/74QNvQ1z2qy8BKZ
+fxPMy0/Po7UzG3gRPxuhBbH6wkEjTe2RwkPD30m2cV2BHR+Y2NGWe/nog1QkYTEI
++zGKmvaHFtC2mr7nn3ln1jjcpOMTXa0CXvKTTOgWh0wv0dG+SdIGedcKeS5O2nDs
+KCR6DhsBAgMBAAECggEAIPcd93CuP73265GynkRexKu2EhL027uPNv1+Dj2AxqoT
+FRhcGrQdJUa51Tw1fO2YEJo8wKmuckMw5ZqRWbUiR5kbc7kUSpkBZANsLJfTXCHy
+dKZYzOYdxlC9n5IQ6u5h1foJTVL6GXPwejJ//7+J1x33jeO4DNjmSwMT4OPuvN1K
+ER6IexdtCAjLOQ0L3Ak9Cws82sx2jxCes7na+46S+pCom5BKU+HMSvZUkGV5pXYH
+JrKLyPe9D+cvomxCNnMcRJ4SCt8w6mOrK7FWMK5zHErb2vUWIovA/iJIPAKpH98m
+Hhy06pyI9H/vx+lrXOb+dZQwYE0iVYm+/TOQH7wbmQKBgQDcOlfALbVQB5V7h+RM
+FjqLJpbZdkSr05bl2o2wK8sH/saaL82bNJp3rwpredzOlNQhUSLD0ZbPA2QFimNw
+mPBv6NGzv3nOe7igHFBvuI8VGWKo5/Vj6G4cA2bPLg9g2xMjS7nzyqbMyiLoMMoP
+a8hkwdYrg86GKW/iF1gzmnT8hwKBgQDCKxb3xmWCzAR2bqzyiwNyFeqHA5plBcM6
+rFOgZ4gWjIGt3vyEOfGhg/X69bZrQRenL5tz18UsXdvpDX05TDPbaNGwMQJSXTyB
+k/IXuIpmdgRuoSS4YvNiBqvaTBPNxzq0NBMuYRBxLbw5uMgeq0n65N50nHLJ+oD+
+Fm8q4VXWNwKBgHx+nsyNCkpLfz1t/KjmiAHRtsUIDpnz6wHVIvPMTeIfLLZM/7YV
+bpzp3sITCbfeemy7KSP5f39XM1vOd5hXXNRmkOVEAN+xIRWh6/a8JmaPCy7gsd/g
+rR447g2AxEDEl3UEggJHNTPfsQwBSLie/ZG34hKHWGCPXCg7eijxz+BRAoGAXd16
+0vlEJYD/P0mtrerqFYLmx7JEN0Yb5QddvhOOxGfUYPuFU163ov8qMNIMB7mF97qa
+CdxrY1FUeEufF83w28bGZ8ipeKu+Dl45EKKTtYikB9864zBivCbBeVyBzl7b0DXE
+eA1QZ4ZWkgj0JW9k6jcuG21uSJojNbIet7oLRu0CgYBudnJ5ML2N5N9AWr4H90SC
+MbbpcuJgMAdtcvKUQvj4w2AU4FO12AtkLDRRriNEKvUAz2ATQQ9+Zn+oILIz0j/W
+1hJEtnYQXqDTouLG7K8AzqfDa9EeixNj4K+vsN73h7BLD4hYtUhWh09bLrUGMz5g
+sg5jn55mN0gAW2NxYm0osg==
-----END PRIVATE KEY-----
diff --git a/jstests/libs/rollover_server.pem.digest.sha1 b/jstests/libs/rollover_server.pem.digest.sha1
index 780132ca997..a7fa47fa3ce 100644
--- a/jstests/libs/rollover_server.pem.digest.sha1
+++ b/jstests/libs/rollover_server.pem.digest.sha1
@@ -1 +1 @@
-425FD9B2BE1D1C0E568801C85BE0ED254BE4F342 \ No newline at end of file
+1AB3BF9792D7D9E4EAB3DA3A121362E064DE220E \ No newline at end of file
diff --git a/jstests/libs/rollover_server.pem.digest.sha256 b/jstests/libs/rollover_server.pem.digest.sha256
index 8c811ff69cb..d77a48bd052 100644
--- a/jstests/libs/rollover_server.pem.digest.sha256
+++ b/jstests/libs/rollover_server.pem.digest.sha256
@@ -1 +1 @@
-FE85D28865D948DA9DA70F8A900570C3C0815F97B788B3FB8FBE9D7B88C26FE9 \ No newline at end of file
+78CECA55F5F808F94824287A25485E155AB136F5CDE812864147E24D8BC909C3 \ No newline at end of file
diff --git a/jstests/libs/rs0.pem b/jstests/libs/rs0.pem
index 784ff592cf1..be1e44dc18b 100644
--- a/jstests/libs/rs0.pem
+++ b/jstests/libs/rs0.pem
@@ -3,55 +3,55 @@
#
# General purpose server certificate file.
-----BEGIN CERTIFICATE-----
-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
+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
-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
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ4WhcNMjYwOTA3MTYxNDQ4WjBYMQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDDAKBgNVBAsMA3JzMDCCASIwDQYJKoZIhvcN
-AQEBBQADggEPADCCAQoCggEBANsoEQiGcegrCCGdTtNQAfNBqLO2ejUo3zHsy92j
-ue8anMwjcxKgEQJpuoXBzQF9AN5sphbTp2r97btdLaZguWlvJ34jHcQ2rMivITwi
-XdfH+rYXEZhnJmpqDIFpD38+acknZJ6VXFiGoYUd++tZLQuPbiUSCy7bkpFdX/Y4
-KJMCQCnT2BCQa4qb83XR3OJZDOJ4b0NRMZnBjTIGYEQlQDYOXamsXrpmVenp9gCe
-JtPIL2aDpIR6PNacTPjF56LlYFmZ1VpEOTwdjvSPRdMeei8bllPt8UpA1OFN2mQx
-pMg1k6fq2tp3tFS0y4if/mg+132vp2fclKatl8/iIDjo+sMCAwEAAaOB+TCB9jAJ
+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
-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
+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
-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
+BAMMDktlcm5lbCBUZXN0IENBggQgadafMBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcE
+fwAAATANBgkqhkiG9w0BAQsFAAOCAQEAclzk3lpQ93jTJyFPHAFw6RIbq2QkxwdB
+xT4CKf+RkvY8lNSbpaot0gAqTb+5+k5UKlJ3cXQu/knc1Ui4kb53xI19XAGdWJRm
+ftkRAqIfu+IxzfdKNWDM16yiXUViygzhLfr3kNgENSbc/1uKg/Nn/NPtKb2txcqh
+9qo+/L+TRvbhws6xHK9EWOu12+7ifTof4socLwznxJ/MtmzJh7DLvCDVuovh47Cy
+O8qc3avolJp75d9+1uqU0cKESNB2IJJBpqIELndZywIa3uMvvrjf6gHroJxXwGt9
+3au8OAMQO4j4ZXuExRp49e0upyawg7YI9TbF9rof7zw+XEDgo8bJqA==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAQDbKBEIhnHoKwgh
-nU7TUAHzQaiztno1KN8x7Mvdo7nvGpzMI3MSoBECabqFwc0BfQDebKYW06dq/e27
-XS2mYLlpbyd+Ix3ENqzIryE8Il3Xx/q2FxGYZyZqagyBaQ9/PmnJJ2SelVxYhqGF
-HfvrWS0Lj24lEgsu25KRXV/2OCiTAkAp09gQkGuKm/N10dziWQzieG9DUTGZwY0y
-BmBEJUA2Dl2prF66ZlXp6fYAnibTyC9mg6SEejzWnEz4xeei5WBZmdVaRDk8HY70
-j0XTHnovG5ZT7fFKQNThTdpkMaTINZOn6trad7RUtMuIn/5oPtd9r6dn3JSmrZfP
-4iA46PrDAgMBAAECgf8lyJ+yzO95aQkgwn49TWsIqFTtj6s8UH4qhhGIjY7SWOcj
-7bLdjtJ3L07tes2jOd5VNNqE/bLT4lCxlCTKrW4EKDFssLh8svB0NKYdfc9S+76m
-d5mFW4khFW1YVrkDzlYo2AqMkpDB+EWa0Jw1dzYSvITYJSFUFbWX/S/IZlqYceHf
-zjU+uHCwNooMgSaGguKZV+/vOYuQ8EzJ68P11LuCbzkDnWENGu2nHLIbKb76k02V
-YCPUFBCSJbpw9LZ1rOwp28r+HCba8hL1RSne4H2letDNHIzOBAA5KOoERp7U9035
-0LbkvK9y58Z1CJZXjpLSWXRc96mckhzWW9zj610CgYEA9tCWLin/RpIaofL0vIw2
-mYOevMv7RPpgTgZVtop0FR0TZnsGH1cEZRGl1LDlTisuDqnRQ6EEC/KU0IHyw73X
-gVQ1ye65fxKkNr4QFpx0ODOaxgMDUbQdOFtpssvshqYAFd7Pzr3CRbLtgzeZ7AvH
-DiuIbYypDHdYclzxIOFvaTcCgYEA40/6e/88whrx5LA4goCyp/zEIbG3U92xpO/h
-H3kREnL4TObTbEzM1gncV2lS4dqtDq2wBx7VdaCfuFM4A7E8sUonZSHByFZBmRnf
-PKJC6+YOFZtsaLTeWG9XGSAACbw0LCD+ycfVI7ud6J6XFTEvPxVvLldNv1sQFrDM
-xXn1ENUCgYAj9j57mXjtgmpJAIpyUoe+FHRzk9EXutd/ZuLkRwYk8WibPP+mX1pv
-k4OzGtc+bYI3drzb+sEJMJ5IRzblGGsnF+sCcjsq7b9pjoXvlXpFmhdKFLROGk1L
-od4jxBzBfbxzc1SaDgIZf7mlrdtKjmjBgsxNEfqrq1QCzdIAdXhzPwKBgHEkId0O
-EcPbfYMCY14xiLssiMLsnf9UXVNnQnpT3Dd+mjBMw/cn0tzGU7H+bo6UNYcU1IT2
-x/CgXl90rHDKCxeDfVBNGRMKO+RkiES5zu1zuJbwoWkMfY8u+/85ekteLem5EpiE
-qoX6oIJkTXby4D1aAdjjA4O3Y66nmYTBS0VxAoGBAJQNomPHyDocbykM7kcPnyag
-btMw9JPt+Z/9KDjW2LbSMY0/QxuLd1kIfireip5aZ3WI7QU81H7dPcLtcpll486T
-MJ7Ey1QdMVGCt9mDuKpmo1794nJzh4pULqdfM8jcaCBMvmx8oZHAXlf0rMN5bz9G
-Xtc7/KNGeZRSWYfcmjJu
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDQzs1NuzRiZ9ye
+drXwBBdb1r7R24GbPsim9An4n8wXF2EHBa5n0OSzfVwN+nChBBu9p9jnkDt+W36I
++C5dO9wh6YIKakqbj+NYYK8fVS85vbFb9EdoE//lgC5yURBjWXl4l1kLq6jy6ijx
+pwyBwplBXByat1KM1G9y6t5vHGRLqMlpk75tpxymr4f1AK8rW0/8u2eiJJXCLcWZ
+fwQougbhzo+MjG8Mqx7LZ6g3QqmbiHU7B9xrSsmRrdr4e683G0cko0nK8pYsA6l5
+c8q9QCa9sxueaY7Kjm5uNWN61dQ/fN1fn4wgLLQXLUUHU/u2eImnieRU+U5fecRj
+vBV1cuFPAgMBAAECggEBAMnxF1Ez2gfJ1u5SdMa5zjV9zHJ9Ti1sXPZKUlJniSRT
+8fyum+u/dU+5z4udR8wRgxq69+WL8l3T8t5Y185HlDAf+ypDfgBQ+liAuR0eb1vy
+f1MlPuIDZZr5ivH4QFc1M2tTREUrMWws1ohPPKNKJpm1kdx3q5iT421KhPEEjmM0
+DK26jBIpE4FzRM6m/XQtw67H2qG6vJzSAPg/WMolHMACWHOcjMVH5UUUHmPAPA32
+gFH4Be5f4ZLb3Q/lVTT3PlwwQTRq7KAdq8W3XwNawTNY73qerlhtvS0LI9YeZafv
+kAczEu866Tnl9pSRNJA7m3qLzu59ulgFmc4BbzuSi5ECgYEA7REC/C2igu7bP6XS
+0CqGVHB6eRjDA2Yw11ugot6CwL3A7tPlNXB3bxXVAdp8JHFUn2Q4RfyiwKDdHGk1
+2YuQYi0OUyQSA+HkBzSWWlqQc3BrceMiaYl5zI3V7WFiDpY34e1Z+d3W5Qielf0J
+eOlVJlSh5TFa1y7SvWa9i2i2kRsCgYEA4XwF396HKqS2qt6MZDJcggEH99P52Uk2
+VXH6hQVeE7zWDq/1Dhg6l0DS7b17mPSFm5hFBJk0OIZ0YXxig+MeDdooyQpuFfTw
+mJojzbUuCcKlCpjAezdB5R1WGGnqkXGTJSZoIvWL211OFP+lJk95426qRlRRkVTb
+uIc4Vyd9p90CgYBse4poJ+HkFLWT7KgJxkvuPAJvg9tJpOvYwP9DSJuA49Rz9dc/
+mxWsacstq/N/IbVdsxjlPfSkPXixVZvkzy7lHkUd2rW7vRUCDxh2hFbx3JHubcgD
+j3uDFay9kgCzOB6ebmTsKI38BPO9IyvAftYOUlA7d1hge/bH4Un/j41r3QKBgAzR
+zkuyDSFBiBki2fyAWH4TrO5MIPJXlT06Y7HYYkbg/5KKMnaAriQXTWay1SoXDNmR
+yKrAQxXLnyZDuh4hdX34H0V+0E9zQ5KJgOubF2j6pgN6N8dJlvd9uX1d2DY4rNL5
+4gXKzA7GuT+8YRlSf22MxyWEeba3il5tYaii2CQJAoGBAJuFoOR+pqTqbHXl9XSi
++g1+kbneOl0SnXFH0jRS0d8znn4pkiLP6nsgSYseKTG4rz9l2eakfLPZy2TLe7hI
+3GqlG2xnTWLfp944b7+G516CehBkShzBai5WfsPEGRwsUdZ4D/KCKVryFI0JXFxx
+TIKC85ZoLBRJmIbZdUlubnK9
-----END PRIVATE KEY-----
diff --git a/jstests/libs/rs0.pem.digest.sha1 b/jstests/libs/rs0.pem.digest.sha1
index e6e3b5bae91..ae1a713be62 100644
--- a/jstests/libs/rs0.pem.digest.sha1
+++ b/jstests/libs/rs0.pem.digest.sha1
@@ -1 +1 @@
-8E3B5B734409FC5EA30E391A0BD5F7A11F085B50 \ No newline at end of file
+9106629C6FB7BA92A5700AEEED526E09D53FBCB1 \ No newline at end of file
diff --git a/jstests/libs/rs0.pem.digest.sha256 b/jstests/libs/rs0.pem.digest.sha256
index 6b328abe9bb..cfbd887b1ea 100644
--- a/jstests/libs/rs0.pem.digest.sha256
+++ b/jstests/libs/rs0.pem.digest.sha256
@@ -1 +1 @@
-44E20972201F5FAD0A21EB2AA8C2DE3A2437825CFD362EFB168F647162F2EF27 \ No newline at end of file
+9C39D98DAC3F0D93FC2C9C040D31D9273E32040CF13664456E96B4FCA31CCC2B \ No newline at end of file
diff --git a/jstests/libs/rs1.pem b/jstests/libs/rs1.pem
index 814326f345b..62b4cbb4c07 100644
--- a/jstests/libs/rs1.pem
+++ b/jstests/libs/rs1.pem
@@ -3,55 +3,55 @@
#
# General purpose server certificate file.
-----BEGIN CERTIFICATE-----
-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
+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
-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
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ4WhcNMjYwOTA3MTYxNDQ4WjBYMQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDDAKBgNVBAsMA3JzMTCCASIwDQYJKoZIhvcN
-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
+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
-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
+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
-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
+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
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCkmEKdNpF+FtH1
-tRK447IWjYCDXJ1PkTMBVpDkxP9jrbOH6vCuGUSb9MArR+dxSu1aqsUVTqNo2LTf
-SapEb2iFgearWtVEZ0rI/sTYd7SF+RTdSX8BO6sIguc3elNtJ2mPbaQw0CmPliHx
-4jyd18bZZrV6L2gPqz/AMON+KrH7IwxaOwn4JUxQCQscbhln98EKBsCZekacK2+i
-rR3ustfuJ1IRFIoTTQxeHmiyEjT9c3RZFZG7o3dPNdJnnf8l0s1D5mIxPIj7l252
-g8XMM8++NB5j+yBLZc9lytb7sYOssvZi+rJO+eEWQohOzMq3p6aM0IlhbgryW9+i
-PC8CWzw9AgMBAAECggEAFysbjVemCTKbIVP4q6/ZXJVUdqktt4p/vHt778fPDy/f
-Ko2mjUsfPjioaC8549ehK3cIQOSN2e9PHnMXFYT9GHXdi1dA190WSM6b1MCc15Ll
-HfT/fKPygkMy2rtMTPwUPs03JGvYvc5rPsoSsEE0S1vKxcUwh6waUCpRi2vlG61s
-TPWLMf7o7SbnkR6mpf+scfRzU/VvdOE7BRzVMT0k3Y7Frx4/dTSeeysU+E8df8oZ
-QV1WHeCQdcES9ny4UEWcR3luxRvK2/AprC6GWclXiAjYKQ7EwMt7Q0g3PYTBiCLB
-ATNkbXUZQ6o8CMtlw25yuT+ApGePV4L4GzF3wNf4AQKBgQC8zMXUtmxsQM7fPI/p
-66IKw5AWpYZI4/WTmN5uwCv/K/0lIUw3TkAKdyRyPE3QkdzoeGuZGimJozI3CrPN
-uKfeU3lhiDZZLRU0mpYGAJF/RbAzUtKr8PfZ6iWcKXsb9hEnDqbJ1m2dRuVykkFo
-Iy30JjOZAJhIInM+55m8euZSAQKBgQDfLfG/sJxnuxeEwlzmyeOWwsL/hlEVRWod
-6K1Y5ySF7lN9VVoU5qCCz19qVgSc1wzDVp2b2rUAD9GGVxF3P1Ng6KnhezEzgUcn
-1t9jJ7EKh1Lgm5STjp8+Fde4tKFh8bura9ltSjCOfl+QJNjnrU5t5JEs/QKc9U7Y
-HWk6GnWyPQKBgEU9iDQprvvIjNX8HP96BlSSQi68B9KFn9PAlZriaYBMvqs2WgBS
-d1QfO8OVcChUxkKPn05n9OHgcxMSnryMwyvbS0HEtcHgsc04AFs1LCcUBLnd3xtl
-5VAK+j4aTGcFyGadjfep50tt68on70rk0/6dYAD14eNalw9z2sLwA7YBAoGAGi8g
-wtWss/reWoQXNDiRjBmTmTkgADfhqFqpI9oSjegVQYonBHa+dDpyPl6TMfeFFtHt
-seBqBfTVJ0bF1NDILoF9lOfIMPvE5mauVMrOWabg0VtPhjRgeH9FjPUcTgp3czg3
-DTx8D+vBuH6qOBw8LGZ5peaVTOb29iIVO2zpTB0CgYBsoFrKrQKgoeh3CzA1rnp7
-tewNKDuhkGPBa8RrreSuA3aEdQ8IrP5UqF66JF1+2EvwPdFZXHmtE/6/BTsSEQ4c
-MPWHxGmk8tBldM6/Etnln5nzyZKooBAnTZcYlGwPUnsZS1i/7F+4Yyqt1SRPabvf
-WkxExXsQ9Bsw1ZkGagMZlg==
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCkCJvltu9i+k+h
+qW/jDorx23Rz98HgynQeLIbJdpiUngGO3ggcnIv1HkC3iC4tW66C7kLob4Fzwgqm
+CoDcITOLZFvgcc9sJpo6uVX8nYF5lzjfSuFq0VjVuCa5GQvxu9zik16pL13g7gHq
+L1onsfbyEkPke4wwTBtHr8LIJ/cFME4jEXargOgtiZTtEa/A7SAq0uG0Xnb6t2gA
+Kg0qwDDMLrNFJybngheUwUWPpFSIM8nwo3CGELN52ag8WKRhY3YWc67FBaWDFIOe
+JW/id6MXFwIOexc+abzgLm810Y8woh+vEAvmRdAvtPOEOn5paZf7vVADCXfl69V/
+JwmuYSytAgMBAAECggEAEuCCwF7bEbLosxwCqkikKM0ui6H5h9sEnexV3p1tVb0R
+RNW8bT5+xMikffqIBeRFIwA0ZvdeGGo+O3l99tdDTUlRYXT3f+S5XwSxJo8htVJ3
+0wqVAmvxIzc8DZUaUMlj1BdNj37J+Paq9b5ZS7QpTRZZBdRJ/8ziXs+VRN+Eh+4l
+7CzrcRq8QybgleEroRavVBeE1Se9jGAiv7JNvLN7ZY0c5HNtXOP9QAf9j8S01ztb
+K0rj3JyVUH7RCwyKA9QTdziZEXEv5CeDea4JVU4nrRTNPvNGSu1pLTtLopIunwSq
+3XBtFT4x6a6h0HUK6fHsYNxgAIAEzxhTZx9U0/k6qQKBgQDaoh59Ql5eFaG0iLpL
+8dbEy8mdoUkvVI6Gk9jCtBL8vzu7azNIzAkpGPvovmlgCnteJEXnzXdiBhcMqZmw
+HUcQrN2Lf5WGwkhYlOQfruMUDfUB5fslfR4zCg3JxE+VUEf3Y7WJCdJ6zPQg8dam
+mU9WucvfvWOcNUXefLFPdYQ+FwKBgQDAEZYvuBS2SpQLrYgDZrwwgiwyMpAhbM5q
+5iNZ1vdVAiNJziEne1mhkT+1NrYl+4HlBYYXTLZO513P2bOUvL39byaoh/VEp/il
+doBHDySDP9VHG6bNFuj2tF81TKbMSKZl3SFD36prC7RH172tnzIj1gu/ziq8SeXC
+5Dm3qoDJ2wKBgCxE41ONmroGO0Xo4X/7KfeTI/HM9Jqmzm0lhqB2Ado3hoq+fBXj
+an9t1aQc2g1eUfiP86+qBOBOR2CC/uGQLBGOTxWt8cLll+yHyWE48jXfVZrazG2c
+1f6TrJMMMukS5l+LSvjCimHfGheJoGL/a/cti8B0ArVgfBM+wFBMhUhlAoGAOfsV
+I4KmfgE1f/D6xkwVM2+Yd+7bo7t89LhUo6JJN9hVXspjJ9AM1sFKQiIqCn1KUSDB
+wfbeciNWJpDJrXTsxbzwJqAkYn1yikCjqM/hbd2vPLAUQoVP/mmk9CoXkEO+N7Hx
+gNPcVkRKQAXYtLkCId9T3KsYK48DVTogUlmeV1ECgYEApFuUAlLkb25cznQZyCEA
+LMr5cic/YTb+R5BHeu68/9dbv+hJe4KlUt8sIAVGcu1QQRQ8+IJXN5m9s7Ri1epy
+W70xO9Bas4WcjuIJqcerm2hdp8glBwDBX2iDeclPStbR3yJWSJk1VC4KJlrYFDER
+cUkehtKvAH2piJmhR4YEfWs=
-----END PRIVATE KEY-----
diff --git a/jstests/libs/rs1.pem.digest.sha1 b/jstests/libs/rs1.pem.digest.sha1
index 4cd0f465e97..ea515f832ac 100644
--- a/jstests/libs/rs1.pem.digest.sha1
+++ b/jstests/libs/rs1.pem.digest.sha1
@@ -1 +1 @@
-11E9E9DFA54E58A8F797CAD0CD230F15861B8B03 \ No newline at end of file
+1E70B7443B2780B55093828952F3F0C2CE94F85D \ No newline at end of file
diff --git a/jstests/libs/rs1.pem.digest.sha256 b/jstests/libs/rs1.pem.digest.sha256
index ea7ca055a4c..d657e0a7d68 100644
--- a/jstests/libs/rs1.pem.digest.sha256
+++ b/jstests/libs/rs1.pem.digest.sha256
@@ -1 +1 @@
-139D95A8A6056B6DBFDD4843322386AC32AACA0194FBE12C967820B7CFE5E88D \ No newline at end of file
+E5AFA6A47B5B7F139C1DBE2A29567C02E7FAEA5FE2F120D700EB8DC426CBF281 \ No newline at end of file
diff --git a/jstests/libs/rs2.pem b/jstests/libs/rs2.pem
index 817935ba61c..f61005e2cdd 100644
--- a/jstests/libs/rs2.pem
+++ b/jstests/libs/rs2.pem
@@ -3,55 +3,55 @@
#
# General purpose server certificate file.
-----BEGIN CERTIFICATE-----
-MIIERDCCAyygAwIBAgIEJhYbmzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+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
-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
+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
-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
+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
-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
+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
-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
+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
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC1bLXLWCYS/Lnx
-h4hAyb46ZX76IRfvSFCY2c3UuooYbsv5EF8eJSsMI2whq7yhZieDQ8fAuzziD+S4
-dxiof5bhVQisSaFrtOs6XP9B0uDmFhCDTy/aMMrHV0E25PR4LvgA3lO8TCOLdCP2
-kJQgacwBNyjwYMv4cQy4FXOOUMyb3ytjBe9Cd8FSVMCzf3XVs0SYhvV9mHRTR0IS
-9q3KfkGsHtUaIg59QeLQFRrlirBhIuYU2HXjFdJgE38Rf1HFuKX8x6AA6xTC13Hq
-gzHhf25c5DZxdbFHybX2IKI3oXQrLPuCshd2W1N2ElOKbNvELMyxqQ/I6PgCEkOB
-8k/TcPFjAgMBAAECggEARnCydwS/J7EbawVB6FHMO7Uro2dU+TFdJbOvQLC6rHjc
-VlQ+ciBhQeHA+qPI5euZXNRkytaH8YfVOK/5EXcUeGHBL8+Yzo5cpHj2HLMJYhxg
-BfOpczBtkw80QWGM79rgrMmlvl7bkCokSnfhI2KgdDpb+VTD7S7Lju+5QaDqiHvq
-HZZLh1EAPF1PKDyVBV0pjooEaeZyzJEL/Hbgd9Dgfs0HsSJhLqvxcFWSH/rd/05q
-Rjypy8MYn9G6BRCVP9NGTuA4x5dx0BO1v/jHL/3bwKtOPi9LOPJAuDOT49A7mubn
-pG5dMWL9hCbhz+ja1sfo712AI9L6W83pYRkbvgm3SQKBgQDtyyp6RvVKi898eIKx
-uZmosSVToFxj3B6HdQYPVtYt7W+7XhIQm+kvpfc+2sWBbsB3MsT0up5zVGYrUmA+
-ygDJNZPncyaUScO4Didz4t81Wk3BKcWMGeIC7/hf5JCr2PnM3njuf0pd5gSoPbvf
-UPdwW0aXWZuJ+0C6TwJvgHHz+wKBgQDDULGT+8LGzgfLR658bX1JTu+Dl6LOsYC0
-UuiQ5zC717Mf+HnysTWv/NFy5FfqBizA3IDQW1bi6EKCUyN/aeC3t8x8f4oa+aXU
-WpW7BNunZ/V8zjg476eV8apmCT0gPYezq8YW3QRniLw5E8qRau+fZkBE3DqJ+PO9
-kzFsZzQTuQKBgQDJ1Snmw5ergGPKGFeGFizQPBuckX4Z3FmlS7SrDF+ad+/gLwZS
-RqN0KABlvzbol2KRSexWdJfM+BQILVE3uilUnz88skZKkxmmfY0LFcOy+0UH8TaV
-pdpp99jvO4d39SCBvUsT08MBVB0b19pAv+5l1XNjP1F/mlzkRe+hSHpwRQKBgB0a
-2zt4GtBRR2wNZHz6O98+ugZcBFDUtp8oc6uUJ/j17aVn+5QkwCFXhUafrFIdVXHv
-6eoiklIB1ldhWDrWZjw6UWiEAOqAJSv9y64wzSKnJTfR6yLg45I+juvhmJBDWwN1
-J3GkwdFD2PiQcHE3BDo2nIEmaDrDNF8dnhHPVz1RAoGAeB/p7rze3e8Lu3CZ4rPS
-84k+hP0jduXrGEW95tXXYzSpSshV6DKGTCGfLnENDuVhKxYgM+NNw23//f40580U
-FtiSEWFcU7eSaRW17x0RAQ9G8GcSSJsB9yZWf0JRNXQzrSJoRxp15ZNclTVM/J4m
-AqxnRmGXRIGnO9Y1kNyjSLM=
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC1xuaK80nlCZYm
+sZJqmFP5rRowj66Z94S6ggf+F2T0/Tx1NuoKLBiD93LyZn2S4x7hsqQH7yiHZhnU
+WojqZ0jsgWOUFCTYhjXswtaeJkaxJSwauSilmsg3p4yI8ZWU1hA4waVjQtSWx05K
+aH/ycAwiTbR1lqOutldko6DjBvJvJBJ4lbg4ScBtAWip63YOF+szbQUApZnyYtLv
+EDTrAtO0DXz0eAkY6KdWMnrcyixHPfjTCRW5wToH5M6QZC3zQapcPF3Nfhn5NjYT
+21zsqoUnsbkKRs1RRD5K7e4x+ZBuNBGVsm0oHg4ER5FfO5ms0cdUeHdyP43bwvhE
+b2sG9qeTAgMBAAECggEBAIM2lzYX1fBhkiROK72MRZnFzVDedo+nbwTeVfyhUHvT
+zG9j+17qY6vm0++L8fs0vRb4R5V+mkfaeKyjyY9CjQ5De+jo/YvanVRRdHBmesLm
+bUbA/0lDSGF8LWKw2GO+fakqh0L2e9R2+9mUQz9yiB++7ZOv8GluL/lyb/FRE3EL
+ZKgdxzMUCn8SYZ+uiiq89fq5lKvgXyRKBbmABDlMqenIbt9C+VGS+2Njht6zXLJ6
+vSrjYxlbs8r9RU+KgRBz0dGbAAVjaNiYbnI5PGx7vrlZkxeTTVu/uo1x0E+O0dyS
+F03Y5Ha9TcLQMSwm87hUo4/i0irKkiSq8ZaczrhaFpECgYEA7808lYna7RKwFWPE
+iOGrkSRX7+wS14Y+I6XRONwfHgoCLH8SktlczkNTdlL0SG56bawmomlZjwROlMur
+4GChBui+bUgwlDv1BjZoBUKA8xj1mE/ikLuWm4YbDJNM+cu6EkdlTuVRpU5iOjVY
+Hu1K/TgypQsaWzw73Pv8zXcM/HkCgYEAwg5F018s46VnAVgbPQ+5v3+a8YpzbrK5
+XrTly103MOsuGd0u/3Epj017sF9rUelLIpJvMnx0kA5HjsBEbfXphiPvAjVsAmMI
+gzQS01WXVeMS1rWVg4dWYTlqyElpFWVjBrxzUknpD1x7h77w8wWSDoZTEaCKagC0
+0NhoHCr36WsCgYEA1vbXcYHjpBPVj0chPkd2YiT/Q48PkO7BM3mIpX0F1ArKyhKb
+ltKNVEWcQvy4CVooG7pv47Wm2ALXYqF1kS1uDGCFnDdTfP6Gdqw88UIdkE52krRB
++NaAeyhrhQlivqZ3Rb2EvoXpe9NZUK7TMN4tE/PVyoe6d8D2NPIbPCCVnpkCgYBL
+otSEdmxAro9fbr/vJNn5UftKefRUCUVHLKsEgOiqIIBvhE51Md5JBKJZNFfYLV4j
+s3+z5d5o56fsc/Q4B8llh0v5SGk45PDEct+Dj7DUwRTuqwgDpBR/AKomNrbGqCXY
+0ksAn94/JoTffATeNCWhk6l9DV3lwzC21iJ+GCFY0QKBgQDI/hmqAelRmP8Msv0s
+zmcLxonkVGN2S6L7Cb5G/IjJIr8y7/cPnYsnn3an50fQEbPpvC1ToQYO1HUnDi8h
+/kgvgoFISGPhmgmRYyB4vUs3bz6BhXwLtZFRbzWVx+G8PLsqDWfI75u1BB7G1NuE
+HX2TFHQAwQlz5wV6RhF1fsSkxg==
-----END PRIVATE KEY-----
diff --git a/jstests/libs/rs2.pem.digest.sha1 b/jstests/libs/rs2.pem.digest.sha1
index 51ea8c2a107..e51df15bbee 100644
--- a/jstests/libs/rs2.pem.digest.sha1
+++ b/jstests/libs/rs2.pem.digest.sha1
@@ -1 +1 @@
-F8CE82E0260BD1E887BFFB6D3C684424176392D3 \ No newline at end of file
+D35B3DBB21C52EFAB99B665295C4F77DBD703E23 \ No newline at end of file
diff --git a/jstests/libs/rs2.pem.digest.sha256 b/jstests/libs/rs2.pem.digest.sha256
index dee82acec24..affaba55b6f 100644
--- a/jstests/libs/rs2.pem.digest.sha256
+++ b/jstests/libs/rs2.pem.digest.sha256
@@ -1 +1 @@
-81EB924EF7B01482F034DE0D0744FB017FE8F005151048B9736890AB147ED911 \ No newline at end of file
+509B3A751A46A570840FDA531B24A2AD7669DCBFA1FF0CDBB49DE157ED9C362C \ No newline at end of file
diff --git a/jstests/libs/server-intermediate-ca.pem b/jstests/libs/server-intermediate-ca.pem
index 19dbb5d415c..89928135e05 100644
--- a/jstests/libs/server-intermediate-ca.pem
+++ b/jstests/libs/server-intermediate-ca.pem
@@ -3,74 +3,74 @@
#
# Server certificate signed by intermediate CA, including intermediate CA in bundle.
-----BEGIN CERTIFICATE-----
-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
+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
-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
+ZWRpYXRlIENBMB4XDTI0MDYwNTE2MTQ0OVoXDTI2MDkwNzE2MTQ0OVowfTELMAkG
A1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMRYwFAYDVQQHDA1OZXcgWW9yayBD
aXR5MRAwDgYDVQQKDAdNb25nb0RCMQ8wDQYDVQQLDAZLZXJuZWwxIDAeBgNVBAMM
F1NlcnZlciBWaWEgSW50ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
-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
+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
-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
+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
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQClY+uPKaJQrh3m
-0Y8RM0VGBDrTV4RJHKDjf/00IjFxOrcIsgXgPb7IY7EEhfqFPHMRbMsr+tawxmGT
-j4lrnWqyyW2ur/c/3H8i7brKpXVdtWXzxZp9OVki+HxwMrzPJsPjMARU6jKFNtjH
-xqdnQpXENMWoAIBDS3zKCs2Vh9Oeq6LtvDXK9cD3TJgMyxNAoqpV1I3Km3tS/rTy
-ehzMa1tUep/kuA1INBQA6lvGKvgCSX/Z8zxG9hfHfzDjMUUZdQoKzmJyscAlGpJa
-m13aGeGhRGvaGHYg54upEydcTJqUWYoqB2vRIt6Eq6GQEOrQDHQFdiCSAZ6DMZc5
-nO/Y+FkdAgMBAAECggEAKA1lm1rqyv0PkrlHG1Q+P3GAyXOVPptnPxDcwcZSEOi2
-MK3kDGUHkcHKuZy0iZWVDDA7l5/8Y/z23mRRVDVgBIIRRM+qYdXFGDFYHgEpxhLK
-6Nj+y7qaooRopkczQDtUDu2u7t10dJxOrTqnibMvT7+z6jaM2T8rrkYleUPWdMMa
-KruyKhXiEPZVLZT08EfvhmsXUtU0Zs+0C/gZTgEly3TCWv0Msid39V3LZwxPK64z
-19YaZUTEANq/WjaYyWPs9tmrcm7HazLAVf+JhiC58PBg+qjWj6wHSBLqsK4Ofipw
-ah6T8n2/00PE61wGEzCHL80ajR5aGV52WxKKX8FPxQKBgQDBNBwJc5TzzAZ0EYH+
-6BtZyocfdCsh+rWE/pG1GRlIe1/R+69nqY5Wmu+HQZfiR1LU0/LoenYHklU29MaS
-DmborQgWHWaUYJaHv820/nV8gyl0dn9GBuQDZN9X1ySWArWgqrsF1xPl+1mVJoSq
-kPnt/xYShduSnQW180Z3KiQifwKBgQDbJY3Vwj0q731V10fxJW48S5QueuJeWEzi
-JY3EE1oDSflOJfNP3nzMygGXpUZZyH2ahZMfiA7PUpbVq+33OaCV4JQ96Uh+6xy8
-aQcv41UItsVl1LSKeFUzENt0OwbV5q3SnafCA4P9PwQSpw16V+ckzcUrIFhSATqD
-rfmagLv+YwKBgBiEADrCy9fTv83imtg5o57VMCgxmXeKVJY3p02PjcHAxfvjL/K7
-dTBQIKzNCfTQkBYpft05DNkRHHcIwFmwMia8LhaATI/vYaqAEB4zW70c95mrn6LH
-JQ+5MQ34YtAWL+3fPDQVgpTgPBHM/XCXTN+CSs625ZHJEvxvjjV4x3UJAoGADtR8
-w7FwWD56udtmt+/zhMsMjRStyvqowUkPTeyNU9mmsF4rGAWTZnxpHS0HFL5XmaRe
-b2zSq78IDA+le+x/bIUVIxdtW4FnoWxuGxSERaGwvBJn4VMBWQJUB4qTDNiefLlE
-iAGa5gFksipx5AyczMXMCP4YW/xPTGfykz0Q+8cCgYBZX9Gr7vPrucPGaaYg/pKM
-WmLlmE9coRu31ha5gB9YBaepQa8AUlgGakRidxKSPod2gS24ggWNPq0G8fAMAtbO
-LWyRbGAE2SBOJSwnfzKMBlDL/7NQYGo5PB3sIue8l3uBrrcLNobeNri3fqASR3/K
-WmCFIucR+ssLWzztYq+1tg==
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDRxGCzMb0NsHyS
+I6PFYF31PrW+RsIFphYq/hVqVyEsammGVziBCzzZcnM4Mkt39gQsJFT8Qey0q60i
+b3wpH9f8onhpF1iuMrTvBiPUotP5BpPXeng7CBiZI3J93OTbnAJelt5JLu4OKAuW
+a619ecBLlq33EmWLrD/Qp0mEfnmItEpGzC4H/rYg3n+bryHPm+XKS1Tm42CrGrsR
+2nJ6pXQzl/VCIQkN/3LskW2zbPU/gsyQjCYpjabapqLISaogZyhA9WbDhm7nG0i0
+jOjaiXYIA+H1dmN4Xcn0M8OQ9cFur9Jz5i0OJoKCKhSt9pa0HTjSJRW6JMLFD1/j
+GlHAAsMVAgMBAAECggEAT8w3yRNbyvBfgyyBqZ0uQRRZCQhb2NBE0JgVx31bxky4
+1f0qJpUC0emjATbI1NrG3Y/4sHnXtSc11sq4XeCaRqX7zmauOp5ZjDA2wzYqEyq4
+ZRlW0YYT7XW5oT295fkkQZ189DQhJUuAlPljZz9AssCgb0QVUxv0rshkxD1kuGbE
+fqEdyk/S9Ou9KxdWBLHcfYl+5KIie8tClEW0Z0sURuqPC7njoddjxjOQWeeO0/0O
+n6EolHHcuMAqIQp1Od+pPfODeQxLyZHVpDShLLRA90sdbbNvn51PhwRyGmEayfZJ
+WSJjO1Q5UvpHvvQIXHFYS4VnMU6lT6vsUu/A5kp9oQKBgQD8plyVXaHBQGfbKnH3
+ii8/eUFt6qAFCqCOzWkqdLA8cLaXNLUfiSIK+xJeXAHPkxvBloQkcNi3xIwb7WV2
+xnDe90BL4GRppBbFxMOmm4zkapc6I4n5vlYxtcEaNyWeieob/Tqr40fkHpzNq3yR
+tAjpa4le6QlPQRe3Wix1WpuMDQKBgQDUjHKMoGgi0eqUzi7Jz2F8cCwkjZSUTG76
+AjVzd/j6/kYsDY5BkAF7j2D9Eb0PelsVkQor02ZhIWkE6temYlzbBSs1BlCJrwYf
+Fj+jeTlm31tLbWh4xO9xLgdy0+bGuW3Kwn58AWF+BV/syiWUadDB54pnlttJzV+V
+khkVAUhpKQKBgA35gbt9T1oqHtR/l4gyq4ReR6E1zh4ZRWJAuGVxyOG+9kqMzsvs
+wOZMluqDOlJp96oQkkSVvVcE1x8gVXFpborWsEbCJau2ONA9nvjTN8rWnoDHwHUA
+8zGStRinHjyTslBUBG/HhY13qAK0TpKcm7WVjiaiyzIIDrDEmxrupRXtAoGBAJkw
+SHb2PVerN4jcOXiWEMrhBc+qgwWHOQzTfrakJzyu+uBRPNAf/BGTuvFqUXrQUslu
+aYhAqq8ip1A1+gsfJZFtXkCvNmilTqIlJOSrQCXWoTPxvLQeK/zEkfW+p7tedbUH
+DKZPUHbFZOeCoicfRKgcOvKCFbZRYKyqSY2MCSZRAoGBAL6VyNQpM/epiEKz2Wmp
+shcCmyJSXI7cikbzjF9pFOZnPbCvl/nyS41Sik8LiPoVCy0D9fK1cfd3bEzRfCMx
+24yVY9YddVYJ+PO8V29CgtFKBXAMBr3x2ICDHJsBeFMUpCPvdIG0gIcuk4sOH4js
+ZrWUyJZ3jxTw3kKlZmEZSrA7
-----END PRIVATE KEY-----
# Certificate from intermediate-ca.pem
-----BEGIN CERTIFICATE-----
-MIIDdzCCAl+gAwIBAgIEPxCEvzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDdzCCAl+gAwIBAgIEMRP94zANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTQ2WhcNMjYwNDE4MTYxMTQ2WjB1MQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ5WhcNMjYwOTA3MTYxNDQ5WjB1MQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEYMBYGA1UEAwwP
SW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
-mnjixoApuIjaBybO3Fy67HEdqhIQTSUiLdcte7A+Lip/nZ7H+r2eJdQntWpuCAA2
-ExSsjn3IXwHayp/3ekUX8f4KX1CwWx3fP3UpyPfirea+AOhJIPuPWGTGzZEcaJm1
-JJHnuKCMWq3xQjKszi6IqH/725jWFRG5uz4yFdsnIFkG6Q/MqV6L80bndJX4VgfM
-s1Aw1ax5tLjxsuk5fAyw3WjPepJ1f6pOGpaWmgp+z50PLOIXufDQcPxFxv0WAPwv
-W5XkJXCDDhh2AktF9eaVjMvV2lPqHmCQiYMsPj3uNT28ceiGa+mQBHr885g8zWC8
-v/MtsdKWce+sMyDjCxFnmwIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3
-DQEBCwUAA4IBAQBjv9XjW85ID6T8L8VxNe31U7+dlVZfLsaFVvUBWioTXl3MbTOx
-89/E+GOzsY+0q8OjPiDoGoEXuQzRrPTkSk/Fe36RBEStUMQSQa01Oq3dxVXzIQW6
-ZUkD+C2aGYxmq60evvkgewvTxs+iROv5Rjs2IPkgX2XXNzeGRgDUNZbVY55dBljR
-5ctsmGsmgjdakOKoSdxhwuW0EP44c0JzaBqX+kbPIi2RUMH34ZCyfWVUCgkLrEf4
-TM0fKYEwt/cgcBG7dA80HzLlD/WYvbuVdY4wUAM5UsrfRjVFVQJz+q6CE4COkB6i
-BrhBbDMi1k+WXyR9lVyrDVaFsUqdzXIXHalC
+4iGdS94QMpwbVEkqXD7LhyfKMr1qMcSVgSNAOw5XCvgF/i0/TugIcOgdGanq6ksQ
+1vO87jraCegLuOAz3HnzdAw6grcsAohk3RpZcmyDvpsyW9t80UwoGE6WeZ9+//BW
+uaXuUuokuoTEFQBxU86igIgZ1we3sFfuD47pettQr8NUz911Oqh4xXztXLmD+8Bn
+FHA2kwlSR7fJRJDOa/jG60rKSYbUvTCH9qK7GinXiot3qiX1XgO2CCesuYDG1XXH
+72ENb6bg0kGS1pKMJQhxArwV5xwykaJ3UUmggCPMwURtc96RD+9S5yhIjKPB8PRs
+lU8o4Qz4//3CLqMFQQqRMQIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3
+DQEBCwUAA4IBAQArkFpwgHPoKuWHeuDnSqsM68vtORDN95H/4NXaRONxxBz/1owW
+ptJ74jPMlXLYy3tA0q5cLZuJzFQ9c643S3kyDeKsFYqzzDrgRSpJPcKE5Rg6DWXu
+7zBHWbqcvfYoBrJCUDTN30DMkEGkHpdVd0RQSZ+/KjyTEu4CvEei0taAZ7vWj3Yn
+5KwMKyvLNxjpil8SF4nofBC3iIxpD3C9uSSzLrm2ASTYWQLWGX2KUZiKF5Y3KYim
+ZYdBBVDNtHJaKJbomwcXRjcUA68J/4XPeFRH5yyE2/j8xII3W2pB0iPrS3DgMoX+
+0GMp3Vx+WBnnDC1dAintOkSJtW8hKlvYnfJr
-----END CERTIFICATE-----
diff --git a/jstests/libs/server-intermediate-ca.pem.digest.sha1 b/jstests/libs/server-intermediate-ca.pem.digest.sha1
index 9c5d3b57587..37f6572c1db 100644
--- a/jstests/libs/server-intermediate-ca.pem.digest.sha1
+++ b/jstests/libs/server-intermediate-ca.pem.digest.sha1
@@ -1 +1 @@
-AC34BB9B3A8645AB93EA1B689A96FEA2233467F3 \ No newline at end of file
+FF5F0F1C2D6100843ED2438D36544172997BAC2E \ No newline at end of file
diff --git a/jstests/libs/server-intermediate-ca.pem.digest.sha256 b/jstests/libs/server-intermediate-ca.pem.digest.sha256
index c1e5c99c31b..50393510af4 100644
--- a/jstests/libs/server-intermediate-ca.pem.digest.sha256
+++ b/jstests/libs/server-intermediate-ca.pem.digest.sha256
@@ -1 +1 @@
-CC480E69174AA97DED6C6250AF3AD8173693119924BB305C0C84759DB4998885 \ No newline at end of file
+D159285FCCA431555BB01AAEEDA583F189B90B9EF947D783A50444B2424CD529 \ No newline at end of file
diff --git a/jstests/libs/server-intermediate-leaf.pem b/jstests/libs/server-intermediate-leaf.pem
index 5e00914e87a..b1f4d419dfa 100644
--- a/jstests/libs/server-intermediate-leaf.pem
+++ b/jstests/libs/server-intermediate-leaf.pem
@@ -3,52 +3,52 @@
#
# Server certificate signed by intermediate CA.
-----BEGIN CERTIFICATE-----
-MIIDqTCCApGgAwIBAgIEIdCSxDANBgkqhkiG9w0BAQsFADB1MQswCQYDVQQGEwJV
+MIIDqTCCApGgAwIBAgIEdhF+XTANBgkqhkiG9w0BAQsFADB1MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEYMBYGA1UEAwwPSW50ZXJt
-ZWRpYXRlIENBMB4XDTI0MDExNTE2MTE0NloXDTI2MDQxODE2MTE0NlowgYIxCzAJ
+ZWRpYXRlIENBMB4XDTI0MDYwNTE2MTQ0OVoXDTI2MDkwNzE2MTQ0OVowgYIxCzAJ
BgNVBAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazEWMBQGA1UEBwwNTmV3IFlvcmsg
Q2l0eTEQMA4GA1UECgwHTW9uZ29EQjEPMA0GA1UECwwGS2VybmVsMSUwIwYDVQQD
DBxTZXJ2ZXIgTGVhZiBWaWEgSW50ZXJtZWRpYXRlMIIBIjANBgkqhkiG9w0BAQEF
-AAOCAQ8AMIIBCgKCAQEAnOuOjR8l4+NbQ230jm39jrJWPnrG7HDihAUf9jvQkZhk
-9OsiNAD1BozkieGiQt8aQY6J1YDz4lBVcGAcwk1pj8YTnhlKIN6dBXLmBivyhzC/
-uBeDPg5Abbi3LMz2v+J3UmfABWBM1ULC5thiGY4sQ07wqi0/dXEbRBg8S40j70sz
-eJ+TD6+26kY8fExpHohXNxFwYJKqohYdfGL3iXnHHh40SoWmK6FdswWU3F8uP1A2
-GnGWITmuAtH8EBP/81kWCYX3OTYMw3amuI4jEFIdhUFdLnF7+K6fhLwls7QnsLGy
-1TSeY3Y5qCrjEV7yg06aAVUj+gTwYVid8Gi7wU9cCQIDAQABozMwMTATBgNVHSUE
+AAOCAQ8AMIIBCgKCAQEAtq023AAMRvcbIBm1h0yTSSa18YGdXGhDsJLU2/rGJwhG
+8w3x+UzfjYlEIn3zxjujDntlkhPHRaPIM65eeWIThk4TgCQFKzry8kxLMm7YUdN4
+0weLNxbTThiFd4RKrhXPr/J+YwHUAka7IuQjNOvmX89evrz/7g26KYOERuYf04K8
++ZeEj3DLUsekB5UxL4yUU0ck6DgL0s9ch+RsQzEUXplkR1knJNmBGi/OAxmE2PX5
+0rJbqhDGQPdPRO6zgAU+CFYkoB6j7D5yXYE0NBkXfY36QWCzIAToe7zv5CvwcIk6
+uIF1cregv++AA+P9RVWVwSuoRW2WkHUGh1AmmLINtwIDAQABozMwMTATBgNVHSUE
DDAKBggrBgEFBQcDATAaBgNVHREEEzARgglsb2NhbGhvc3SHBH8AAAEwDQYJKoZI
-hvcNAQELBQADggEBAHFlDECZqP48Wn9sD30jJv9GPiNs/jRdMQA19AXGH4C8z16Q
-523D0Aw1pbp59ORfsecJNqzkyhuDI/7nae4lTj+cXAfV5BsNbmXJg4OTJK7THlgF
-qey5PcJAVoep+XFXOaiffYlIwQcGpDxJqpH3cLZo3/cRkIMMPtJUZGR9m0AnsQuv
-hrn+1ecWefyYMYgKgIt2TzMdzOtgYfzGwtrlFXO4t2rP1UgnM82P9uD0iLBh+izo
-iaieBFXeGL9O0uHbMJj+YgHsmOTqKHPpGx6O4oRygHwi/vfBnNLgspmmdJ5Q1WA3
-iWcQnhfogieYZFJ6FrGKR9bGLCC83avyzyZYX1U=
+hvcNAQELBQADggEBAHkg8jH6/ysk69utO8LyxOKXu7bkv62pGsi4ohLwO+uKjB3G
+4gHILirEi9iwYR4jTbZNEDR5mkrk964O8Oil2qqSAN1Nj8Dokcmep9vROMqJUbOl
+N3sKCG8HZWfxy4ixA67yx53PBKXLgOkPsKE1x8rkPuqYJGsBOY38Nbqa4y5HpsRZ
+IYkGn7Q0QjEhI0/ZJ+2Y2hE/NPjAm5fsDwdIg6SAJVjK704zPkMi1pS6p5S9hAS+
+HJsTau1N6175yFqH9QSlqdtcd5B7AzXYc7lOcuo5X9EFLLO3ozUetyxvJEzcqPiJ
+d16n7HdOt/BAWUBoRseORoqnb4hprwPULCmYo00=
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCc646NHyXj41tD
-bfSObf2OslY+esbscOKEBR/2O9CRmGT06yI0APUGjOSJ4aJC3xpBjonVgPPiUFVw
-YBzCTWmPxhOeGUog3p0FcuYGK/KHML+4F4M+DkBtuLcszPa/4ndSZ8AFYEzVQsLm
-2GIZjixDTvCqLT91cRtEGDxLjSPvSzN4n5MPr7bqRjx8TGkeiFc3EXBgkqqiFh18
-YveJecceHjRKhaYroV2zBZTcXy4/UDYacZYhOa4C0fwQE//zWRYJhfc5NgzDdqa4
-jiMQUh2FQV0ucXv4rp+EvCWztCewsbLVNJ5jdjmoKuMRXvKDTpoBVSP6BPBhWJ3w
-aLvBT1wJAgMBAAECggEAHJDD+zwll2HSwghg6dGrg//Cc+7BShb1oT9WlWpHmk2B
-6VTpfcqD0EyzKMd2lJJNEwyJ2mA2ZWcm2oVgjt1tP0M5XIExjaDAuFZ1eb+jz4jo
-CbDcDx6ki2TCEamBLKai/pEM812XtwXHeaL/3rOTKrCS3oPMpsovgrqftUgs97kx
-khG58QqBQ5AOZHNvIHVR6izQV0hfPKBLfvCJIPQ8fulFHgTkKTHdGzsnz+D/ZILH
-37tvmTalG5/s/0cbH3gKsc0IlCL3ue5+lWfRsiVxtTvpkYN62ugdMGBd/oQ0zL9e
-aAxCCFYPj06GmENRgCzuRxyuIK5dj76y7LJ7KYlqVQKBgQDPf67v951deKA2k2rb
-+Ie8tTDgBNFDM6e3iAWRd6QWBV7KScpjWk1LiGKb/NSPiBOAFAzDZWgoomfP4MrS
-cJcQqjCip7rQt6pgx3NtFuIqd5ZH3tpFWe9L8JFl2R/sBM8Niu0i7aKFstOyvVA7
-NkKE60akUr/Qr6nnEk5XVYfehQKBgQDBmVlEL0Y72hE6f3S7AxHdKVo5sq7QyP0q
-tY0SWe0MygXrVckimLi1SeaXR/4fdWUN/fREwNLcUELvFXmW24VfI+O9ROxkJeLe
-Q5SZ5bFg0BpAPqSkwCtAyt4kPhNkYjt3zmSZYEqza10JyJI8zsoZjyq0mqh/CQQ8
-tYcmbEVotQKBgQCeb7cqwd4ltepXYb6xUZaLT6qPEv6aGoIQkEr4JOtkaRtUyH1B
-2Xy1lOD+jFHdeqCxJh4MwIyEomU0BEe54YBnmBvkxr/NiMAOf5yyCkwM8x0Lqazu
-UVp3mKvcoapPM+jJRXAGQH7dKYudqhHt9GNcTK224PxXoxnPN1ocM1G4ZQKBgCuN
-Ksaq99rJAK0vNPxJAYDGJ7TpHGh9fm5YLyccsbX50IETaE7vGkY2HLiVinZbO2N9
-aLD6y7SiHZyZMSQduBAiC75tPdx9pV6ox0ojoNaNmgovzWv+ivxlZrmyeTxQ2N3n
-wTu7rLJWCbUEuNkTD+XWDh5Y2GTTi294yrF7E9YtAoGBAL6LGa2qerZG0DacaVD9
-Gj1pFfIcFfq/wdjOIhtlsIL1jN4I0bi/nOH7gze7kXngTuDwMAdiiOt9L9QY1I6e
-UKsc1O5vENqIilEZ2g8eE7JfBxFpOK9NnYB3N3YGNkC+osiRcJykgmn1bwf2UNRp
-CXjU/c7ymSxzzdW9q4RG57UR
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC2rTbcAAxG9xsg
+GbWHTJNJJrXxgZ1caEOwktTb+sYnCEbzDfH5TN+NiUQiffPGO6MOe2WSE8dFo8gz
+rl55YhOGThOAJAUrOvLyTEsybthR03jTB4s3FtNOGIV3hEquFc+v8n5jAdQCRrsi
+5CM06+Zfz16+vP/uDbopg4RG5h/Tgrz5l4SPcMtSx6QHlTEvjJRTRyToOAvSz1yH
+5GxDMRRemWRHWSck2YEaL84DGYTY9fnSsluqEMZA909E7rOABT4IViSgHqPsPnJd
+gTQ0GRd9jfpBYLMgBOh7vO/kK/BwiTq4gXVyt6C/74AD4/1FVZXBK6hFbZaQdQaH
+UCaYsg23AgMBAAECggEAWdwO9l2XrHj1gO7kmu+SLBO8wFYQAFrRoVQ5HRTY0G6D
+6B/d/dJQzaDOQWFPvx2q8f7FUfwktB8C5llJ48/Y5uIVOZ1+ZWuUApiBDQf1pRqv
+fq9hTfIOc4YgcVBEJCpahaR1g2Js1cnRWDJ9FxVLt6mcY5s5EfLytmUZdn7Q/Qun
+pq61yOnsWK4IPB+Trejsb0nmv24foTgE/x4bt34VgXR8lXk+P6l7AWmkPEJmGy7j
+Wzmu2WYPSSB3hbfKfjhXSHCfnm0E60Ur6gXfw8q0Grre4LaLbpxpv6zD7cvCeDPo
+dek4+cETEnmr70NcRYFeIwEUoWeXDBKvhSTM8qSa4QKBgQDlVW9oKeccHM+X8hWk
+rjZR1CvLC3bEslxVwlwCKOgjNnFY/hxI7oA+oihZvlt+0JyZ/PIhaTtk6fMsQgIn
+KGNqV8amXPGX6R5zRmiTtdJEmQKfVZn0/yz38O0c2Xq5lFzGwoRd93XsbLxR+uwD
+nOXF6ttyYkPCDcPe5+xNmOWQbwKBgQDL6vB5FhVGr/hz7zFQ99e98dW5fg9wpa9o
+W1Js4prKDzCu+x294q9hu7JYkkG2lDJxjujSL8TnwTRRNdjGCoTcwIXF5bCuXs9z
+NYL9U1QN4e6Wl6+2etz8uRJXQQK/79UY7Wo5loaDlkuB8oyNzBgtsjRC5Aj/qgyn
+TGOHf3HrOQKBgG/iF4EE+GhhsfGaPG7kQ0H2tgrQI/hgX+XC9apkFKShOflFt7zp
+Bo4IBJGL6g1bbxs9KU+djEl2TZmo9m3uKVpHSnX9YCxRofZxQjHWAahP0dS0KXE6
+UNEBrFxnyZTiScT6PyOsx845WkLQnPZCRGMjaj5KrG3u00FbepB86HpnAoGARRTQ
+ZpT+nDXdG5l6wY1U/zpAR1jXbjgTFm1pnQ2flrhSq9TSnJOBCsEFiE/0ByBpfmMF
+qL8aG9EuIhz11RGXNRnbt9E6a7ge207Tk3J5VUKnC0lT86Pn3Y3tErYpclCThqBX
+ji7aXxW5espqp1bvEfv/DHIoQkSfiMWuKicYtrECgYBa5S4KfjG6ArOtIoCRm5/8
+woC6EuX1Vp3KLzfE6ukdyFh5HiBXqrer+/dtsPXIAoBVMy/oyx5K+aow7si9hFBb
+Sv4t1TLj5SiMy7oN7dcAWSWBP46hRVzN9yn7bSNsAtSjT6rs8SUQ/v0Q1MNvx6SH
+QN6pg+9e5iRX7p9MQuEp4A==
-----END PRIVATE KEY-----
diff --git a/jstests/libs/server-intermediate-leaf.pem.digest.sha1 b/jstests/libs/server-intermediate-leaf.pem.digest.sha1
index 690168928a4..fc1bffff35e 100644
--- a/jstests/libs/server-intermediate-leaf.pem.digest.sha1
+++ b/jstests/libs/server-intermediate-leaf.pem.digest.sha1
@@ -1 +1 @@
-783E0BD615F832200B9D4A3388FA5369F941EA76 \ No newline at end of file
+9120929356C522216EF719E98C9DECC7C1C53B89 \ No newline at end of file
diff --git a/jstests/libs/server-intermediate-leaf.pem.digest.sha256 b/jstests/libs/server-intermediate-leaf.pem.digest.sha256
index 6ee8f893b28..426ebe74542 100644
--- a/jstests/libs/server-intermediate-leaf.pem.digest.sha256
+++ b/jstests/libs/server-intermediate-leaf.pem.digest.sha256
@@ -1 +1 @@
-C04291C3590C82026EE51BC35B84AF24263FA526A19AF2445744DDDB45749853 \ No newline at end of file
+A4BCF8E51FB41F70BBF48A7AFC0F77CC4651C857DAB26BE5351CF9EBAF72C204 \ No newline at end of file
diff --git a/jstests/libs/server.pem b/jstests/libs/server.pem
index 3bc1b16fbfc..517a97152cd 100644
--- a/jstests/libs/server.pem
+++ b/jstests/libs/server.pem
@@ -3,56 +3,56 @@
#
# General purpose server certificate file.
-----BEGIN CERTIFICATE-----
-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
+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
-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
+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
-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
+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
-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
-h64Z06tWjHG150447PjmZF1bQNYgNjOG
+Q0GCBCBp1p8wGgYDVR0RBBMwEYIJbG9jYWxob3N0hwR/AAABMA0GCSqGSIb3DQEB
+CwUAA4IBAQA6v4mt8ILhLVOkt5zRnw2QdMQ8YJddrBpXLbanx31rjHyNSPJDApVg
+u6HCNwGoSITJXis1d6MbnKbkbW9zZN4sR1eHDCFdYqv7w+QRmOyeHSeM/AvNDbHS
+L3ysmqSwXKBcOqpCv5MksoChuXoBme5tPAPMaFY61F3gLTONXZCjEXR/z5PiaMfq
+dCOVpb43ssgbRJuSQaD+4ekJugCsAxZwuZeymEa+U7gfRxAJRGe1ct3fVfZ/JeuE
+/Hg91HvyAHxr0WQm4VF/oXYnD2wv92yGt2GNB79rFCl+Qq7FhZ2oEilIrg1B5Bz8
+axFG1R6wrrP881MvFIvtDwjsyBMNwSx9
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC4VGsLgbI64Dcq
-GNqNUFU2APfpkqe/CJ3pCNmUr5hRWvI/1ML+j3lX5u+49zOP3B6tYaZjGy+EGGoI
-oK5s/Jsm0ny3le9v//+1Ya+VJ7h4r58W21K9RyFvKSKBbC3sGHkaBE0RC1XdqCU4
-LsZVuqP5jrand7XnOuHZsv7TDWfJHANQE/HVaMStZpSPELaPjn5y2bZychL5KKhA
-tLoJBvl4TvN6OOq53ZQ0qZbuI9lmYMl/R3EUnRmiIKafQcutNY0JJSZwTfT716ZX
-rNPWUvtZCehcEXLo5HSB1UCtn1ACwDiG7aVj1pBIzEPpUVl9KkuFbt9rn3nbvfkQ
-0+MdCfRBAgMBAAECggEAD1lHLxZ6AfVK3qRiaXc1mzk2K4LA2VNFO+L25C7BdQ/I
-wXgs0v/dK6zBDCK4bkuW2draXSEFwj76sFR55b0cib1n8W0ImqfDUgYL9fRwY8tC
-6OczIuvt/Ki9FPAOPF0200vlo2xRVnNSgxTBAuE3V3fS3YvGL7aLWSJynd4dROV+
-HJ4jKFKe+ovQhtMuU0iaw4CrMyBDHw98/widcQeX16O1ITIbRwo8311ukwiawVL5
-FbWE77Y6qy++4TO3M9YKlIv3OBkfx3bgPguOksg57NQh2IlNz1BA/e2Amswv0wwZ
-FJjJvWxsK5ujRnX9lN8gwpr6FUakXMBp5MdJEBGoeQKBgQDo/EPb8DClzYH5GP9b
-O7zOekRkzArJL+unmXzxQcXB2XUoq0dhvdAlGVchSvWhE4h3j3ZVC5Wv91Kq9iNp
-snCku628HTbGq9dyRypN2DJSh4vhokUtaZV/YrWJ5VkSG/cqChNjDx6vu8BmDcd0
-x4wM+DVu090PZuNhvXKjyIEP2QKBgQDKib+8XgmclS9Z1PKU9BymMN47mwR/1Ibq
-DX8gJkEKny7CVu8Gz518EqWYQ+zIcyHzjgORPmBzKjCj0+uun8SHu1wKu/fAFbHX
-IB+DCfnmr4mj7Eju71LKNnrj4RIiqJo4t1hgKxC18sa8n0xSDdeiSplzxVo1PaHi
-5XtrZfmuqQKBgAoK/b3YT7CF+ElNi4xaOdxIpvQVW42qlCToV9tqc2TUw9kZ8PzE
-mtlOi1PzED1+Qw6sT3SBCFXKenTGIWan+3UOZgHK3JaZx7K0YJ10aU7nat8yCHtZ
-pskT7zFfgoRmUjQstQM7Hp6CoFuF0og1JdNVS7BYT5ofXEPVT8DBntaZAoGBAMhj
-5eqvd/8Os9zDjofFxxq/OwHqbFc1pY6pb+AVOUETIiZx8OjiPcTmhiTS/9GL6Emb
-dvgbqT4Ivjs5j/Qka0SIIZcVRxkr3dslE0iJdFHD2ADx5W9SJq2fnZMdut3Dx2La
-NHxh35TF8c/qJI8C1xjhilY7KveGVUezGZu3N4SRAoGAN/Sp7cceGAHbRVe/yYBS
-H1w67r3rgCtbZHuXljkqmb0W2gUR17JMD+UAp3ZBJXMHPD2TGTv77jp3uiE6KFbD
-uDV1BBeznooR/SD/tXsKDy5mVR04KLC7ih70Gm5/XVY/aQRXOUS7F4LD/XNlnN1G
-8h93q+63Q2CDtPdQTnLXwGE=
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC6wSIZosBVGmAj
+vbzJCs/euYq9MD42h7pP9RaJKQW/Os8FIlNAbSfGAM51LTKnxr3b8JviGZsV4KTk
+0Q3xqDJHqSlqo+y3dvmDor04Dn1S/H5dFQwSI+KOW9/Qs22BIjREQWCtFE1Fwdr+
+6V6RIa1L6plbnLh0WG8pqsJcM9wlT5uJfPNqOzvYEFGqQn/RtkUaU1q4AApTQl0V
+drmi601TA5YYMmVNTofShCG4Wg3IMpy/9VcErv4dup1Kg+tW36jif5AR4AcFLks2
+UrUiQVUzE+bwlNa+2Ncvi2KPHMgkbFGZLk9Kp1EnQvmEm7M/5J1JKEzAZvPH7ZOa
+8aD2iOPfAgMBAAECggEADcK/XX41h8/Kt7d6WqH2USYAyBHu85uqqcuYXoDsUHvn
+1ywBUGT6okda7x1mdyBYywT+p3lViRYlcErLKTxIgClByP7NKXOVzRJHuQKwT1YV
+hYxQeGG2huDULA+ciQBZM5JRqk8tpm8zUMcnVbBSkZ52sF5q5P/DKSHQ8nRLy1/i
+6kdqlGeb8ApaW/K+yB8JSH16cKMpn2iHIDWFbfFaqjOc9sCqzZ6RcKiRBClokLfl
+DZskRsqNfloNqgvg/9wRDZOVSgMf+5e6pLIoU1YX3Y5yCrj53eDCemZF1o5is2Zu
+/eN8WwrFAtARDF1NFFs2iI8iJpMcuAxlWGLEWEc2oQKBgQDwmGVcAwWt1zRO28Ia
+n7hmowCJnJMYoVmCXArY6Ci8M43vFN3/j1eET3O01fTLhl0HXo3HBcIMzUNvhCHm
+BLwt7Z1ZuNxFxDo1+Axv6P7rosmDvxPswQLGEXzBUI86tAY8cPfzzu2SUeRl5QHT
+u8e7LpwJUj2P4zdT6W/b+iWt8QKBgQDGtjrn1Vw8b1K9Lz6sZhz3WrWH49YAj7VM
+IhZ+NOnez4BMmztK9Ix0T8zZ1y/xMYjwUwcVwFOB/fLAWciLq3ZKkxgHFN72z9bB
+FspTI9HocULvFf0lNwEKpDF/9hJ+3zBcEkrp2S5RfV0ZgvSbn+BLjwkEuzqNBeRZ
+apHLL58ezwKBgCT2BHxCKpkuOmby87rLVrTNzcNWPnLGNs4D/dacs8VV1jQobIJa
+LwOwgQIC7Hxnw9rh973fcJQu5HE5R0vi5lXX7xhdgdll79tio+Z9UMw6UeLfc9wn
+OpnbDeNU0Owfw+V9JVpbK7wSwJe2urUgX+qtmmMEM1jrexB1CC4vG6LBAoGAU5/E
+0mOb2WMP8sW7Hloqvn3R/0oGeV4A8fU2eg5SjY3NdG+vWC/qG9ipYNOKPXqXImwO
+gzzY58+zJPejygNyWJfmeLRz0HJO8hthMfPVFnjzriIW0l5/dbb7jdpEllfexiB8
+nkTjlS+oyl+uCQATKDkdlnwke8yK+IY8rMFxuUkCgYEAhOc0mvF+Mj2usdI/erYp
+JXmqzfYH96tGW5ihcP31MdZQPadKehQVWD1vcR6KnVtYv+7gP+ldmzR8RJmSy3n6
+Wv9IqSlvDE4JOjkRajPfirlJ6Df4NrG+yLJd/5KoH/XK/oaqm38dB9coB2Y5YQqC
+UQ9Mss5hIXecv2DJZPxvZPs=
-----END PRIVATE KEY-----
diff --git a/jstests/libs/server.pem.digest.sha1 b/jstests/libs/server.pem.digest.sha1
index 1ff98f8abda..584e879133f 100644
--- a/jstests/libs/server.pem.digest.sha1
+++ b/jstests/libs/server.pem.digest.sha1
@@ -1 +1 @@
-C74F20048A083626B003CACE2A7CACC3F5E111E7 \ No newline at end of file
+FFA4191048D6C520E1AFA0B118495F5F3C04D1E2 \ No newline at end of file
diff --git a/jstests/libs/server.pem.digest.sha256 b/jstests/libs/server.pem.digest.sha256
index cd0cd784f5d..236171553d1 100644
--- a/jstests/libs/server.pem.digest.sha256
+++ b/jstests/libs/server.pem.digest.sha256
@@ -1 +1 @@
-B47CC498F8B8EB814F651409057F3B4E165A4C4D8E6503943DDF4F613A9E68F9 \ No newline at end of file
+1311A239784AA46B1AA7C225F65669CD3BB3074F0061CF2F481E6293FFF2FBDA \ No newline at end of file
diff --git a/jstests/libs/server_SAN.pem b/jstests/libs/server_SAN.pem
index 4160518e22a..0a5bd3d486e 100644
--- a/jstests/libs/server_SAN.pem
+++ b/jstests/libs/server_SAN.pem
@@ -3,53 +3,53 @@
#
# General purpose server certificate with good SANs.
-----BEGIN CERTIFICATE-----
-MIIDvjCCAqagAwIBAgIEOiXn4jANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDvjCCAqagAwIBAgIEZTmmVTANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTM4WhcNMjYwNDE4MTYxMTM4WjB9MQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ3WhcNMjYwOTA3MTYxNDQ3WjB9MQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEgMB4GA1UEAwwX
S2VybmVsIENsaWVudCBQZWVyIFJvbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
-ggEKAoIBAQCMI+JgtT4NAyjzo5nmlI+lA5F9RGaMq37YVb02B5IOd2xTVXJPIT+0
-IT4WEzn/GIcazWa41rxf+eDwFryBY6Jvj7ttjOKgkz+UG+u5IzCX/sHJFF9ersUP
-eVwZRNvVmzsCudeS12TShYlrus4j/vAz3biMl0uZwUhfoN1ABLRTav0SanW+iWe3
-Z/QLway0BxT8f6/hVEk5BBzep9cDVxzfXnr7zjzlL2WoKshMHKFzu1rHtk/ydjU7
-8477y/ddfoIkUFot/PCNGjRw9HSZqasOf3WTkv5EUx/5BZ28TMESVLqCVywLG5qd
-4cGZEEf0SoYclk/c5NZyUPAcoLK3Oy8LAgMBAAGjTzBNMB0GA1UdJQQWMBQGCCsG
+ggEKAoIBAQCrWauGW6U0CBNnbCVxE819Cm49Yj5Myia4pgCmbzUNemS2dlC4q2XI
+SFrhLY2aoLBxfNha22zVOonDnV6saqr/863VTcndhpoV2l18rMrTGCam5leE/+gy
+8jIl7K9XQUcI4d3Pf89kVMWEOvw046xePhge2RKtJ/yQjKiGgMdPKCwv6Bxz1K1o
+rcEpCyAPzYyykXZ7wX5owq14FfsE0Dqv2n9G4Ez79m0R/YbbrkmmN/89NcQsbxzG
+GrPF/ax8TvPGzR6saMcuOc6Kk66APEkb6IwVnvrEQURV+H9x+cmM+fible3Js3+X
+TVakhPsJhO2X82zm5sKbJU+MGqFxvGoJAgMBAAGjTzBNMB0GA1UdJQQWMBQGCCsG
AQUFBwMBBggrBgEFBQcDAjAsBgNVHREEJTAjgglsb2NhbGhvc3SHBH8AAAGHEAAA
-AAAAAAAAAAAAAAAAAAEwDQYJKoZIhvcNAQELBQADggEBAEfMfi42U1cYFZt8mNef
-73EIGd7dRDuROS3245x1vioWqXTzOds4s8xV1pKSqIFMrscx4q1ScPLHgZ7NAvEL
-1zyi9d+OJmcOg89iHZ0eetKWt0pGvcbkwUk4YM+ez2umBRZKIzNL54IlrX6+SjvN
-L8Ch58jGHaZM6muZVDF33p2QdtSwXCcrokKgPtKsv7XKvm4FqEsAALN1NR/K1pQx
-EJyXeUAeFAF/+NiaVQKEbHGIXQXYpNxSu4wZ7VLfd4u3+HSx4mYnjD2FYINuNFhX
-AGdgYAJMCIqIluJZK07+r6XN46DEwnuOGBebRAljk/RXQgOOt3txsPqMSDmXtzyI
-IA0=
+AAAAAAAAAAAAAAAAAAEwDQYJKoZIhvcNAQELBQADggEBAH5MPqj9Sav1YamZPUQ5
+XcyihWiS+otcmcnPcWjeGpNphzWv2iUCgrh9sgYIiypYs0U/EasesBQPyaGaHhrv
+Bx7hZ/UpmaqMpMWss3gVG26wmVgPN75NJfkJRDsAF/fCmWUgAGVc0IQNidU5SFnp
+8MnmCnyEXMcyNtc+BaguH2QnQjkQjp8aYIaxeBzy6avViIfpycFhJDpgo+WcT12B
+jGhBruCpoI8OEtl6jWze/QwYDuPHkjnhgnoYdomvBWENC1UWL+AH30YTDkLip0Am
+NvXJj5jZzboWpAmoQx7Ahvi0FkXHlHxKmOrXqjFgjhnVVAETn4AAY/ShArmD3MpS
+GVM=
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCMI+JgtT4NAyjz
-o5nmlI+lA5F9RGaMq37YVb02B5IOd2xTVXJPIT+0IT4WEzn/GIcazWa41rxf+eDw
-FryBY6Jvj7ttjOKgkz+UG+u5IzCX/sHJFF9ersUPeVwZRNvVmzsCudeS12TShYlr
-us4j/vAz3biMl0uZwUhfoN1ABLRTav0SanW+iWe3Z/QLway0BxT8f6/hVEk5BBze
-p9cDVxzfXnr7zjzlL2WoKshMHKFzu1rHtk/ydjU78477y/ddfoIkUFot/PCNGjRw
-9HSZqasOf3WTkv5EUx/5BZ28TMESVLqCVywLG5qd4cGZEEf0SoYclk/c5NZyUPAc
-oLK3Oy8LAgMBAAECggEAN+bGkjoqFum4R7vuk8aWKEZsnlIPMDTmw+grsmZBsmib
-+v/+OadzMGkESa0AuQvxNNVTkQ8DlKtqOYtwRZLXhHYK12/YJSKnvW6H0NHDPBZg
-+dOZGX1Q2VPZU7Eemi4yU2uLnSUzsDCZeTJKsZwr+ByNVfOyMhKiSpcyOqvFvPI8
-6bQtu7bFb8bbm8JEyYFUQChk4Nt5pRgnPweOBGw8KnLirsIQHsBEzarYacDU/BiO
-or4la0+1vHKxGHmBM6BGyi2l/dgwYtuG3SONu/aAsU75ziwMsUgXM9GioBanWBkJ
-BgExhtztPKcIYKD8x3+EP/CdBnVypq+i35n4ON+ptQKBgQC2WVPyBndy0qY42qEc
-K/Yp4eoluvQiLJALrPRVfMET7NBRYojgIYV5h8FEmExLWY+7BuhxvsR3LWOqL6bb
-aT2R6APQVrXLW7waiKni70Kj2jBFAL4VaUZb0m1LdmeNk+6ZK0Rc2glJM0d4xUiS
-DeXVMij7FZNoOBvkXIRLpCdAdwKBgQDEvjfjTzUQ61CZizWfc9uwVtr/VEY/Gmtg
-vdkoWIZP77DF0lqUN1BnYp4g8blxrvd/EpuaAKoW0Hz9KhaSDhnkR4RR1Tg/qBUs
-pglBH07FSH6xJHyLJezhzaREzSB0xJo5nYS62iYm18MBmFxTuv/7lXbEPaaVvl5f
-3tTdiSWfDQKBgCGx0+8u/rd68TgkPg0EmpIWqruaFi6SaXOe2+9IBC14Xu4K9Rvl
-VdKlITNZqQ9rV0HJ/v21sHwNKRNzhrOYeMYTR1EiFKmlI9cLVckXSQsZ8D1v66/t
-KhEhiwycrnnc0gP/mLxHlduu3BAW9Ff4tXV1tVjgHcLuS0khR1jq1k31AoGAZrX/
-q1XgmFKhI2e/uNzdZjQR5JZ0jeEXCcxTIHMGu5igqsXkr9goy7B6aSyI6ca0QszO
-GxoZsgtqFSjx25ItBjYn6CjuUp1HYKXV0v+rOedc7NHliydjgYbAKYMFXLB+63FG
-p93XaRPfJGgMW1IW7ZrcBBtDao2V62sDqhw9XckCgYAOVTA10LJH0BSojbeITBkX
-tkyNMfFAqRWoy08/dl8W7aUFESzgLpCB9LY+CS9e1vfQl9K6etow0hCVz7O5kkCG
-YV0eovIb5zQ6Wt4/MLgRph9TWrGGMejILb/VmXFkQ49eLRq3AJ303PvkoktBEOoN
-Z4SDWd/tZlW7O/i6n7DR1A==
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCrWauGW6U0CBNn
+bCVxE819Cm49Yj5Myia4pgCmbzUNemS2dlC4q2XISFrhLY2aoLBxfNha22zVOonD
+nV6saqr/863VTcndhpoV2l18rMrTGCam5leE/+gy8jIl7K9XQUcI4d3Pf89kVMWE
+Ovw046xePhge2RKtJ/yQjKiGgMdPKCwv6Bxz1K1orcEpCyAPzYyykXZ7wX5owq14
+FfsE0Dqv2n9G4Ez79m0R/YbbrkmmN/89NcQsbxzGGrPF/ax8TvPGzR6saMcuOc6K
+k66APEkb6IwVnvrEQURV+H9x+cmM+fible3Js3+XTVakhPsJhO2X82zm5sKbJU+M
+GqFxvGoJAgMBAAECggEAEhG3q8h4SF9dpHdcD2uWLMxvyZtVlIVwxeIDiYmKn6w7
+eJ5Lbt3sMs2mf75tA1RUpvMSYapn9KhipLUwqZ/p/mm0+Bxm4Cx0jT9kwmP6U35l
+fQ4nRogx9UVjEmq+JsZkdkRTPrFsrljeJ06NEAq+P4Xuxzn+5TGlSZz7nItx+R/I
+LAW+NMi9gKRmOmieQn+mz5VGsQfydCqk7GyUBJbpGMsh9vYvhXYLCTnpkWO2S+pM
+fIUf/UQhc+DFr9tml+lln6cuoUXnNesiEFlzdLdcWqpq/K9RfWaIlZ+DaXSHlqn4
+Sb4tLCjIO9RDxbkIzttfFUMxtp6B2y32q3oUTSznMQKBgQDZ6F+z0jJcyJKM0a7h
+8q8E3OzETV4/6km8n+t7LRPhLDRW1ptypqu4WUKD7rlAVnn5P9FiFlj84kHRo8a0
+v8uUlIDdnu9aoAnS9b7q7O8dbRLk1eU6dUfOJYldMINlXmo1TEvRGeTm66Q2BR/a
+WvurpNVmRKkpyeE+8UYEwfB3dQKBgQDJTcvRQbI7iLx0boR7owfi4EVzKSQbHUUB
+B4ZPpPQJN6Eqi+Wi0dgwgd9lCixaMFhmttc7lbFqraVWIItoXuhK5ThHHFh5tkqn
+ZzZ9MEs96CXJ9C9ROpAwD+hC2qwG8GI9VohYrth43ZNJhJVfzllTtOAz+wXnlMhG
+VkY6szvpxQKBgQChOwGMwMtIwZNFpGQchH8hPwHk4UYKTqUObtlCg4EBC78SPao4
+8799IHZJvhnN0+5eEO0xAU4IlrSSk/aTiJHuNs7+q/l3+ZArSm9fzb3C7RCcxvLc
+BSkDC90OWbXvDCPTmcdDSUCH5/TRj4sY+lbakpTfHZB4/gmuk8D2BjWRfQKBgGH7
++CWXMMZBvFmAIgR8Sq5oM+XmNKjuClSB8SJ7TD3gUhZ/mfsy4WRbEv3/ga80sRLu
+FL3wEze15jCSDslyyOcLw+T5KyezT4tEdgVhqH4trZcrwIxtURnT5F4GSo3mHCt3
+H07rbHsIf1TdsEe+DUTtWeRzX2Blz0ZNYEnaTGNxAoGAGFmYd4J0mGN3FjuIC2/8
+tikQiT4SWSgXlk1oJ/xmxRLOIqRfCwCx1jviKX1pq1H9yOiJvHDSTe/5gqGxPrto
+ZCejf15QJs8ZUUX+/YhgVAqDhtPA2mKSsnJW7orMRQHlKXVx4bKOBu9w7W5t4bFp
+F5g7vOpXijL5LMMSuuzc8JM=
-----END PRIVATE KEY-----
diff --git a/jstests/libs/server_SAN.pem.digest.sha1 b/jstests/libs/server_SAN.pem.digest.sha1
index 31795b29fa0..4f617b9aba8 100644
--- a/jstests/libs/server_SAN.pem.digest.sha1
+++ b/jstests/libs/server_SAN.pem.digest.sha1
@@ -1 +1 @@
-3EC495706A98C2E80FA65B63D2E739C1D67755E8 \ No newline at end of file
+C7D07A53FA64674BA20ED16BCC91DE34F594E1F6 \ No newline at end of file
diff --git a/jstests/libs/server_SAN.pem.digest.sha256 b/jstests/libs/server_SAN.pem.digest.sha256
index 1d3eb29259d..4b024cbe675 100644
--- a/jstests/libs/server_SAN.pem.digest.sha256
+++ b/jstests/libs/server_SAN.pem.digest.sha256
@@ -1 +1 @@
-0C9EB019F19FA712311F20E080678C01D8ACAFA71985497FC40CE69B1B9D6A4C \ No newline at end of file
+92ADC294F6236335B1632008E281F64EC96902B6741F0476D6FE1362F2A1EA10 \ No newline at end of file
diff --git a/jstests/libs/server_SAN2.pem b/jstests/libs/server_SAN2.pem
index 725254d5f52..9382eafe345 100644
--- a/jstests/libs/server_SAN2.pem
+++ b/jstests/libs/server_SAN2.pem
@@ -3,52 +3,52 @@
#
# General purpose server certificate with bad SANs.
-----BEGIN CERTIFICATE-----
-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
+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
-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
+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
-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
+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
-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
+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
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCnhbaj4uAvXhnV
-4MZLq0h7+fNC9bJCJgohtUazT4L4DJaBH6kvJ8CHUfNAVoMrf4MOQyHExg61Ys11
-/iYptzMKbAXtrJsgv9roN5vI7r0RxNQobUVlSSAMStuVlx0gHuiA11xcS29Glld3
-UkOkFqD7ZYg0TLu4UMftU7hfK7iogDKBqWxM1SpxZOMihJo6hohYcR7cuSdeI6na
-5EaKP/LXWd7PzLcuLoKslTaAx0RqUMIUmu1pUksDtInq1GWzNRdAAEFJzk60JBDL
-ZzRV7unV/zrtd1o9yVhFum+O6f+P1rVn/axdiUg9sduNeHDl5X2iLm3Jg8AWl785
-tjaJ23+nAgMBAAECggEACCjDFIhgUu5KY9hm0Bivlxo9du1wmTgxFiM2JlWhE2PJ
-kNBx9RIClpSvPFr6WIwFXhR2+JaM8Ni3GSAfy7hYjBFm2ISnqZiumNDcjZTTMKJd
-kvp/fsdpADBFMawChyX6PQxAO16RNObtq6oeEUfo31W6pJF4Myn8EtsZB8mhXNON
-YKvzGyDYOV/8bJpi5iKb/y3HZJ+uei0qF9rCBBDp76CmzM9uInaFNvX1dMTqPojz
-gFTcVxK5M9j65zXDKmZDvQuEbJ1y+mUEzBEPdIzzAgzAq+ZHPwFDE8QnogoTEpT9
-DYIJbwa+65enR+FCZfIVDCn3Ua+6TDCx0sc1Z1m6QQKBgQC9If4p3GqzaLLmFkCN
-EF7o7jofGakJh1jgm7jXe8im5fTV6wkdIHsB0REeRryF3w/X2tMmSZRaak7CTesN
-5Dv9HU+ScflTtm4ba1NJhT/WswF6kP+yjQYaZ0W0+2LSvoA5kMl3IYtID1RlxLhZ
-G7RFVgjb0NqlOyWCQ+zhccvycwKBgQDiv82aaa7ZBXhrrWdhLEeILHp7ZhrGbo9q
-h0gn7srdiywO3yGubtoGg1yaQOjRg/CNFxrPynvVH/WZZvagS/icHZ31aK8ojraq
-OHhd2pinbW+9GdMm8ipfeICljFVckIfqo06ZPULRKBA8uAZ8ldzuAxVAMdb7Grmd
-kFSLvvKM/QKBgGccLiWCPkWbMdUQkpaVMzkID3W/FpHUURb6rpYDrQuYWJd7MJfJ
-imYeJZf89nCBgHCsouq/uHpmdJOnyRrkr/O5VBVBv6zsyzB1nY16cKhLJOY+QLiF
-+6rPXIhjeKfuJZe8oKkrB3T8roVg7yPdX7VhRykXvuvPyA4xm+X4lTiTAoGBAJUo
-hPCJiro6Lf/vHq0+eoOqdpvMC9ryiacS/LVAEPTxgvb5cueTBhr4uKbEAiMovsmh
-JEMCOLl2/5F8uMmzkAPqO6lexrJQRvrskMl0bazdgX6MiWj6LkOFOmMsUE7GyJHi
-AWcudFCwIRZAHAxCbQWow4bqAjhGWUm70tHmtxllAoGBAKzE7Xb8OlgnVmBzjrnE
-5qx9f/eumD22p7l/wO7BCb/bY/n+TxCEKxaVQC6eHzlR/n+QV+DBXUrO4jJle2Y6
-oHw4tH8xu8KY+atH3FkEpOqMNR+SS6gBmyLivbFYjlBjE/Yjr7y9i27EaVt8SDY6
-Ezw0YFUJGDe74m0dlia5INC7
+MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQC/GmCSky8jCC7q
+AZMXzdpwG/jxNuR3cQFWaDMXPzfgwxsTOF9Yb5ne7+FSFjpTfXs7yo7ba+OKr/q/
+HroigTFOjBGukSb6zS3TkIBlnUTmszic+dv7WTdQy+NcJ8swAc6IMkrb17yF0CdF
+oZR+x9kg/uz/dcqbOU4/WCXo2Oz5SxgGQXSDK4oeE/NZm17bOhS7zLChYV1JITze
+C3tQxsZjsbA+TbYoH116zMlQg5ahDL0155JrRKXL8Wy/rg+nIHzCUnXo2Jeww6W+
+7UBp/2XmqIBXywIh+mSvFpAjNH4gczYNvejUyP0k8Tm1BiAIpc2BHFhhh25YIq+g
++VBSg07DAgMBAAECggEBALDhBi/EoWVoZpva9z2aICuSCHmjGBXhd551dYx3zA1y
+KLZCgCWHrkDlgIUM49FxHEX8NvuqwYIVXh3Vn+zd7ThJdvg/i3epv1fJsL3csfBi
+Q+0vasgbDJLxFDCw+GUn1vTCr/0Jkom8Xw0ZACvUaAkdS1krumqvwNfqi7QYTEZz
++LHt/bEyifJ9eW/4QL2cf02HgssBGait+Dm+2LSLhjTcxOzqziUeB90iAZc/JnTx
+3QWYBPj+gOOLBrel8dcPQEAUXV1Si8TSFfOrrMXfQVVwwHzTREsD+n+wmFLr15zu
+jyhn0kxttif4l1wEizdAcLm4ZMUFCpvPXxqi1NdBWNkCgYEA/ZWI5XYYM0x5NFmg
+YDzfrOj/Iw+g5bHZb0cuuetZEPFYGN/R6QKVo0oi+byoioj7ZVczJFsomTVj9Xji
+DS+AmlCQo9uI59w16jzC4RyW7ZuiBBTh5B+KKawtwbqhe+p/VxANsTudqoNTdFIV
+Vm2e5Y9vt5DIsQfK//iwMUN6zB8CgYEAwOx1J054+NyfNzjc9s2ZOsEuALBakJwh
+lZZCLis9+3fu/K/93NrfGIwTa9AAHH1R9eoe3jnkk+7wYWqs24FdWZlr1pPWn16Y
+s7bt8JJa8E6yV1GLIV4hyzd27fQCLHUA3XJMx4beskCWj7Sr7HZGElHMxsZ/u1bg
+KtCEpZbb6N0CgYEAsUXzMK5RFrOUW8N4OS71ExTDH8iSK2EcZw11HeXoGs8NTj5R
+qTn0T/XI45s+m7JNRLgj+Xt8szY+zeEW7i7SEY7WvqX/XE92pWyas/JflHXjWkUa
+8XYXCTDjv/XvZAg3wy5m1AqgGw65raygXA5AMa0HZWVi11diU3WP/rB0zPMCgYEA
+p/p6+1GJZW57txJs2vwjahQgIPtsr7MyTtP5JcgC/PztetkmGnH8hJwaoOoH3saD
+YbKLVAVmcCRA6yF+BtY52LUMP1aULkmoffpObQSR5+EtyXe3w8L5e778b63hYqIx
+sZ8/GQ/mwaAZOGEgvRAybOsKeR0GxLCdGMpcZO3Y5oUCgYEAta9bVRkclNjC92i4
+4bxXhvKGw4K0qbBmT6EPmxco2Po6o0ouocR3pdDZIXczSMVoTgLqsY+Sw3gkuy1t
+MA/KzpeRbh38alx+cutozJSVNJdPkkiZZ/KHk2lMkJSdEOk3lmRyzCGXQi7i62Ch
+yDwPt1MQjAPpmxbQntd5fLZN8CM=
-----END PRIVATE KEY-----
diff --git a/jstests/libs/server_SAN2.pem.digest.sha1 b/jstests/libs/server_SAN2.pem.digest.sha1
index 927027d941d..bb9f32db170 100644
--- a/jstests/libs/server_SAN2.pem.digest.sha1
+++ b/jstests/libs/server_SAN2.pem.digest.sha1
@@ -1 +1 @@
-11FD267CBF6EF77BEE7181C18AA02913C3A98743 \ No newline at end of file
+5E64034DADF227E3D024D3B5F3371A2438BF7860 \ No newline at end of file
diff --git a/jstests/libs/server_SAN2.pem.digest.sha256 b/jstests/libs/server_SAN2.pem.digest.sha256
index 7e2ba33033c..0a6e1645e45 100644
--- a/jstests/libs/server_SAN2.pem.digest.sha256
+++ b/jstests/libs/server_SAN2.pem.digest.sha256
@@ -1 +1 @@
-DA3F00FC20B32CB2E3E171C3DEE566B80AE402B3DD3A0075AF5D8615864C6853 \ No newline at end of file
+B0BB86772F59D090AF9D01ABF1F659C1410CD202F36D8F1417D22172E9DDC900 \ No newline at end of file
diff --git a/jstests/libs/server_no_SAN.pem b/jstests/libs/server_no_SAN.pem
index da4f5addc4a..65ef2625f55 100644
--- a/jstests/libs/server_no_SAN.pem
+++ b/jstests/libs/server_no_SAN.pem
@@ -3,52 +3,52 @@
#
# General purpose server certificate with missing SAN.
-----BEGIN CERTIFICATE-----
-MIIDmzCCAoOgAwIBAgIEK6jRwjANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDmzCCAoOgAwIBAgIEJwjKgzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTM4WhcNMjYwNDE4MTYxMTM4WjCBkTELMAkG
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ3WhcNMjYwOTA3MTYxNDQ3WjCBkTELMAkG
A1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMRYwFAYDVQQHDA1OZXcgWW9yayBD
aXR5MRAwDgYDVQQKDAdNb25nb0RCMQ8wDQYDVQQLDAZLZXJuZWwxEjAQBgNVBAMM
CWxvY2FsaG9zdDEgMB4GA1UEDAwXU2VydmVyIG5vIFNBTiBhdHRyaWJ1dGUwggEi
-MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaH4zX1wEQz4Sr00e/mC32JmyR
-1Win81nCp0/AlDjjO1SGR94lelDPlrjgQq1m0riNz+0TDyLj0iPw9SxdkxeW3Wj1
-y++Ak3oGaiMt5PlIs9MPH6YaPs5+q0fqDNINuWipVgihMd2FXRdcNE2Fb5+VPb7s
-wIHsCEULAzGC4bw2F5/TnesXGB4B1iXiuMSaHgFXigXYtuDm09rbZcfzaRcApddt
-TP2Fk6BgO0Yba6oC3QlWAFjCRmPfrRBer6BdZOnpe6oC0k+F5xDAEEiCZtCZ2NzW
-qg0336AjtShV3/T0iOjyp7WqK2Tf3jTl8IZk/6N1aikJnq+hG2mRRdJufdntAgMB
-AAGjFzAVMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4IBAQDS
-TjSMagylDzQ6+UtlasmrbSgMFdcJlgpQXydT5+uCiCqMFzkRDO8fT/YBVyIyXmQw
-VmFFCndrz6xeTodR/0LBdQ1EWZ3R+SPlXqupvRjXiqPWeL9NrXjDIBsksdTV8yVK
-Of0cLkmD+qmidKzc/cIXp2ncCpN1PB4j2N80rl02pxg01SoDHqK1rVhlIW3yFn2m
-05IPxp2j5BHqzI0HrJnMEZHdXlRU21leO012h3DMvD/7ytJ9yn44aUCfwVZUzJlS
-+qrYuWRlmhBRfHOC/thxDjDJ0kPKj736eQMjOopIy9Sba+lMfwmgZdPefM2Uj8rF
-fX36rG7SkCjlO31NhXv3
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD3JS4s/3sH7DXEsxq1A7OiHshW
+Ez8O+2wNzbgtMDRYbMnLZu3ryqjCm7FDeNQyqmKdW3y1sl/G7WwbcVUFVMrwKNwy
+XBeDupcdKDKIHDqQyncd63uAo2ShJ/hprQ68s8CIZnmF7x4HLnCUQrtDeh8/rM7p
+5Pt1ypn6YceE+cpjPC63L5PvAdYk8ZZ0P22a184ryO06nURyw4n91EQgTvBqposc
+cJGPLj+E46pmI6cjNJSGgO3esK1tAYQi3d19Ndv68wZ0xPG/SR1xkLKv9Uqgc6cf
+qQ1eyAgu9uowMIpwgGJdAGnW4cXV2z+ImjOr7L0lJCtnPg7N8OZutdaebUjRAgMB
+AAGjFzAVMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4IBAQAO
+l3H15vmuTVzom9w5CyRfnMuhwuGmue54PhcGPMBzpG/voHLkDkhJzM/JyCQ7Zva9
+arVB3xADiU6T5Ip1254jRFXet7yHxZxuP2TJ4Abq86iXVO0sZHDzazEOG4bfIb8k
+EkbYNmlEDUjGl0FuYgMd+iXpOyLWsV8POaOXi19ljB3ENaB0PNugIJNOsUNrRAK6
+CWNx0gWQx8UQFDopSWbpdNd8yk2ohv4868fqtZjALHITZgEAWZcD/Iie2E5Vl9Ey
+MWpyBlK9HwbG6KXNNUQTMtmOj0qOXFGuxtYCruXp3bjcTLNqwFig1mMNTcqdOBLq
++0+0UxmOeLFpEwzVBjVF
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCaH4zX1wEQz4Sr
-00e/mC32JmyR1Win81nCp0/AlDjjO1SGR94lelDPlrjgQq1m0riNz+0TDyLj0iPw
-9SxdkxeW3Wj1y++Ak3oGaiMt5PlIs9MPH6YaPs5+q0fqDNINuWipVgihMd2FXRdc
-NE2Fb5+VPb7swIHsCEULAzGC4bw2F5/TnesXGB4B1iXiuMSaHgFXigXYtuDm09rb
-ZcfzaRcApddtTP2Fk6BgO0Yba6oC3QlWAFjCRmPfrRBer6BdZOnpe6oC0k+F5xDA
-EEiCZtCZ2NzWqg0336AjtShV3/T0iOjyp7WqK2Tf3jTl8IZk/6N1aikJnq+hG2mR
-RdJufdntAgMBAAECggEAOIFjtkh19A9ZEVQDZJurEilxOaBX3+eI26RSyYSuPKUm
-bprPt8bZ9NnKCzJ295E/J4L5ZLjybjs/gRqqOt5wUhf34NH1i5rGLK7iGfPubzi6
-oztTvyCSvX8XfRhZNL3qwNaxkEPDdx8zrtLgLxFHHUTHiG5l078ObSStFNKlGeFK
-LZCQDEGGpH4+tc5AzKaUKRbDvpeG632F/1+qzh2xza2n3xUcia927H6W1GWA+PWy
-w+hVUocAPy1D2ELynUjoLn8HbxCO5SMMGGrJlMO73QJzKInzoCPy7nRVBBXnb/18
-hEkgBGm0RTcHRezuZ/a14iYhG2hvOMo4ph2qz50cYwKBgQDZpwNZHMYW2miFiN/S
-oiasW2VtJGyHAfwnkGxfvU1hBieVIxNxfXOFVaYyTd7i1CaVCwhhee5IYKV5Wnbv
-LP0Db7k9KaVGSA0RTxQuGN2jAMbo/Uzz8ViM/9vk/Xlt73BK9fW5hpbXRRMfuf1N
-YvG5oaZekPq8Z82txec4+DAkHwKBgQC1Rx7Do+KltqWLTBZs9ZombFRyi/4MkwcQ
-nG0C6TyANPBMZKXlb3qdNREc9IwInKTCmL6/wiR6cmSxk+jhg+Y4TC1tvKuFW9AA
-X73lqrNTZxYzrhhA0YvUyopK47lwrxgcaPWCeFFzDJ30s+S6pbNEUoVQ1ZAWu5ZD
-sveq4m5gcwKBgAUO14oTnBrd2n3371OixwlMWnAN36PHjQeSWKJk8M5naTYTCZmi
-k7OuiN00aBCXY4olJn21aq8t58qJKqhmQD77Mq/ULu4SMJONZeeoVkY6d2TktgwZ
-OLiWHZMVvOOsI8zqKFq2YP0Bsu8S0Gsi+IEa25XpApqsQuBd8ACn6957AoGABMbm
-AaPM8i74982+fYqPUFnkc8xKmow5UG++06fPx1Udy/WPBZfFdGUUmV28XvG5ycL6
-q9Ty3yMqkh9isKaoJ22ieNTS9EWyGoBrYaT46sa5qAz7aKHc/HOF52lO1rBWg1Ek
-vxZqlwyLEQq4iU6ahb9i8flevaqd0BTkP+WNoQ8CgYAn4Kh1I3pFYTi0jllARuZ+
-6UhSyvO07rjSckbVnbONbCcFRTcJcZfqKRs2HvgaAmzGKESzI5ozRUEYZoWRaI1b
-gyxfNh0+WI+Iytq5AGrK1HVItpCpHHjkWmbm5Fe1oPTbBdazYha9l7aSNfyrdwKM
-rSXLWmGw+2gZ1/Q9sRa3nA==
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQD3JS4s/3sH7DXE
+sxq1A7OiHshWEz8O+2wNzbgtMDRYbMnLZu3ryqjCm7FDeNQyqmKdW3y1sl/G7Wwb
+cVUFVMrwKNwyXBeDupcdKDKIHDqQyncd63uAo2ShJ/hprQ68s8CIZnmF7x4HLnCU
+QrtDeh8/rM7p5Pt1ypn6YceE+cpjPC63L5PvAdYk8ZZ0P22a184ryO06nURyw4n9
+1EQgTvBqposccJGPLj+E46pmI6cjNJSGgO3esK1tAYQi3d19Ndv68wZ0xPG/SR1x
+kLKv9Uqgc6cfqQ1eyAgu9uowMIpwgGJdAGnW4cXV2z+ImjOr7L0lJCtnPg7N8OZu
+tdaebUjRAgMBAAECggEBAI0XVsMtnuko+pEuxqJsWJLHDAvHtQoykr9WoDx79oY8
+pP9P5afk7G8dPxeL1WiPSPkYj5uTF4aTaFJKYwVGIQz15q+BT5NOZJKqrh5yLyUV
+0Obt1nXb0ckG7pQ1zeIApHu6NMo3dmcXJgIeDpY5E7ngR8fTh5L5dOoyBBtwFxCK
+3c7kF3PlMOHGG8z1LE3uB0erxMLF3ahE5mNpzaogeQqh31TWJ+Xpcfk4Tq2rsgMU
+Jzvcdu4uaxM4//SCX8da6y6YgWZzb1+WS3aAHQXDGp5hY/mPdF4xklYgJIiGHH3L
+OIlF87RvZ1yATfyvx+A69P4+GZp5Itu0tMXtXVlUVrkCgYEA/xDUnxwOcAnJBP2a
+LQR85YqxiUSCIrAPL5W2ADbem4Ja4ZUUrsIBvA5Mn0WcUbNzR2UqpaWR/X2XvI+O
+lf4g9aawSWplq8l1ctoek4vHnhc7UNCAPrTOZry+OjH2li/htgHtJV1MAOaz3ktA
+1u1ZMsYAv0Ju7WGi9dN407hjdtMCgYEA+AzsRaHi/E2NcPD3bx8arZTuomopanBt
+nMMCw+tQCpsC/yKvGQGTwHcUq3wXLQwymEzexKBgIfVvGEqPOdrHNTmQXzKnfR3J
+2OUtiX/yf6dXDpFCr4GbCctRwNycwDXIktgU8aqDlWvn7yS0WR4vjTW4jz280zIJ
+tGApE+BnA0sCgYEA/H5AvLEdabOGFzalJONIcEJ3tRbobEY1AjoFzPiELRVBugXG
+T6kl5m+RUimqsQYfnBF9wjTA7FsjljnWQI0tO4AjCsoUk5X+eg+KLS02Ej2VLk74
+ZRq/J9y3wwwquknz+iS2CULuNgYrEGcWbKzQm/5+RtcQ0FTS6N7KwWvKqpkCgYEA
+2F39YqfZZRcIv3GRg55wGOWGWqmbwrqbAligeuExim64aHCKp5dWmFXG8+ZkGOlA
+4NR8pKr37+c0ps2yrVaG2YiCxGdc7agkP0t5My0mC++d4pkWwByfbiWqBD7rhEXl
+1SEi88I20Qm04Eb2AZ5xAA3SFTBXGynUiUAv1KSzdo0CgYAL1kuzo/OffINJKq61
+0rSexvnxqsGIAoFVMD32Jwo6DT4gH0U/TMheTw4Q9uiCCC8ch9yF59mTDuB5EU8p
+C2bNDNEGkZ9qfddAnKWumMAqgZl3lwG1UcbmUOEfnyfOpt8WttC8Adcbg4KzM5ko
+yzsyM5hlkGOp5kKOar1BwAOr8w==
-----END PRIVATE KEY-----
diff --git a/jstests/libs/server_no_SAN.pem.digest.sha1 b/jstests/libs/server_no_SAN.pem.digest.sha1
index 5f8e0c2274d..6edaaf023b8 100644
--- a/jstests/libs/server_no_SAN.pem.digest.sha1
+++ b/jstests/libs/server_no_SAN.pem.digest.sha1
@@ -1 +1 @@
-1F2B144A15769545398C19079ACBC396E4AD5328 \ No newline at end of file
+428F46219AD6896ECAB65CBF80BFF2A8EE08B648 \ No newline at end of file
diff --git a/jstests/libs/server_no_SAN.pem.digest.sha256 b/jstests/libs/server_no_SAN.pem.digest.sha256
index 6ef321fbd5a..f8cca76f1b2 100644
--- a/jstests/libs/server_no_SAN.pem.digest.sha256
+++ b/jstests/libs/server_no_SAN.pem.digest.sha256
@@ -1 +1 @@
-D80721E41714C25094CD064CC352CD8D82D836E3D913392ACA370E53E29450B2 \ No newline at end of file
+AF8E43015171A764500396734763BECEBFE4FD022961707487E750BCE9354372 \ No newline at end of file
diff --git a/jstests/libs/server_no_subject.pem b/jstests/libs/server_no_subject.pem
index 588ab3f552e..952e76bc5d4 100644
--- a/jstests/libs/server_no_subject.pem
+++ b/jstests/libs/server_no_subject.pem
@@ -3,54 +3,54 @@
#
# Server certificate with empty Subject, but critical SAN.
-----BEGIN CERTIFICATE-----
-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
+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
-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
+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
-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
+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
-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
+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
-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
+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
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCxqmehD3CKeKLT
-FLfcqrC1rCPnjSbDNdJNLTb27uYjEXxQrfNHW2r7VzOtSltY17JeRjoLhomFvBi+
-mqldGrE0wjK2s7N6URLk3Gnq1dabfB15EMng2lTRZswogsOidTDTTpbIsaXU29h2
-yNRz+UI3hD9q6YVTx5FeGNh6W5Ao4VBa87TmMF397qtk/2hgynvN+23ikqOdSM1r
-OcrAxZB/0iOLG3dzBFP6XMbwJyjnTt4GEDU7UhY+lkXgx7x+Nd6nn4TE3sqimzf2
-bX8U9/Kd7ZjhrVcE5lvfuCo4QE0Bk35j41ZispACYIChTfiPMOcDZEULAoXtPY76
-gukATBGvAgMBAAECggEAG9p1zavQfn0ENeh5HMjL1GeM53fbHF6bPks440S34saS
-gUmMKuM7pfTZXrEaGhcS2THUVss8UzGWhYdUxwpwvq81aSxKFoKQXj3qAw2MTCsM
-qdbGd5BzHLMrjaxWhGkwAui+ve8P6wueZ5z7pcTtqyt6D8ZVhzlx4lkt0xz4wFez
-OVOHBvJaF3CtNfBpiq5AuegGNS8XWI79mS98Sa3rpeLhKNaSnTEm7lQ6rXOhDHCu
-dhmR+iMpyJ5uEZR5LKWulaXfcESHGQ8mRynWaTQImBcWQJLg4ooTQ8cuOejkJvyH
-VCi9sCMDDoBvP2uFeMnUDmfXJrVX597CsmO4Tp9CoQKBgQC9Hkfg0QCOhOnSRC3z
-rUHjJvj9iFjopIxj2y9BQViHBN7EtrHAjaVnEV/dB9mDCBcv3pV/k5eT5awdjJj4
-/uYRp9zZqQYxlY4vO6iGMIXL+PTiLkj8l1bDpv4VzDoIuouJ7Y98JaG0Y9XPWLRF
-v/uU5bM7taEF0sHFT5yVyDas4QKBgQDwf0P7Y3N7QvtWw7dehhEgSpojLqb/vHfW
-5wIw3gO4nrq8L00JiTMetI+B1B0ZV/rZppAZHWqBdK2k69usu8Yr0kPH/tUJyBCN
-I104TX5NdeaNxaooFk5OlfoAdkMV0xRntO1p+Ee0rNgDZehMgkKRSOk4gscuExEe
-1uDtBHGAjwKBgQCZKa4C+KHfyutnvIoOwPIMmuKqysNe3u1IbhqOWfLtntcgL+oz
-zUP4/kxKQXI6udG1liozoX/wauEDKXw2pJIGGJI3wblfbQUzYbixvRiPQnhpuhyo
-XZUKbfN4CeeybApY0YoUfJHC+9wMyoVtu/dv9rw7DnVztuXx+/EQKY+GYQKBgGca
-KErdl+SAEsBfp30efLkbQnlSxsVcRwQahRXuGCpN4kBLBvvPldrUDbHa/Z6f2Sr1
-/VDHC6H0I31QoBytY4fl3Kkg1rQa0P2w64X3su4CXZTp6MjGx0tpgIQyLxBsLZNI
-PX/wsM0ETJcoWS5zqZYfa9yONFXMVsqh1EvIW+CBAoGAUYELSK/Ee0W/qBRAXR9O
-UAcbXPt8aoKRJRqLf04y29q/4ym6lI1DikH6x0KFWu4GzF/r/f23sJjJA8yw2sKz
-JFOyKL51hg3bQsAbOmqNe+nREO9OjpsjTQrT35fxQFdn7F6bEHrMCTYkirIiEwnT
-GxWKiInL10dw5R+K0tMavZM=
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDrGwh50h3mSKLa
+BdysryFoNiWasyRben/aF+l0VYrUvBnB5svH/8bcQdJV3uYvAra8Yet1bCyARsiS
+sFAvhlso0itRbBKPqs9R5kE3h03101Nd9lvjfkuKpWJaf8JO/L9dvoul1e5O9IaD
+EojPakR6/zaOZW2lxqv/SuzRmhuleccB8ufbwFwI4crfkpRMHO0wesniUa9Vq7li
+hhl0WF3/suf9ZA8T0aDloKCdz9NfF9oqy0MCYKVQeqYsvmAMvoRC8fAFcaj+K173
+yNRmHseaBEYqGgu8Sm25L/s5XlwhIn9EEPoJRZiZlBr5N4NBsTNx6YWgVARvC34w
+8IuCHBpJAgMBAAECggEAaNKwwL/yHM6d7V9XuJaM6o3ZzlO5DiBcCL1IlVnegGMt
+iMqCaTWdUG74fNjZAHTRTMTL2prUbI0iuGRsHARneJfcQH1S+UNLFFT5Fuz40XXb
+YbWJ2rBgtfxvEbKMy/Lcz8s5MENl8UYNAzusS+4xgjVv+aU3cgZWgYjCdeGkGe6L
+Bhpnxni0dfhgcDuNUuUzEdUNNElb0cIuHrz6zrsgn6tkubFf8xZ8NMf7FFiQnWfw
+Ifu3EHRfHw1Qgpb0M3/GjTQ5I0JZd1WzJf6W7gvX/ViiNlLjRrAbbpHJH4/DLod8
+T81Lzxnkyl7d0wTZDOoGX4uSQQ9AEn8BId0seDHmAQKBgQD46AZNyM/3IIREjCwJ
+Q4yLHmy4cYEqd79hlM91HjupUmbVRTKYXcx8+YrGzSGM+sn1kV8B1tsRsmXr9VvC
+WwhXIGfpYnxqasNiC1m8K4pbvhJurg5LnJ1tET9DzFYagE4gD3TzXwYA9VXoy4TG
+9wV/PIL6T122kp3St7l3bGS7eQKBgQDxzlIb+em+vQIJmNvbwSgA3ZegTisJunDP
+7ZOnbD5ItyT+vBCT3S2xZzrk4ugx8ZBS5ww5NqLFvHXx1TH8Hhq8bFqFJtW7q300
+BCTTyAezKg2rwhcXQ/y+yLI8IKmcuU1kA0msxb5QbcltEmAHqC1x5AKd2WmFQEc6
+sVYSh+fRUQKBgECH7zJ1cK1yabhX2wbf020yCx/alZFMEHsdGJgVqYQhj/WVBiQI
+lX6FN9yIzDz/vCKFeOtCJ/Ozm8cMCqkd7tCf3zDbzsPMQDGIHdCyPSHB6od1atFh
+nlLrmMpcDKq8PwUC3OBH74eKE6bSNO9clblCF/cLYpF1+6Lo7RWwLYGJAoGABJrJ
+NX8s1FUFFOm0RhsHh/ywRn02lJjYTR1ZEncdOIVETxWFu0sa86XjmTg487qF5Q5B
+TVWdA+by2AgXS5XHLI9jqeVzbH93guYRTXchrme+mua3SdohlgB8ZGi60iE1OBJX
+9NJPLXjpvQn8iijJtMGCyz64o7D1qkh2OyQbZgECgYALYD2neitnQ1cNehdWxchj
+NXpHsMA4m3CUMLZiEFrJzUompG1Tu5VZovkaCGgT71AQ9zYx6V4tyAgF/9VA7/yu
+IkNocIm3LL+Tb/1EgDAR1R/vOGJ2NKUdUv4TRlmTxR8+xz0Dh55dLIcNeq+YD8aW
+u1tbJBTP7dQP21fshJHa1w==
-----END PRIVATE KEY-----
diff --git a/jstests/libs/server_no_subject.pem.digest.sha1 b/jstests/libs/server_no_subject.pem.digest.sha1
index a5d0fdbf1b5..22537e8cb87 100644
--- a/jstests/libs/server_no_subject.pem.digest.sha1
+++ b/jstests/libs/server_no_subject.pem.digest.sha1
@@ -1 +1 @@
-8DF7D10C240AAA04D102E59EF2CA4843739E0BDB \ No newline at end of file
+4AE168C4B38F4FFBD263D4900388D777FCAA546C \ No newline at end of file
diff --git a/jstests/libs/server_no_subject.pem.digest.sha256 b/jstests/libs/server_no_subject.pem.digest.sha256
index f51d4bc14a3..f51e0af27e6 100644
--- a/jstests/libs/server_no_subject.pem.digest.sha256
+++ b/jstests/libs/server_no_subject.pem.digest.sha256
@@ -1 +1 @@
-F5A74B3E9DA3E909351E208DE8652CE1F8A34EA0062780B51FB917D8B95D7C58 \ No newline at end of file
+C10B4DA14300E283FB5D8CC8F0CE6CDB2B1A14743E36BDDB7D2076EC5A921586 \ No newline at end of file
diff --git a/jstests/libs/server_no_subject_no_SAN.pem b/jstests/libs/server_no_subject_no_SAN.pem
index 9416942b2ca..d002e25b2ab 100644
--- a/jstests/libs/server_no_subject_no_SAN.pem
+++ b/jstests/libs/server_no_subject_no_SAN.pem
@@ -3,53 +3,53 @@
#
# Server certificate with empty Subject, and no SANs.
-----BEGIN CERTIFICATE-----
-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
+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
-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
+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
-BwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQU2WSMGwUJDd1/bNIPdeS4OJcruicwgYsG
+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
-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
+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
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDeKX1d2GSk0a7u
-0QDnubb++TXgCfef821fypDH96AJ8NHTcqtTeiUXZeE3K7VMRZKD2zh9jnq4DbK7
-m07nRO1yYjRUh4d5bnkct5g4EmsanDL91jNXV4XHO9wY7Y9BdSB9pe06OlJTWt8h
-gNH6D9n+/xlz33fSULGUATVsSqbSt9WFOO+OCAuf+icPfUciPMF2cj6Co4YcaQ3h
-tmOoowTikSE0sgPonvQmOAOFx58KWxu5XLQdMzQAdbE7BLbdJirGYrHTq1lm4/hm
-22AGqos+qsjdPPGi3b6weNAyiJpIruGaIJ8H0B0NrWYHrBRbPi09weoeJ3BWF6zH
-yCKOeFFhAgMBAAECggEAC5L7yLovsXU0eOqt8mShh7JyFRmlK1HM/p2Yt2JLldj/
-BYDG3j18gIs6lYY9wXB/y/DNhkpi/a3GWbHOBYx4wRR5XMyxc9PGlDFtyRYPOxQC
-MBP1xB93hRlgQ8g0m24VDZa/FOEu+CVsKdxX6YA5P5NeFG8DA2kC0g7SEAc/nmCu
-mBJlJmqrHPsVIMC4Cf+WO81MrzkJXfQLNF57veHXfyUf6Z3ZzgbO2TDtuCvtI2hp
-9uiVLVhfnLOw8DLK1xPh3JJeDMoC8MPdyfHtZH+/VNxI5aOFDqlbLQ3TjSRnhSqx
-1MSyIUvNeMVWAlXWhSLTRlO+7rTjbnMojivNGcgqFQKBgQDlikPUFeVR7MKtw+S3
-KW8tNAwEE4idQ9nh5o++iY8DkSn3lekCjc+lYxchiqjieSlVURJFgAMXgtOP7CN8
-A+GslJUw1JCSHu/XOIELFk0lMHEkLyotOYxAZKqeCtIfQMtNLTzCPiXEAw0pm/iu
-7RUpfHWaFrENXhHLbHjk+zjVEwKBgQD3xX+5nLBE6Rx5O4/n0T4g9sgQKD8uAF3m
-PtrCSRJzwqxWhsjy3kAVgQofAWt3Qy0GA7qq86V0gmJZzMNcWUA5R9qnRgd6uGKb
-Dzu3JzaZBSGxiC2bb0+BkHwzFQvuTeCbFrNoxbi8a1ysHNXY0s4JF5I/ZmxN3+kp
-z4x6KeiyOwKBgQCZLRlycGIlt496kd0Q9Y+BZNgX6EkkWWEOxONrzTQotziARgPG
-dof44BVRhsyIxT319zHwOyrVB7LSukw7uANjPYwJl/AZ8pcu0kAa+/jjNl5qPScy
-ItMbLZJGAQaTYJPKnsOLBBoDod2oxLLBWOjkVG/OMhJYz0ukqnBKrfMRDQKBgAWB
-LcVB5eiiBS/sUtYjn+27jdZODplHCM8Etnd6iB5qRMnnVK+QoHvZ0g++SFTt+SIZ
-ExyZLSPZgbXdBroWgYbEQedVdvUTA53OSNVY2a2sn4MCM4Ewh+OpAhlgblNtB4Bq
-kLHTMrd86yInwdh/VnR9QZKHBAD26Ic1RTmxlKnhAoGAV7BPFX3Aktqmujd0WMHo
-5lIeq1aKhVM59KYzQrhftdVHBfXGKWucgWJSqvyR+/Ya+3CTRfOVXPWVL2p9HCMQ
-5QIS2frBUKoxvZ1P5l2424bCiU/iuqqORpV/OKVsJ9Vo4CZ3tkHN9gTf3xETeg+7
-wrqgH0+XVJxZB34FLL423/I=
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDNr1o1sCYKwPid
+mRn7icTg8+5fjtGfoDTW5ET3nNG7F46XX+pkSJWA/0jum85j8DaZ2o2zd9R7DURL
+/8MZh9SmU0yv42iV+O8t5UjEmgW+m/vBBkxFXuxW+zF4dCMkxx4lxMgCH2ctYogr
+Y4fwzMsQhhmDzrNUe6VG2+FygvqpeOuaJVGSpaOHgnIY0eR6R93DRbhVTbLSTAHT
+4BTSjKdQSPo32z3WYgaJcFmQO/eFneLL3wfAIs669/eOgHzBB09ZoPJFzW5ktl3l
+9kfGU0P3eYaJ4P+dRoClVkqtcX1qwqAcYcVlYYetmqt+E2f7BdZZOQ8oWVHfLsLQ
+kLq4h5dhAgMBAAECggEAAKsiOuxwozZPWIvH1tZyylxgmPTo34DwywYA52EeGWKR
+NxK7u0m1Gq85uHTPLen483UPYtbv3NqFL04Mf0e+vC+nHyc5Dsu5U0fcfa8Wd7Eg
+F1eC5fLSB9JXLdIKzzLKeUrzb3ZUqoQYdzOinHi97DbTXGdOk+a2+cz7JZkhYW2e
+sEdzHD+u2csYIDQ/2OGYUkuSpxbCGP5jWlzN5sKV0ekkwkVMJR3tbcgDtFPL34YI
+VVgV0Jaan40Vl0jt4s4rgU6L8NwRcBxGBWR1W50SgCEykT8l5qBHuf+Fidu2CJvr
++A6Li0NDhvd4rsVVaytZaR2Ykf7H13TmrmbjDCIVJQKBgQDucRdf5+DdOSGBaYHm
+Tuqu51GMvHmT1uarBjkHEOi1HJcZc3sKT7UBraCiwpcH8ytw1oXQyTqqXtNcet+u
+e1Y5v0vAeaaN4+0ZEOY7esbrW9SoF16Yu0u5+gEsWb3Jh38KYI0Mrh3adxwRPr0+
+wmfzHr2HWqRHzO1iCxrEXWraowKBgQDc1MHB9FThYHkTLkK15lNTDCfp5nTyz4th
+64KuITStGUwdkKCaY7v8y6d35RR4M5yuzS71QOt+UHnEstpKYng5FhBjybzBCiWn
+yatj8hegelq3dA2kczBvzK/Q80Bzza8PJi4j6flpoXacXCl2vRovlwTsDPwlbehF
+90G91/OKKwKBgGKvQ7FZ0uM8ZfWdqTmcp9zDuCi7SMY7RzS5WpjmEqoCrzbFaMMX
+wh5zsewrBT8xEWWeI7wJzNH+dRPtdu5L9Z/o4H1E2/4Vu2eIawFrCzEVzKnVIj2s
+JudN5XZpnfbusVGmLDp3RbvJWEB66vAynbstmduPVDazRfwyBF4JG9RpAoGBAIEq
+XK6SuDcfU5I5g8Gbl+9Cc/Im3w7LAI7kzwoE2CfLXS8J0jab0XAaurixIFjyb1n7
+H9VKBLRcY+z+ZBoQIJvbYPjNHf+XbNEIb5xFFTbDel5FnlkrGxC5m7jPH0rc6uEk
+huZwy3bSf2sTqRkPoMpnPfTH35ARCkQqTKS7NHMDAoGBAK2o8Yb4zcH4Ub1zW5Nk
+k/5AH6PWn1vFJD6xO1whLB8LStkA44a7EGCI/DXQUHdVVweC3VFK7tnQKw7X72vn
+K1HGXUfMrUP9LM1qEAy7audURUjaTMXkZvnr5iDwhdd/3tshkrUXYrOMeOdLTXXi
+/xqx72NbpsNtP8wS35rpfjaP
-----END PRIVATE KEY-----
diff --git a/jstests/libs/server_no_subject_no_SAN.pem.digest.sha1 b/jstests/libs/server_no_subject_no_SAN.pem.digest.sha1
index 4f7e3de3fc0..4d57d1b6d8a 100644
--- a/jstests/libs/server_no_subject_no_SAN.pem.digest.sha1
+++ b/jstests/libs/server_no_subject_no_SAN.pem.digest.sha1
@@ -1 +1 @@
-DC9D1E8FA5AA70731ACCC30CF57C398A70FB958B \ No newline at end of file
+69C7E04A211A53F246DFC810B2CF098B108A8678 \ No newline at end of file
diff --git a/jstests/libs/server_no_subject_no_SAN.pem.digest.sha256 b/jstests/libs/server_no_subject_no_SAN.pem.digest.sha256
index a44f32d495c..4c61e52e7c1 100644
--- a/jstests/libs/server_no_subject_no_SAN.pem.digest.sha256
+++ b/jstests/libs/server_no_subject_no_SAN.pem.digest.sha256
@@ -1 +1 @@
-28BAD2DAB0C7E2276F067B51D1062F1FD7966D3DBD5F9CB254DE295C58C088BC \ No newline at end of file
+E5F6419C5EE71F3D3C9E5D7EBCF46941D91FBF303E17C5063C07856B760D9F7E \ No newline at end of file
diff --git a/jstests/libs/smoke.pem b/jstests/libs/smoke.pem
index eaaedf37c3f..ea5cafb825a 100644
--- a/jstests/libs/smoke.pem
+++ b/jstests/libs/smoke.pem
@@ -3,51 +3,51 @@
#
# A self-signed certificate used for smoke testing.
-----BEGIN CERTIFICATE-----
-MIIDZDCCAkygAwIBAgIEfZVmmzANBgkqhkiG9w0BAQsFADBrMQswCQYDVQQGEwJV
+MIIDZDCCAkygAwIBAgIEXstJbjANBgkqhkiG9w0BAQsFADBrMQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEOMAwGA1UEAwwFc21va2Uw
-HhcNMjQwMTE1MTYxMTQyWhcNMjYwNDE4MTYxMTQyWjBrMQswCQYDVQQGEwJVUzER
+HhcNMjQwNjA1MTYxNDQ4WhcNMjYwOTA3MTYxNDQ4WjBrMQswCQYDVQQGEwJVUzER
MA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAOBgNV
BAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEOMAwGA1UEAwwFc21va2UwggEi
-MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCuSe9t3iKqWFygmPtAvSJa6haH
-kmSHMarUrOHBbORDswnFhNqW2ZC+0CNWALiXlXhaQcL1jZxIS/kfA6At6Gl2RWhn
-qm2hnyQ72cgkLCW7TLYAAEUQWc/fhaRNu/prEnagB/3ePF3/XXoEfzRo+0qtcx8q
-RLtAq3kBcTvdahQLYUyfh91nNFy0FRRruFM+FT7HFz5fe6w5F3jFeCou5xUSZGOU
-QvKBkJ5h+sPwf3bwhCAghHhpOMH8I0aVKkOfA+/YO/4Z4Gv3yyXrPHLzMjMzYY9Q
-7h8HHL3DNbVKkeYgn6ZUKEIePceB3v/CGd7NAjMaw+Ta97EWPRe/rQaJqUKVAgMB
-AAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAIc3W8C0nrdv
-Ha5ZJFlkbPtj4KXFr48HoYVFQjb2obkRZR1HlrLqYY3eLEvUptuGA2wnaEPm8YH+
-1UpTktG6QUO/VJ6pHPMB6N28ZAeEUsX4kP540QTRkjYZjKRFHk3k6S5QMkdK0U/J
-8JlMONNzrCTiHLyGypnahIPPOJ2AtIojfsoPn5N4Sjb5uB7Qpdl6Ql6ZJXmpNBtv
-y7mnImcRoKv8B6pRzxD153uIFT6dw3h73iLAIkt5uXfUSJItMTIhqcKqQtW5eHHv
-peIhSwzRRH20hLMWkPO4ALdEgBr4eTWe+FaEuFl4wb5x+q3T0oBlKtdHFhDwz7QJ
-A4zKtjNmQTs=
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDAIUaDw/cU2zCXuZej5kuOVa+k
+uMXlE9W/yruNT4JCn6fTOnlusy3cvaeYIeqRtUTTo45DD0yccqsOminIiycMQwSh
+vCqi0Oab+nLutFOMKA61ijjeELNsRmgqtmB1jNrCsDn9Q3tCnXbxiDTRPVxxx00N
+2/dQ+WTUO/m/EtPDyXgLsxG804YPU2N/1+sySJ9lP6IG5WJEP4HqEorjxlCoJBk9
+esu2JXbuJvK3i9ehPKZ1xXFQB4mXK0/gs9bcNDT6lAsv/uHmZKYWfVy8O4zY0Je0
+LGyMzA4HBamxUod2L79tAuFRALmMmwyTqRypJ+jEb/doRhqy7LaMjC8q3Z7jAgMB
+AAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBALcb15LDCHo6
+wOVRkgl73feqsipHwnd2HYEDM0QqFbbh3LwVF0MsendfHsxS3FDDGqm/5Do1RnJ5
+Eurk51S2rfRLSChKjcY1fSaEOv09trZZrWyx8CaIUqta3njT4Rs+aaaIfJNCpf60
+1ELWU3Y5VpD9Yp8MnfmJE8kDYiZjmfpiKg37Kl7vpu3FQdAjJeXcru5wWVtQACfT
+QhafpTO13Ov2P8iEPX6LEz1rZT613coQIMWCDW4qHnTWnafcVZbiJnfaTxstXsj1
+fOVDWFFrFrKIy4MHCpFLtNmTSO1Vy3Ym+vMXBZjxIsF2FbVsDGlsBS1UWbjJRMbS
+7F9vAFr8gSQ=
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCuSe9t3iKqWFyg
-mPtAvSJa6haHkmSHMarUrOHBbORDswnFhNqW2ZC+0CNWALiXlXhaQcL1jZxIS/kf
-A6At6Gl2RWhnqm2hnyQ72cgkLCW7TLYAAEUQWc/fhaRNu/prEnagB/3ePF3/XXoE
-fzRo+0qtcx8qRLtAq3kBcTvdahQLYUyfh91nNFy0FRRruFM+FT7HFz5fe6w5F3jF
-eCou5xUSZGOUQvKBkJ5h+sPwf3bwhCAghHhpOMH8I0aVKkOfA+/YO/4Z4Gv3yyXr
-PHLzMjMzYY9Q7h8HHL3DNbVKkeYgn6ZUKEIePceB3v/CGd7NAjMaw+Ta97EWPRe/
-rQaJqUKVAgMBAAECggEABymlmlAngEHIfSO99nbMMplnUSC4gTmoXpXdr+Kr5xNb
-BEzPZFhiVp38e2Ex6BR97hNA5T4LYIlzKy2tngCTIWFWjXIaqZ2xPvg8vZQ55CUE
-+S8jQROFbT2tCn7+Wns90ebAlASxMtifQw/zC7Ontng73U0Wg/pRqzgOQLoTQxwy
-zPAdsbaV+c13ZY9iIrK/qhLr1JqX1kKO2UJURQDAm+JCGoPkAXxr/L7xZT+GK8KK
-BoMWftB/2+Xu2pV8k29LmMDKv7tKe6l2cL6mSlJGHC707ImttEFa+TGsKN/TiDW2
-pX80GbExOvchHurJPL8//oKtEje7SAD2nqnFyl/CiQKBgQDke9JnvSLjV3+kB1By
-hBeZ3VVaO4sRS3WxvTnbkXUOpmJ1cpJ9mBMagLXuFgPyy+eqay4vHJFLTwQEkfgJ
-cN3YwZoVrGsEKu+/vy0yZTAXq1HcKESCUWou4fsrV+D/uyFvCLrsfVlZk+FaSyL7
-ZDpsX0jeJOs1jffXxTgENGNoDQKBgQDDR0eBBRgADnuYZVH0iVY1psXlpjdnOxjn
-/SEoWZtex9s/Gf7hKl45C9faZJPC58O/6bUutZMLevX2sujG+9PvuVt2VB/ROTQl
-ZAyRhl/cXbS341agLjpmOQG5F7Mb+Nt3x5NCXzp8DGaZxiYlbo+A4AoJ30HIBQIq
-ukaofQlaqQKBgQDBQuMEEH1UIwy6J92qH4T/BrJNcpP8+wEAaHhp+q0yyRX7FgBG
-770o67n3OvP4CPVZtvMHsnhLZPiXDQjqo2djEs9MidyzV8YXQJPwTprRSn4hZIYe
-XNMd+NPFI74TUavECXRi2Nwc4vL4txlN3sd0J1yxWjUBxaXgAteQ5uc2eQKBgDSa
-YOKacqqhPB4DPR54WGa/dBO2wLnoK39iqqnp6XaQs7i90fDprtQDIrRL35njQNHT
-rODWPLQc/WDlNNtVPvQWpFKtupxromZoGxKgdfYwr9vRO6aOjWC3/oTTo4XndYdA
-laSNbn24AXNu8xumOrXmpA2gvGGbJ8hGwX3loL1xAoGBAIRk/nUwbk0Ym9G5YRaq
-xeeyQQtWhpzr2yyNC+iK5OeZHTcvAZiNBUyvjCzEyO53bjMmxMZEHc61LVVnh2hj
-g5TN1gDg8KvCUm3kFqFusGc06QImhp+bz8Eg85CW7rSICAJ2Kl0SbTcU/tw2VX2k
-7CarDbEyyTAIO4MpDzRTUgTK
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDAIUaDw/cU2zCX
+uZej5kuOVa+kuMXlE9W/yruNT4JCn6fTOnlusy3cvaeYIeqRtUTTo45DD0yccqsO
+minIiycMQwShvCqi0Oab+nLutFOMKA61ijjeELNsRmgqtmB1jNrCsDn9Q3tCnXbx
+iDTRPVxxx00N2/dQ+WTUO/m/EtPDyXgLsxG804YPU2N/1+sySJ9lP6IG5WJEP4Hq
+EorjxlCoJBk9esu2JXbuJvK3i9ehPKZ1xXFQB4mXK0/gs9bcNDT6lAsv/uHmZKYW
+fVy8O4zY0Je0LGyMzA4HBamxUod2L79tAuFRALmMmwyTqRypJ+jEb/doRhqy7LaM
+jC8q3Z7jAgMBAAECggEBAKFuFAp4aC088fo5tUDAKjHAqyDTI2uTm+BXHfjgmkkS
+Tnd7RTaPFHTJYXzA2o9s6BSO8uRDgZJeAn31aDAZQ0jZMpYWPRiqP2lFKLaKCzzT
+F3DPX3KuQ6MxESr6K9f47oHwgfjbb0CMf7j3QbGhRgBPfd2sOYPu2Bo+/lveHNH+
+CVuTfYQPQsq79ZX1JWjKd4FTskSDoHwx43qJK+7WbM+24Llx5X9SA4KNfV1IOpL6
+wgzWCHd90DOMgIRPVybKFWj2x9wsdWXqkl/jOA5WCwhvnyu2CzD1rOL1jcP+4TFj
+TOzxcfFyqLZf7jzOeL7X1pyCXPGZ3p47vVOru9E4H8kCgYEA+MEXyi/hWCu9xOnv
+RB7au3uadc7+RlraVN+QylFO5mTpQ/bQeUplyFzNSr19PeHF0KdOU1yvO1dDxxdU
+hJ7S4NZn46tfaBGAh3Ia4+b1MQ0xqJ+h++yJ2aHlVN5L5bTFVgL4OYQuu77TjM/M
+GUriny4e2OMEWNe3hwUNgBRyJJ8CgYEAxbnyiE8uBJPauLMeuovh0VFDJ23KWGkf
+G2HI/MqPbKbN/MvOfelpBQ0rHDkEMShAlKNTjONwcekrIGb/xGRXwV7bR8E5/AWa
+nxpCMtRrQHFbQT3KctMy6ibAqOi+Rx3Lb56cgrvTQCVH3tgUKYt3TMGXIb9Ewm/a
+17rjzGxd+z0CgYAa+b2dtHGIgT3UE9ZZmcr4l9/ZNLhIYuPYXmIyPn0C6SCOuT5E
+WPgOsVml6ESjqE8uYGZTDfMGyWDVP0dwFlUiAr5DZzsyaut4RLx7yHkAd8DR23XS
+fwU376GSAYVThLX9rNbETfxPadNBKuukNoW642J+/KdlBwelAbxEDnOOWwKBgBWt
+YjKhg6kK0LLpKFhJV7OMFjGvbrysobVtzgww5PKDgxfQ/E1/lnzwSaapdZUyFYp2
+MYXDtaM3bfv6btYILjrL/HxsacAAmUgSJ+nMsgl5pAiODrDyCKX1I7Ag/CNt18zf
+9ca7ctiYfb2nsOYxHR40Jy6S+qXaf4KhQbI6uz79AoGBAOZ77CNpacc+AgEehP4g
+TWQ/IIwaEgoUOZo1nnyjkwXR3EXLxJ6su+nOeQbEZYUGd0CV7UZ7MEW2gyyoMxCZ
+XDZsyX04RGU0KKekuxJJDZmVc7gBC6o4Xk5E7fDjHAWnXlosFuqcayPXGOVmIVxD
+C/CnJAHM/9qeSZzRZvqOUctm
-----END PRIVATE KEY-----
diff --git a/jstests/libs/smoke.pem.digest.sha1 b/jstests/libs/smoke.pem.digest.sha1
index 1ad740e1a38..aab51414a57 100644
--- a/jstests/libs/smoke.pem.digest.sha1
+++ b/jstests/libs/smoke.pem.digest.sha1
@@ -1 +1 @@
-E4EE21F2EDDF719D94FF21656F88F22CBAD5F580 \ No newline at end of file
+40A980F9DB90415D99A545AB8A864BD108323461 \ No newline at end of file
diff --git a/jstests/libs/smoke.pem.digest.sha256 b/jstests/libs/smoke.pem.digest.sha256
index 9551dce31d3..d49f3249e36 100644
--- a/jstests/libs/smoke.pem.digest.sha256
+++ b/jstests/libs/smoke.pem.digest.sha256
@@ -1 +1 @@
-57ABB2BDBC1F06B83A0BB283767DD80AD5C44CB6DFF07C5AE2BD9A132AA08DCC \ No newline at end of file
+81A56A81C7133AE6655AB337AC26695D6C33971B6762570EC292EFBF6A33FFCC \ No newline at end of file
diff --git a/jstests/libs/splithorizon-server.pem b/jstests/libs/splithorizon-server.pem
index 3162b08a4b5..179019c68e7 100644
--- a/jstests/libs/splithorizon-server.pem
+++ b/jstests/libs/splithorizon-server.pem
@@ -3,53 +3,53 @@
#
# Server certificate for split horizon testing.
-----BEGIN CERTIFICATE-----
-MIIDzzCCAregAwIBAgIEULEB0jANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDzzCCAregAwIBAgIEUy7nZDANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTQ2WhcNMjYwNDE4MTYxMTQ2WjCBgTELMAkG
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ5WhcNMjYwOTA3MTYxNDQ5WjCBgTELMAkG
A1UEBhMCVVMxETAPBgNVBAgMCE5ldyBZb3JrMRYwFAYDVQQHDA1OZXcgWW9yayBD
aXR5MQ8wDQYDVQQLDAZLZXJuZWwxJTAjBgNVBAoMHE1vbmdvREIsIEluYy4gKFNw
bGl0aG9yaXpvbikxDzANBgNVBAMMBnNlcnZlcjCCASIwDQYJKoZIhvcNAQEBBQAD
-ggEPADCCAQoCggEBAKSSrMidgUo44pjA0uTwnQ2DUq3WD5c6s2qQc3lj+B2WIrAd
-c18JsyAbHI7E01qpN+id0bDmd1+XJy1KC+B1UyNTZN8WARVYd6bZl/Tu7FXsyTGx
-OisWlrZUAXr2zfHsGhvyCR/nSfa9HWyPLAlDWY2xY5/H4yulypdoloOcmP4NnGZb
-Ydv0FpGbAMg2eB/avaHnvzAZWW1Gk7XS0EpLGxdOG0y+gItGpi7IoMYrlrahKf1M
-71ndjJWzRXVkBqTp2dbSNO/h9+8kRotumqWBrX25EltnbkuY+o3P0w4SPDO0TFk9
-v3iNZE/6KTyK7MEVXjnvJAwoWjwUqQYE/U46y/cCAwEAAaNbMFkwHQYDVR0lBBYw
+ggEPADCCAQoCggEBANbnuOFn7oBLC5gwBhmccMbf0NR9d2xLgLCxEwj/eR8/n7jj
+/KMuV9tyThsVLECpUhr+wQn8fGI6HWe4cXdVVlyEJVQCzthSnVAyXz8oFH+2A5ir
+kEXZDsD5YnPlMlAIiDkNx80i76dswwjlQLn/5gXD/LlKWsH4WPKsY5N9ZnkWQtLj
+Jzh5wJBeI9omv/ZOXKq9mLUs7avDvWJ4xP/Zi6m47nqqAVn1EbVnMzXKNo5lhR5U
+w2U2qaYK4Vh19ZBw5kQVIxWswJD3J+fRuGPQcM0PA7I/fTQZRJwdX30ykjOdlRmb
+bEuVwI8EBI9y12OKtzihMSv8LkP9J3ki2doq7YcCAwEAAaNbMFkwHQYDVR0lBBYw
FAYIKwYBBQUHAwEGCCsGAQUFBwMCMDgGA1UdEQQxMC+CCWxvY2FsaG9zdIINc3Bs
aXRob3Jpem9uMYINc3BsaXRob3Jpem9uMocEfwAAATANBgkqhkiG9w0BAQsFAAOC
-AQEAXnArbp+ArR0aKUWDq3kE3bTI7ZUXw4o6v5uff2x40vIcnhbRW8FURZXv9+fH
-P+CTBUaZjetl07XzMXG1f/3gvxwpeGlfgTw2ma641rbQDWwg0z58leO/UwHbzPZR
-z732XipTkzl+lJU038YfREK/AXCTj8HpYTelpsOIXJDyNBonRaxfoMnqGKGRUZ9L
-5vLCLtaegC0mb/0ZTDpP5CzxXEKnnzV0Eih3++ixSVkeW7Y7MGmkmv9q/+/Z6n74
-G+1oZUicbfd+/JdsvyJJrqy/pYLrV4LQv9HdReSDSlxS8CEYKI5wLHrCSXw6Dchz
-QmqrFe+T5lEhcFmUqmQNMQXsCQ==
+AQEAXSCb/ezMz6MaZhQRwWYkOAjkPxBXerktm8VW1zDYEI71ZIdwVZyZaA6yzkHW
+y+V4TfrYNspA0VjjPqY63DoyGHafCo0OiQIqxFUDJPFCbFDtI1GP+aQTj8S5Xs8p
+RmwGQjEztyKfepaE21HtOfP5Mp+ckU9s80BhNUKbwqmaN+etUAHPbv9hM/UqW1MW
+VscKs0uvjgBMvMd8kKkApNb6xRClH61Ns97jguePc/CsYhQviXfhrKtXHUsv0UbK
+gUtCaKB9Q4AtyxClOOYNb6C1ydwb8vJRcmHu52zW4Z9Zc+6YLrDNr3Hot1gVwaJg
+Ujuw6bjtBeQuZglIdfNCkbwHCw==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEugIBADANBgkqhkiG9w0BAQEFAASCBKQwggSgAgEAAoIBAQCkkqzInYFKOOKY
-wNLk8J0Ng1Kt1g+XOrNqkHN5Y/gdliKwHXNfCbMgGxyOxNNaqTfondGw5ndflyct
-SgvgdVMjU2TfFgEVWHem2Zf07uxV7MkxsTorFpa2VAF69s3x7Bob8gkf50n2vR1s
-jywJQ1mNsWOfx+MrpcqXaJaDnJj+DZxmW2Hb9BaRmwDINngf2r2h578wGVltRpO1
-0tBKSxsXThtMvoCLRqYuyKDGK5a2oSn9TO9Z3YyVs0V1ZAak6dnW0jTv4ffvJEaL
-bpqlga19uRJbZ25LmPqNz9MOEjwztExZPb94jWRP+ik8iuzBFV457yQMKFo8FKkG
-BP1OOsv3AgMBAAECggEAKVEvsuAkNQOqFAqZB+RGsb1OFRmgaWnR4Ieqjgfko1zt
-kYSbUfln8MANv+Q3YdQJFswEeKKrxqJ2sf6ck7ow6LYHpaBrHjZLN+b6KQKQ8BOW
-AXVKssWlidn2Uy5CTyHk/i4aT1msbpdVG0uolRzFD3dBGTzAUlV50uBtpVY77NAL
-sgGkbEZoDKB2PD3U7pKQwh7IsCpkiBfAeIeGZZOsORPVy1N3HegKoK1551kzO6FP
-qSuwShxj0SlXRGn7eHsOc6nwMHGafbvN0SzHe7DQvQmg5CCaDW6mktHOUVdMlX+e
-v0Zi07QpCIaPVC8M9xGWOgU3oRVx2ejMm3L/s119nQKBgQDbNdH+UZtQfOTwAs8T
-CtPX6DfROWn6TdUxGHV2WEr3AH4Rj+6e4Vy2Gke+YwGcxIBVS2fKkEliPrf8r38f
-36ZvzWBjknFrEZBxJv+31k33WMS551w8n6pXgsMx1/SGdBNoSHJGvp1cMZ2L4DZH
-RK6uQ/NF3Aamv/Gv6DXio3g4CwKBgQDAMWkW5egHN9fenQ7wchHefM3gNdJ8M+wD
-MdwcljmGkt0YEpmuv7egk/YO0Z2eCpwRs7fEOT4v/qKXX4UTSxACIWY+hWADFdmL
-fMYRgJ3bKVgcZjw3tzuNfpGqMcX1V2FIKIUsqC9cZhhYFJcIzBP0nv6Oq0esgkuu
-13kPgWyzRQKBgD/DNPTr2eicm58wwfkBAkPgOTQzph73utaQDcLBxfR5ATKskjVG
-ykfx9wJrHBH0mnu09ljWhXH9Wlk21xx3WptUuv/bngAN2N0BAgsAXCdhe7+zi4Ha
-05qm345FCcx+QRLpV8w6L92cVP5V1pP+Z20rOL0OViT02iFXwyzMbfCnAn93Xjjm
-/+Qcl5J7sRCWRkLS7LDxkHwqqBTt5wnOt38DFjQ7v1G0N17VXRB2I7rBbdWBKR35
-wZPeO0jAu5LraLOInzXhnvUC9Y8oE1bxh/CDLiqLePPtpuBWAUZ3bnKE7sB9EK2m
-Ds9blA2Kpz8nN5ktVZLFCZx6iHJ5JVsLRlc9AoGABinL5/QDSs5rzreB6lWbAxOe
-ccRsBsSY6IYfhJ7HLMYPkwAsvgIX2rZDIQ4lKcVOJesQRllYssWsiSZ5MEo5RgmY
-kudCgGd/yP7zZry4VZVrZ1DzjNV2T38oIMWQdveyo8LaxRleqFgQBvQy+EES/v9M
-ZSYYEMRe2IB7zKpMV0Q=
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDW57jhZ+6ASwuY
+MAYZnHDG39DUfXdsS4CwsRMI/3kfP5+44/yjLlfbck4bFSxAqVIa/sEJ/HxiOh1n
+uHF3VVZchCVUAs7YUp1QMl8/KBR/tgOYq5BF2Q7A+WJz5TJQCIg5DcfNIu+nbMMI
+5UC5/+YFw/y5SlrB+FjyrGOTfWZ5FkLS4yc4ecCQXiPaJr/2TlyqvZi1LO2rw71i
+eMT/2YupuO56qgFZ9RG1ZzM1yjaOZYUeVMNlNqmmCuFYdfWQcOZEFSMVrMCQ9yfn
+0bhj0HDNDwOyP300GUScHV99MpIznZUZm2xLlcCPBASPctdjirc4oTEr/C5D/Sd5
+ItnaKu2HAgMBAAECggEAWR7bcs6Q/68fbctsnC5eLnsetSAa6FQfWCb2x+J6LlVK
+PXh+ioVrddvfPCf5pA8Tt5IyJ5wHUQzcqOi6VUyUdeVvPXm0oc0Q4/MfwKc0aQno
+T+XF/NFY5voEtB82UC5Zn59xXkbAr+PQtd2si/XtRDLUmVqWbJ469Ng8qytz1X58
+yRRu02OFc0uNwK4Xq49yAZ9ROVo6Vih7ADqxBywtIenhE1H0fDVruAZMrIFog7n0
+4g3H4VJfEoLsd4ofa12RoAqo2tSLEYTtZxgGklMPiWBci06E6bMwFLZxgjdcHeXw
+R6jbdWwL/ydrIQ7Mv6N6t5hN8kC9XtmfggV3z/qwEQKBgQD8AGKED2itwpTS0GSf
+8As40MAhLfGXgJNlzdQ5JMyDjQ/Kc22Jz+iJ2XM+j8cC76Eiu4O0qqrZlKq9V4xQ
+rwMk6TY3ozuAghtvfxP0eNcHr/jmQn06dcI+iiopkfo1NZeNNLxgeF+GURyflr7l
++h9DieyHGkWxIFdru3c9z7tZRQKBgQDaUKd72HifS7H7+pg0nlZNm2UvaDp0QCYQ
+Zq3XP+vQ6dyi+K7WxIZ+WdCIPh2t6SgvtanMVJtx+o/UyD13sPKAtDhqDGEuhMBW
+xIKiMXQb2gpI9Q1LH+x+F8QrCurp+EIkxxOTtNkwNVGkdCKaj5qQdTzkS2jWxyiV
+hThf1leKWwKBgQCexm9L3ZmKwWqbWQnNa6Tma0Bip1vspOo53nG0f2cMC7jDSe7e
+Qcy17fgaluRBCVJxW8wj7NQwuubI3Xxe6aYFf5rVe1dmJJO8sEiWY/y3rzwXeBUG
+3GNCnDLsdjk7hUSzh2KZNb6aFkj+lDA7HljMaP5KMVdvvnzWOAttOpFEMQKBgCM4
+cdzEDqm8X4mEYzvR86BvmoJscUnB86IfvpoEYPoCUKsmLabOa9hEiyT/yG//NpGD
+4FHrsGxR/RRZ/biqnmTvLk7FkoQbvKAC8gRSsCWyJoigqDVfgBrToL1E9KMsfxdJ
+2rmwqn1hjLtYVSDUXB5EG7/E/rPvy3db1712agcTAoGBAMTld4IJK9TZRQ7ShNYS
+WWL3lCaMo+z5AaeHuN/nVxP9eyRCwuCJwqeI1fDY+UQtrpQRBezD5ot/ulTd5BVU
+LLF1PkXDo91eXDJF3Sw4M50n8o/1rpEmqkiYA6U6by2mj3GFn61/BpFurSUCFzoC
+C+uodJMfhmZ1NfKEZVP07ZeT
-----END PRIVATE KEY-----
diff --git a/jstests/libs/splithorizon-server.pem.digest.sha1 b/jstests/libs/splithorizon-server.pem.digest.sha1
index b3b16a1a611..1369e62e1be 100644
--- a/jstests/libs/splithorizon-server.pem.digest.sha1
+++ b/jstests/libs/splithorizon-server.pem.digest.sha1
@@ -1 +1 @@
-8A8580E5B2C2D95351D3E56C348F50DE1665917F
+0E03857BE6F69CD58048FE13A221A1F80726636F
diff --git a/jstests/libs/splithorizon-server.pem.digest.sha256 b/jstests/libs/splithorizon-server.pem.digest.sha256
index daf48762f9f..ea673976ce8 100644
--- a/jstests/libs/splithorizon-server.pem.digest.sha256
+++ b/jstests/libs/splithorizon-server.pem.digest.sha256
@@ -1 +1 @@
-E5A75DDF2021AA51A0A9F966B3E6A28AF188E9BB72FFB5FB9A519D97E48652A2
+9AA927053B8F5AB553EFAEE575E7EA76AC6E68C8EEAD558735FDCB0CD5A38406
diff --git a/jstests/libs/tenant_migration_donor.pem b/jstests/libs/tenant_migration_donor.pem
index 7d807730f0a..a2dc0aea667 100644
--- a/jstests/libs/tenant_migration_donor.pem
+++ b/jstests/libs/tenant_migration_donor.pem
@@ -3,53 +3,53 @@
#
# Client certificate file for tenant migration donor.
-----BEGIN CERTIFICATE-----
-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
+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
-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
+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
-ZG9ub3IwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCiR5+mEVSrnvzV
-P3JdvT36w/r3LW9O719cGr5iBgCWYqD1jZrRjCNgKRvDlVdbuNCHTp+Sp8E/C1WP
-gfStkyRGFa++aHmCn79y3LbMitOhKUV3zNCaSyoGgoVtnOQx+C3sqXV1LVfscqe7
-UAvBEYm6zYHQwRYzJ7qcjuXp4ckvuIHYqOfrtXajM75YEp6GSekP2GY4ob+fTLeh
-ztDstJjeoQVReeVOcDzKt5ddQFMKLnPU4V46k2Bdbo7AQzuoPT81SeCpCChxOR8d
-UKXA1vwNWEyOIN8daEUyhxlEaNOmOSdI0Ut+2S7uhvd2HIjlCRgTSZuaAE+ES5hV
-D0NL/A5DAgMBAAGjgYUwgYIwCQYDVR0TBAIwADALBgNVHQ8EBAMCBaAwEwYDVR0l
-BAwwCgYIKwYBBQUHAwIwHQYDVR0OBBYEFIBvrhj6R0AFVNOk968TJhO+6VMqMDQG
+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
-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
+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
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCiR5+mEVSrnvzV
-P3JdvT36w/r3LW9O719cGr5iBgCWYqD1jZrRjCNgKRvDlVdbuNCHTp+Sp8E/C1WP
-gfStkyRGFa++aHmCn79y3LbMitOhKUV3zNCaSyoGgoVtnOQx+C3sqXV1LVfscqe7
-UAvBEYm6zYHQwRYzJ7qcjuXp4ckvuIHYqOfrtXajM75YEp6GSekP2GY4ob+fTLeh
-ztDstJjeoQVReeVOcDzKt5ddQFMKLnPU4V46k2Bdbo7AQzuoPT81SeCpCChxOR8d
-UKXA1vwNWEyOIN8daEUyhxlEaNOmOSdI0Ut+2S7uhvd2HIjlCRgTSZuaAE+ES5hV
-D0NL/A5DAgMBAAECggEAH3J5wZjCK6/XlwuAgiHWDO5Fh/jKBSXl+NdF5YD8RChA
-wNT8F3dss4nD05bxItkhr9bQnX7ct/beUb0BSVGmSd6R+/gK9AE4/G1BD0on0KdK
-yvhpxDyknDZW3PL2VaieXapJFLgAvdVKI8ZTQMrBQe3pJicEwk0EoKoga75RWmm7
-oy174ZRLvcCkv9wOvSlkBsdAMjBXzY6w/mRzFOmpKcMOTKrO+5kLDNceIVLG4h/V
-rAex3gwqgIVaI3bg+yrTrymvVWCvQn23EazLiqqUOEgml9fSnEkgth0cW+lVbGa2
-E2cKz8+LW0kWJU26whTZdL1/7oElLoNDLAbXedeiwQKBgQC8g7SZa+YdrR1xrMzb
-gfheuAKIT183F5Qiq/nm94KyQ/HLgIhyk0lPTQZw2s4mCdQ9krLxxdv8+cWjQoFy
-rS64h8UJJIEFolQzAfxZsZYoQZwFTBHi+ivhf5iMHpzEo/LVTEW4lvlDzBfg09DX
-v0+RVvOvv+Si4zmmVRim6q2GKwKBgQDcX6fOzON6dkfqxi/HL19N3gSnImpnrOv4
-62a+Y+KE5HTZOiSTGIVfYhKnGvrCOqx1ZPxlFV7tF2MKb8mY4k6mZ+hel3m9EeDH
-Wg/l/jKUCmCf83nubamfdgT/TIvFCUlqNqgnIG3ssKf7+liXbiNnGMIxmMayXF1M
-4lTglEhkSQKBgAtqqohUGYaYklztCycMEv+hgz3AGNMcUXNcGPFc8gRbywv5B8pw
-kxMDZi11guCY3cqw1LeBtRX4BnkhsPdB979jMZKhLFMsBo9kQmUoNSDRAGLtvXOS
-lQ++C34I6JOcHju+t8Y7FnN9q8CI82/tfSMfMfjl1THsMvSY2LpbIhErAoGBAK/V
-Nux/eGWm6Jz/wvF37+AObMH6aNIOHD4BfXod8og8TKtig/pGD2zasK1ajofZDu+g
-Qu5YjeQ4y9Jw/XaZ401NDRAkZoMgN6x4RMUq/Ko4WX5mY3yFTVkpbrVRGxh833H6
-6FJHws2e6nnX90XkICVLkO7HyopXvi3xTO3gAp7ZAoGATEjOMoDJSNoDA+ld9sQQ
-P/Xv3x+3MJufExqp1ssOJuVLfI6f76rW4F8aJUPs9tJx3U2cnZwXhsCfXL6TmKwE
-u2rvxlkRqXw7bSpxAN4pmG/uRhSAI3SF66l4RqFFJMnjuua1P6wwlweojIQeX0SU
-6CqvMyWtQNnYdK8d6Y+g/AY=
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCuWIqf5OYrsNzO
+OdZ2rx6v+Mnsti7S+fqiyvq+FEcd0zpWwCP/8pQCIElk8lMyXa8d2gU2U9SWoUpP
+mbzquJP2eaWDHpQZTBAYoltgRz1P0wnjdCDxfZPyntA16faWctxrGh0eZaJiqTXy
+ECedbxXqCVExVlRKlk/vpMSLA2j4S5MShgDzfitRFIsnRPQuN6C6PFs9KYj4Ymp9
+mCT6HOHKt5K5WWqHYTCUEa3Uw7EGDo/fCduKj7EvP+cX5qw3P+Frb+Z5SgIBxvxo
+wxg4YGem5LR9dpVPlHnLwnEoVk97VcNTWC6kx2El+H1J+R8I2UnpJ5r83A/IQUf6
+nsV13h4bAgMBAAECggEARUCGT9zsUI6AJqpytdH5rox0KMJ09vi0xdU6pCYJ2Z79
+nVfU9OW2ROHuRVq8EVWFKaZgS6Qg3XRTwCqhD9shatYHGH4c9a9w9VgIU8X4ZKy/
+UMngDAyFp+nNapz0he45/5Dv4BMe3XG5K92e3roxSjVJOv+/m6D5P4eDSnSgTX+P
+dgSz4SyyRYbVBGP3RQHkGsJI/6BytO1X8KORq3SdkbO+nxBh1gy9rYATgbvkHMuv
+Rdfqrae/V8QFC/ORd+xCVTozg9OXGtdq4x1uDpaCeCF5sNsCYW86gA4xlpRh+Iwy
+CZQboVrL12wf5dQQVWpX2tRPa8Di28Eo3m32tJSTgQKBgQDdfRPNUlWPFvcNBing
+gr6Npa0u8tnII07hU+zxYbPeZ5mxNU4WqgKpt2VjNFKQMXJybLBE7uEuEV/p3VZ/
+S3gSjsSbQLt0/gLYY372lQ4j/HIIgl5+Se7jwlo5ARKM7C2115ild3kJcNUVtwQq
+OYXyk3xaNGLCZOUJb1AI3PrQdwKBgQDJgv7tjaRoH7/E0vlynip4STT6PF9OtFkc
+7ewBQS3rkOQh15qo7M2TWU/rkpn6+3naPtPXEJClbDMZPIYheqwDtxkI1z90zI18
+WEMtAYamVZms5uhh9AIlEfm/RAAEhFFUi+TuxJvIqMl9HG/wd+TpdQSuc6l2pT+P
+5T3ZrlVMfQKBgQDDmPWn2RId71X1dn/8+Pl29dzfHTAegq/iZc9Vy8agnjUoPb7c
+XP9FCeTLmyVemYxMaJeyCJNrr4RYb1M3z1oWaWZPBPeG9dtlZVh2QmPee83ondj9
+BiWllbk/pibPtLMZZ3AykDOflrlXF+zhrTMRahXjQ2gD7D4n+tlfOmd1OQKBgQCS
+rd+SWv/JKxMT2d3pKGgRlngRjdByIaScAjM/1onuZlEosR/KxlP9ZY1fFB8xKcvQ
+qNraORyQzOmE/SFFTV3YdnaqkMOH6T0zvatoHyw79yMdUBbm9g55nVQFfSHmJ8pr
+mEjT5BjhPrsrbn+sshjWNm9p7Jb13eMeguc6hENioQKBgQDZEI04snkHhxUXGUBp
+Xe0RgzIaysftZvKSx0f1q2Og3RrA8+1IUZgWJxR2e8jRNEQ6UmcnoIQ9D3yKYCrp
+8aDX+Q3BbeRH9u+aQhshaRxoCs9fncMamlI2eA7sPfUd42SZ+u0oS9NC7u/gZXWM
+qboNh9a8EgHRRpKzNFQXlsgaTQ==
-----END PRIVATE KEY-----
diff --git a/jstests/libs/tenant_migration_donor.pem.digest.sha1 b/jstests/libs/tenant_migration_donor.pem.digest.sha1
index d84d7be3f0b..10e26ee3b06 100644
--- a/jstests/libs/tenant_migration_donor.pem.digest.sha1
+++ b/jstests/libs/tenant_migration_donor.pem.digest.sha1
@@ -1 +1 @@
-37E0CE4CAF034EE5E4A0F79672C688CDC0299412 \ No newline at end of file
+C986231117F2A25236074AB84CA0745D1174968F \ No newline at end of file
diff --git a/jstests/libs/tenant_migration_donor.pem.digest.sha256 b/jstests/libs/tenant_migration_donor.pem.digest.sha256
index 8b912a93b62..15036268bae 100644
--- a/jstests/libs/tenant_migration_donor.pem.digest.sha256
+++ b/jstests/libs/tenant_migration_donor.pem.digest.sha256
@@ -1 +1 @@
-EC106EF238077F95ABD5C9E9A20C9D90AA85134C7C95AF2E50557DDFEFFE027C \ No newline at end of file
+C41D367CC956F5EB1493DAD938FC37FA034E35B31CA9DD778BA8A95DD6AAFE9A \ No newline at end of file
diff --git a/jstests/libs/tenant_migration_donor_expired.pem b/jstests/libs/tenant_migration_donor_expired.pem
index 7f0c696051c..97c50505806 100644
--- a/jstests/libs/tenant_migration_donor_expired.pem
+++ b/jstests/libs/tenant_migration_donor_expired.pem
@@ -3,53 +3,53 @@
#
# Client certificate file for tenant migration donor which has passed its expiration date.
-----BEGIN CERTIFICATE-----
-MIID4zCCAsugAwIBAgIEBWsrBzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIID4zCCAsugAwIBAgIEOD8fmjANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjMwOTI4MjIyNTAyWhcNMjQwMTExMDIyNTAyWjBrMQswCQYD
+IFRlc3QgQ0EwHhcNMjQwMjE3MjIyODA4WhcNMjQwNjAxMDIyODA4WjBrMQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxHzAdBgNVBAsMFnRlbmFudF9taWdyYXRpb25f
-ZG9ub3IwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgD6MZ1o+mH9iL
-LP3sebq/DIY9yumxtRRUdJcL2+mWtTrjWRH3e+D/unukcR9wRExCZdKCNqeJI/1z
-yPvwr6cKeUBohpY/vmn32H7gbYUn3PFsVImAJLFg+TMIOGBUKTAvs61KSAvfnFIE
-w2qzWB5fbA2sgOFFdw6Q35fC3UJoVXzcuSqWzOTIR5O8nDorqiYpBpNXhwjTM3wb
-KuhDo3I72idzukZeZ/+MFBNwxvrdkiM3dIvGizGsLiTCsxKmFXihIH4m5qM2VeuW
-F8J9u1hAwL0F2gA3wwPfQDI6MwOkldfp3LK99K6wwI3yBRf00Guyj8DOycLUr7uD
-xu2vnxINAgMBAAGjgYUwgYIwCQYDVR0TBAIwADALBgNVHQ8EBAMCBaAwEwYDVR0l
-BAwwCgYIKwYBBQUHAwIwHQYDVR0OBBYEFBtvfxJnkxRy7cIpYA2hma6W2cd1MDQG
+ZG9ub3IwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDD/TC3grAlc4Ru
+O4SBHtYZ7LmaHNi52sLZNIqXVSAiI2GzSbC9ASh+/Ycx7XYyJ68TDfKvcXoHFO1N
+hczRrFKe24o3NnQDUkBDwT66fQ8yrEvOkfsBwaNbhyvSzKQUmtSeMGbNlLd7RMyy
+7pwDMe2dPUeOF87TMcXdl/z53MCjykYYGG9nwbvFqcHiE+g2K5CDPr+y+AFzVaQ8
+/GqkqEccTW8m44iHek3pfaiZiEzYE72/iDH/jPuQkqZavvHaVdEMxa3j5ftzAYbi
+8znwZ0ou6zLmcedFqKQjtt38xUSHiYcP0aYq6ANZS0k6fkChlwHQBZuNi1mOVHo8
+mHJXRgMZAgMBAAGjgYUwgYIwCQYDVR0TBAIwADALBgNVHQ8EBAMCBaAwEwYDVR0l
+BAwwCgYIKwYBBQUHAwIwHQYDVR0OBBYEFKTk72A2M39hNRf670s95FJ9euoOMDQG
CysGAQQBgo4pAgEBBCUxIzAhDBh0ZW5hbnRNaWdyYXRpb25Eb25vclJvbGUMBWFk
-bWluMA0GCSqGSIb3DQEBCwUAA4IBAQCTQqiqyT6INZpuIi15mWlxbkQ664vrnKyL
-Nye6z7gPGYmd77nbERhBk2L6iOgXMhAW6eLQhyo2vkmv9n4s90WRcTtBvsSnzvCM
-SDaIlmsxjshcJH7voqN0dgxlpZ6ijNK7QdCie7mvqwEf2giZAnubvLg9S27E/WUP
-H0kdktSffDwNlTNQqEReYXpecrud9gvjJDZcHOnXtiHLyz0oUjit8xpOJevuxgjI
-sg9mcL/5KrvWpRVKW0LnKgBWH0fjCGtUGJH4wgQZmtECzytTn2hHa5fS2wGu+ucc
-koPL+ZBWNlQuwqm2sWimg63SeaNqkMCjekaohWRsuOddV1DJBPiD
+bWluMA0GCSqGSIb3DQEBCwUAA4IBAQBnQeo2acxbBDU2/zypQrOe8e3EzfDshT+7
+12p7kVOWvQ2REadBUye+vPkBisXKFVUsWdBjbpnZL4GfUVLD1O1YIEIxdqjhXMI0
+r75YxQLikSdWeHBRCXA97Sp4Be+/99N6JFuUYN4C4qwDYn0NmUPPknRjs2SC7nnb
+MbhxMVKdnPPsumV407VSXVEeJN9RuWi2kR9P3VFZdYYHwzQji3x9Gesbto43LNwe
+Iu+GGrSiRel/6pcuH0gEBGUSEQhhtstz6OPe/0io7o9AI5fqlR/JWUkNBG4R4BCz
+TUNmvPAChZob6QoFUYKYIskWeVhz6uCdZMfGn6pUhtJqGSld3L1O
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCgD6MZ1o+mH9iL
-LP3sebq/DIY9yumxtRRUdJcL2+mWtTrjWRH3e+D/unukcR9wRExCZdKCNqeJI/1z
-yPvwr6cKeUBohpY/vmn32H7gbYUn3PFsVImAJLFg+TMIOGBUKTAvs61KSAvfnFIE
-w2qzWB5fbA2sgOFFdw6Q35fC3UJoVXzcuSqWzOTIR5O8nDorqiYpBpNXhwjTM3wb
-KuhDo3I72idzukZeZ/+MFBNwxvrdkiM3dIvGizGsLiTCsxKmFXihIH4m5qM2VeuW
-F8J9u1hAwL0F2gA3wwPfQDI6MwOkldfp3LK99K6wwI3yBRf00Guyj8DOycLUr7uD
-xu2vnxINAgMBAAECggEAAilLASCzvKSw4upwx4yBeDVIzvw91e3awEFq/ypi+bJ+
-cq6sfpm7yuEaJYdaoH1nKKfr4WEFcKyS50ktbGZOWp+S2q9cVbBZXr2qCHr+jgW+
-kev2h5K3RHMeUcpDUIFkUa3pJxDKinm3ngcumkXpnU121D+J7rzq4AuXikvKqu75
-VkudHlUEEVbC3nWe6phjhXcaMz0rrNPH7MjGS7p8BnX+/bTk54HdEb4cVhXEHSfu
-UXAHj2rYek2cfpjxGxZfj7TfecUb1i2Mf9jfNFGlaoOGAS6TJWTBKZTU+NXpMFeI
-ZJ/CDUV5vO31cuWefp+7tFnUQK4XC0jJXvjL0FJtbwKBgQDL3/pPKDiiEXUjrCVU
-XElhcW20hJdmMxy2q0VRxyx32q5f3bEj2SzniwXWpGyixqKOX8oX4ts7TxnjERCJ
-chtbEAaiU+m2S7apbRdaFjxbK36xJJChYZSYd3It7+zvFkZ4vROoTQTDhY2JLDuu
-3qSTI/KNbXmJ4TbfiflL23fR0wKBgQDI+/TJB6bV/EiVB178wv7DkfRZRN7yKbRL
-KemtzgalgbWSqzwc9MTFSVctrszgAt2rXT8Y0ALbPYmahiHXo4B+MlTV/0WufjCe
-00hDi7dAJo1Z7V2GgoK6w9COgNJPwPeN7eL+SGGe12UNPFdeHrQZluWrH/b2OieO
-ynT/HuVAnwKBgGjdxnTc7XR/ok89Bt6DscMLgzBtWyrYc5aKNlfAKWFk/HiXIbyc
-wvo+ijxDyxVXMtok72Cl8bpqD5i6eFUaenO2pJLusrJv837mfDJ8aYNDtiEL+9Dm
-znY2SmbSmH7KaGlGaEwTgbXIhmrec7yZDPIadXLFstR3IbCN2ctpEhK9AoGAQyVh
-/3ON+nmhqiBfTKS8xovRja1jqpXiRSZIiqeFMvAlwE1y9N2Vi6/X70wx6Dks455w
-gRKlkad6fGSJk+hs+jxIeYIiPoysI7PEtcRMwaLfoIabs1+Q22KmH6XMHZcDXah3
-KKr36kBd41EggzJQyyfNrSEtuc9t/deHxOAGiVMCgYAs1ny6A6BhKFIwvSVWPgNL
-b9eFNWiEZ3+LykUWF77GMEx0qfaOvyo8nSrXWKmRAiPG2XykRZic36UwHUPYf7jx
-1rBe0hsP43Azjg80VMXYE6omtEAcHmrrUkyYYpYVDy7DaEMsx2qnyom5Ac+tHf78
-FRWLu2C8dJqc1L+QE7K0Sg==
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDD/TC3grAlc4Ru
+O4SBHtYZ7LmaHNi52sLZNIqXVSAiI2GzSbC9ASh+/Ycx7XYyJ68TDfKvcXoHFO1N
+hczRrFKe24o3NnQDUkBDwT66fQ8yrEvOkfsBwaNbhyvSzKQUmtSeMGbNlLd7RMyy
+7pwDMe2dPUeOF87TMcXdl/z53MCjykYYGG9nwbvFqcHiE+g2K5CDPr+y+AFzVaQ8
+/GqkqEccTW8m44iHek3pfaiZiEzYE72/iDH/jPuQkqZavvHaVdEMxa3j5ftzAYbi
+8znwZ0ou6zLmcedFqKQjtt38xUSHiYcP0aYq6ANZS0k6fkChlwHQBZuNi1mOVHo8
+mHJXRgMZAgMBAAECggEAePpjBgPvw05pIroucp2cP2h2sQC5bw/wUq8yFXQAX9JD
+Tq5gIGsEmk7ZEyKnYRJJ6ZMkiNOdJZ3vVXkQEyUx4slVqfs85YfyD2DL3cWwifD8
+4kgODul+ctMfZAHaDrX8JKFv89qm37p6OME9IGPDbtoSv01G5+rDXqOhDoMLjo4J
+IC+WBVHFCfa/k/ddmxeU0FIgI7bIC6jF8DYVdsSGNXI7uWlKW2MwkxBP/+qy8fEM
+wyQbyiglIVTZD9G/9EPfqEjrYNykoNwzHogp498snA1BYl33YW8tNs5UMo0snb3f
+rW2DnPKXeC5nAqP1+JjRG9YsH8dEkeNUh0Nz62TA4QKBgQD69NzPiHpLMpxbL3uO
+/0rzp2lc2z7lid4o21KRcjPx/nGJ/cCxEtUp+FlP1QC+zucdbQqQAnpHudIUQESq
+qxMEbrMt1u25Brm5J3PavS8/Xvu5oKNsCWtEgRazRRpG56lEX19Hj8P0cFkNX8to
+ixja2hezETCn1WjuIXGK91uQjQKBgQDH7YcK2b/jUY6c3L9YbUEUfLcSPEJhntB7
+5OjhDSGEC+wQBHBc/Q7fLavz66IaNqlJb2euRrVHH8eN9eiHal3/jutBRsvm9Wth
+el9cfcvKF7KjYfvUp/4MvHxHnnXglcXtIwEm48y20R15F35ateT/4ulQa4Zx7VFq
+ZgByQpY3vQKBgQC4JtSdqZ1r7uCTfR1jCm0arJ+BVxUpZOjT/FTzi+UYT8lLJByx
+E4u+d5I6JaidW8B2dFyK3naSiYXh/GMnBdA3sW/kVFIvMwM4Hf5C5g50pyN6zKj/
+D05af4uD01J782TfWkjVf2agyYxfZwshVOjRN7aqXRPiJJUSIRJrkiXrxQKBgHRw
+UVsvcMOa511Sb5q3ntSowhK7x8mFLlVJ/5u7Aw8dxnGZtDtkIvo2ZlRcov9zYGrl
+mFP22HNA/f8e/juH5pEFktxkuDKeMtkF5W4/0aW04ZSoZ3v2D08po5QupOaVND4l
+SfF1cO/0oJ664RtBnsqtREdTKG1H00gNeisRvt1dAoGBALd/AeQ/Svzq8ALAn2FR
+LfCQ4FxT/hWgtVnc6bjfifTEudU0KDga/ZKr1E7mdNPX12YA0CcKRSJpyNxDNTqd
+fjDuOE62EzuGjIMIUC4RXTQn5fvdI83+jEGv/K39LVMyz+rjJVRctVObPnA3SI/E
+QgyLq6gGyXyEyovAWfCw58uG
-----END PRIVATE KEY-----
diff --git a/jstests/libs/tenant_migration_donor_expired.pem.digest.sha1 b/jstests/libs/tenant_migration_donor_expired.pem.digest.sha1
index 6625061bf44..b687bfbb3c5 100644
--- a/jstests/libs/tenant_migration_donor_expired.pem.digest.sha1
+++ b/jstests/libs/tenant_migration_donor_expired.pem.digest.sha1
@@ -1 +1 @@
-CDC8DE4CBE00E68B3A974683D3AB048ED736B000 \ No newline at end of file
+3E6C3E5B26DDD71A3AF311D0752DF46C2529A55A \ No newline at end of file
diff --git a/jstests/libs/tenant_migration_donor_expired.pem.digest.sha256 b/jstests/libs/tenant_migration_donor_expired.pem.digest.sha256
index 476cc1e6f09..2842875ab15 100644
--- a/jstests/libs/tenant_migration_donor_expired.pem.digest.sha256
+++ b/jstests/libs/tenant_migration_donor_expired.pem.digest.sha256
@@ -1 +1 @@
-DDA75E73AAA346C1CD1294B2463B432CA067E5322AE9722DE3D7E002D6CDA3E2 \ No newline at end of file
+15625A417472F9466DC4152AE90FF33A443DB18ECC9A6B1EF78071062FDA121A \ No newline at end of file
diff --git a/jstests/libs/tenant_migration_donor_insufficient_privileges.pem b/jstests/libs/tenant_migration_donor_insufficient_privileges.pem
index c745fdd2e93..9bb0c63a8a9 100644
--- a/jstests/libs/tenant_migration_donor_insufficient_privileges.pem
+++ b/jstests/libs/tenant_migration_donor_insufficient_privileges.pem
@@ -3,53 +3,53 @@
#
# Client certificate file for tenant migration donor without the required privileges.
-----BEGIN CERTIFICATE-----
-MIID2DCCAsCgAwIBAgIEQ+PqZjANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIID2DCCAsCgAwIBAgIEZMoFoDANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTQyWhcNMjYwNDE4MTYxMTQyWjBrMQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ4WhcNMjYwOTA3MTYxNDQ4WjBrMQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxHzAdBgNVBAsMFnRlbmFudF9taWdyYXRpb25f
-ZG9ub3IwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDr4hsO5F9tEJKX
-duodvaBfswGGUN5pseMbXP6ueyKJodqRDiTZqhU+7fU/MQVz6eGutyqo9znFjACF
-xiUUcT8Nx5j7gSXqv9/PgrSr6VfAB4q99wEVTSwAKM5avBoUd/Oo61N0PrPMzISx
-/Xv9ZVmPF4FLyFl+uCivDILU1DUfZV4G1lgGqLopzkuL/FPyQt7zYKMlz6lggHjv
-NdR5w/12fVJ5nJpb2jQtEOi/ho1eP8cljJHwoWVKAu+jVrIge4EFvP2mPunOJiek
-FCZDOejqYTzCP0DRZ+N9Wvl3uX1TYRndpkEAVnn+u3nSJJonjsjZvgGLgRBdHKeD
-ABDsUHcZAgMBAAGjezB5MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMBMGA1UdJQQM
-MAoGCCsGAQUFBwMCMB0GA1UdDgQWBBTS5qLQeIabxC1AlZzGBGa3zAAT4DArBgsr
+ZG9ub3IwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPcW71Qt9Vxphm
+OBQUJHxf2x1MFRVMx0MSrV6AsofpfZvDEkhlvCwTeFkxtrWA7rw/+pcqsVRtkIYs
+AsGJl7/HL+BySrcOznmdt0pLIteiDVkFaJDJAPWBrZO7CJR/gcb4/Qv9WEDic3xw
+ombUANdInbZbNj/dxre0tw4YA4pSRTOUf6ubazL7V3ZLx7h13aTyvLXe8PaITjE1
+FUv5nlVsK7OAan9K89bdazOcPSBxsCBS2t6cHt71hn1nRywSDQ0AodZH3twfTij6
++Agxvc6/R4mvH9QE4kcWJEntyRVYGOh4uJ3tkSPs9VGIDpoHy72smnwF89n426K3
+IABAGDlhAgMBAAGjezB5MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMBMGA1UdJQQM
+MAoGCCsGAQUFBwMCMB0GA1UdDgQWBBRhTVyJ04R4YdPCk5mjA5uEb5lzcTArBgsr
BgEEAYKOKQIBAQQcMRowGAwPcmVhZEFueURhdGFiYXNlDAVhZG1pbjANBgkqhkiG
-9w0BAQsFAAOCAQEA4sMIjDnr62CgwZeTTS0yynPcuwbLi5rdCedBGlxU8XBOXQiF
-5H2YocrBxNM/VzFBnZmq5jggYLipcjcR6xTkuUPiGjuBIYgeQXV/melI/v37ww5U
-V0SVXCeLs21NkupiyQid6hem3qlXUO8u/53aP4m4qRl5Wb19AAR6lFVDV0i6apYS
-JfbdLvc0M8LLsWI/fNDj/3RvFQHEMsn8LWavnxaatVPkfk4xY22gSsUKMXO+DE1h
-DXQF04zM8IFdKyXOtinCOm+EJNJbeOjowHfudR0YYvjCHJPYHbcZUWpqwG1oeLCr
-eKgZwtvwGVSuwrME2jEh01KC2cFLs9Mpogjs6Q==
+9w0BAQsFAAOCAQEAYVViej1FdhX6Wd3EdpgKK6Pp8HuwH2kMdHekxDWKhB3xCEPb
+Eguk51eX3yYiurm5SYWHGKy5p1j3j27vgpW0Q9tUgpOn0+qCJhUAqfxtqLZw0iK3
+2IzxKy4hrEvu5sUjO1/1rCw30d2YIxAw+23PPE95sD3AnqGNYhm0sllaYuCq80AC
+jFs1ZkiUcWo8KaV5d3Ioq59IaIk8q+lY8/O28Ym56pxZGxYCIQyWhz1YfXK9F94L
+m/OWnnk3PFP0UHUAoMMg8wcsUdIDHKyWGrwlyRvtv/uagZ97MGakFSB6oge9gBgz
+AvsJzpsKcy8iTc6vXqDBf1XAfmaei2wASsaoHw==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDr4hsO5F9tEJKX
-duodvaBfswGGUN5pseMbXP6ueyKJodqRDiTZqhU+7fU/MQVz6eGutyqo9znFjACF
-xiUUcT8Nx5j7gSXqv9/PgrSr6VfAB4q99wEVTSwAKM5avBoUd/Oo61N0PrPMzISx
-/Xv9ZVmPF4FLyFl+uCivDILU1DUfZV4G1lgGqLopzkuL/FPyQt7zYKMlz6lggHjv
-NdR5w/12fVJ5nJpb2jQtEOi/ho1eP8cljJHwoWVKAu+jVrIge4EFvP2mPunOJiek
-FCZDOejqYTzCP0DRZ+N9Wvl3uX1TYRndpkEAVnn+u3nSJJonjsjZvgGLgRBdHKeD
-ABDsUHcZAgMBAAECggEAGKT5SP1m82sId8rwo54S3gDCq2TyUdZoKQ0WnkXm6jyG
-7IIO609b9CTSK1GctVs1jSadrkTTLD6n9NIKgHfi+7Zzdy5rdtroYCKyq+XfmURo
-dFe0zSQQkW0x/xSZQHN2WXsJr3LYH/DrublnPYab3Gl7JJ7oa8cDmCNdXW1U5gRC
-vQsNKjtNPIhHnwYI5pM4Jf7p/hq7oEwpfXUu3uTmtUhEx4petUQsZ4XlOhlAnYYu
-mKlTRy6iI4WZecEPmwPLdiexQG/nGz3csjbHIxXpW92qkMnvzmQ73uB6eIAgxhMR
-7WnH9RWm7tVOHKR26oAzZYbbdVYls+ebfMhHwcc9sQKBgQD1PqeIh4+Ce6rEIlOm
-GFoRkkFdqOOPu0oU3XoY1HFLasvZQTExW8C7tgqIJ4NrvqEpQ6M7qzGJYHvv2Drf
-TBaYsfMZX9QwqyZ4uVDtICN1aiEtZwGM6Qb7WkidFG8lE7onU0RI18mIiFj/Jdbk
-fbpK7Qj+SWNmHHHMBesB/0OEKQKBgQD2Olmj1xLYE3ptRZoLZ+GIAxM5PiOzkzo4
-xQCJtOTwd6R6mMujMIyjRX9+36OUE47Q2R09CLoV4sK0A3NyjYdud8Jq53zeZdOE
-Ms4zvokgdOW6g/YKX7D8lYWbCW3v6PSPYQTmzSgCVGKtcqc0cUy9dPs6VTQB70y0
-W1zB8SY5cQKBgBB1Ke0Bm+HXxrfuzcpBrBmtxPEyGkNVAD2yNzVfXFMBUbi8pT54
-t9BhAQfuDuW2Hz6TqWqhrGtZrDeGPT0q8AFDP9seETFK6wQC+6lOFNMWUi+nz/TS
-1oMbpe/UpTjJwB5Pei+hO4cMD1zf/zHKNiw9B/N4nVEG66QTaZfyt2cxAoGAJAAY
-Bxp1CN6gMcXRZgWENgytDNuHAMRv6Mj08S1fo8D6bWpVq8B3b4/DulscYZQSd3qn
-Cbty6axD52nxwTfsKzybUmISIbolmNiMyYf8KKCuzfxpRs8C44tBA4/3YPJgf24h
-91TbmquX2eA/ji1amQC3kqnOdtH0FxKcl0aY3iECgYB/C5TCa9gYbGJ60ltr9z5I
-HlEtkDhS+hhLoblGvnoEvKfszxajFCKPlHNtg9tuIjJodoOehZeJ2qjRwKwfgPu2
-1T0cOiR+3SrG8T+0RiFnT52UNr84+cDZXXFBMQJyfX/tls6GJUecobauLc/+WOS4
-elPYfR8tPHf0A+Y8z34MCA==
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDPcW71Qt9Vxphm
+OBQUJHxf2x1MFRVMx0MSrV6AsofpfZvDEkhlvCwTeFkxtrWA7rw/+pcqsVRtkIYs
+AsGJl7/HL+BySrcOznmdt0pLIteiDVkFaJDJAPWBrZO7CJR/gcb4/Qv9WEDic3xw
+ombUANdInbZbNj/dxre0tw4YA4pSRTOUf6ubazL7V3ZLx7h13aTyvLXe8PaITjE1
+FUv5nlVsK7OAan9K89bdazOcPSBxsCBS2t6cHt71hn1nRywSDQ0AodZH3twfTij6
++Agxvc6/R4mvH9QE4kcWJEntyRVYGOh4uJ3tkSPs9VGIDpoHy72smnwF89n426K3
+IABAGDlhAgMBAAECggEBAJaKc0N5rCnLXX2Q5MFZWQkXMkOsaTC2ym4bcqFi7k77
+4LXH5tItpK7cf54cQcu3dNXZPSq2VdbNMxFtTpZTkdEzZWaL4hzUql1STpAIUQRB
+O4E5SRkVoRTiqnro1xtRStwWh0TrburndD8pHAZuNc105ol67Q48z8RNs+SpbRAV
+6G3skZ96xvEw5UdM+whraTeGosyk33TXlTq4lhd5N6g97gWI7WUxXm1tWqOmQz+Q
+P770TwwEDIEECqJ6wQdFNT5XXuuZMIkKp43ByKvADFBWKNPsNibFdqJccsaFcmir
+IUeRFx/Oy5fV2gJSpqpWKkNamRHC/+4wfwF8yfX1AAECgYEA/BpSUeRC5dawZgqp
+9egS2X0oqavTI03Na0GpTiilN0sjTHOJsFHmS1Zl/wXAR9gaymHkbo3UbsQOO6Vx
+gkM0tDJDXdgH8BcSrXRaArI+nE5Zn83VQKPOLLFOIP+4Y8K+59pl+XdpN1x8UnhY
+sCAccJLbvmhi9LaUS8mbAbmC52ECgYEA0qZf0iLqmlS1wXNxX2XA4b/RI6aF1uEn
+4iTILnmw/pmpKPrtXdxWbbE+QuwAtL3SfJJVvkvwIr3Y0uzS7nrihzULrZoKA30V
+dMNTnq5B9qB0sILUno8if+P68yFZonqfqk8TvJ05TXW5Ru4N+AudcvF/4+qqxC5s
+0W1DIoKgkgECgYEA5p5tj9xwFjE/TRmUQQ/7rlmASTaV/0W9FNEMQCOOf/aMY/ON
+kW5abbCrvY9VRmO6nkjO3xN/sZRIMOg33iH8pJsWZVKqcEerHmHBtZW5EOPbuQRi
+gK9YfCn2ftlvpFMSsKZpgrxp0+sXD5poBzZYzeKKgrSbUaF0J6BV3E4IIgECgYAm
+T2nX3s/J96QCpcs1rVzR8b/Iew2WUeaeA1CA21LsSufv8wreaicx1e1b4G4UcP1p
++Hctn8PxnZNkcPu/sYunSWdxUDWIAuS3EpsPneOTRgVS4MhoeeGtXroSI7uYiDKn
+l7AgOnvkcYebtcnGld4xvGgk/FXITiUuRW/TQ+yOAQKBgQD60pI534bhVlWpWhTh
+12OuE/T9o7F0OudNz/fsL4O7DixLRC4i6BikVwQEvclCBsXWkyFrSDTvHkwIVcyb
+mUg9ZqcMR6E8l2yElSpx+xGHO96S408ZgyDvwSNhO826UE7XQpGHyqjaCO8Fl3mM
+eKYErW8Ib9pn+OGOIR8vL4PT+A==
-----END PRIVATE KEY-----
diff --git a/jstests/libs/tenant_migration_donor_insufficient_privileges.pem.digest.sha1 b/jstests/libs/tenant_migration_donor_insufficient_privileges.pem.digest.sha1
index 7fd7a283b17..7ed8cc1c946 100644
--- a/jstests/libs/tenant_migration_donor_insufficient_privileges.pem.digest.sha1
+++ b/jstests/libs/tenant_migration_donor_insufficient_privileges.pem.digest.sha1
@@ -1 +1 @@
-025F6E49306FE71D9720A3EDD3AF07E5B973656D \ No newline at end of file
+41CD7E09199F04BB3D9AB3C82846FED37C7FAD6B \ No newline at end of file
diff --git a/jstests/libs/tenant_migration_donor_insufficient_privileges.pem.digest.sha256 b/jstests/libs/tenant_migration_donor_insufficient_privileges.pem.digest.sha256
index c685e9a29c5..4c7f35b9eda 100644
--- a/jstests/libs/tenant_migration_donor_insufficient_privileges.pem.digest.sha256
+++ b/jstests/libs/tenant_migration_donor_insufficient_privileges.pem.digest.sha256
@@ -1 +1 @@
-B3682E1FC81A222A27D93A40B4CD00C7BC4931D09225B694A45ED34086851D9F \ No newline at end of file
+A4FB8FE50CA31B9AED14C3CF822D2B215739F70C2807ABFF4A34BF128986AE73 \ No newline at end of file
diff --git a/jstests/libs/tenant_migration_recipient.pem b/jstests/libs/tenant_migration_recipient.pem
index 3a42e616e53..9f9c599ba7f 100644
--- a/jstests/libs/tenant_migration_recipient.pem
+++ b/jstests/libs/tenant_migration_recipient.pem
@@ -3,53 +3,53 @@
#
# Client certificate file for tenant migration recipient.
-----BEGIN CERTIFICATE-----
-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
+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
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTQyWhcNMjYwNDE4MTYxMTQyWjBvMQswCQYD
+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
-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
+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
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCxBKDlA3mmesVY
-XdkQOEG8kR8P62Q4Wl/Uh1Lo85t/vkoohL/EwZYpc5NAc10hyxIHGKNXHvtICqnw
-nbuej+Gr5YO2cwFabO8Gr0vJ+4BWCZsTsA19Qt7TIBxiAqxFUqRRZ0bGFrYvkxwM
-BW//lB6Qpns0xokAgYNtwvMDqUJNp9BjvGsxnHZ/NrKSNsx1VnN2SbJM7ZHTsq3f
-iYxkppQizk3TGbkOfTdx/n7jW0alUBut2Z9ye54taUt7nyU6uIFCPAyv+cOXvN2Y
-SzPL5pVE3zB9Y98NgTBbyXQRL45YRiF754U6aakjbQ8HUiM4hJEnATZm5/OJ6Fsa
-Krfv2b+zAgMBAAECggEAEGMgTfMjaOEGseaGOLUsiLtah8u/zGO5aWBZsY0TwSCp
-ltSrOBi/wPidEiNb5Mv60ENco60PkBzEnKzNeKFTP+mQZuyAnJFnE1RZDMrGl7Bt
-9cWfihANtrfLSNt8fTJoWczYxW/Gz+KrfwVl1+ArcDKpRzp15mEW/KtGeflKVQvj
-ebgWVqcb8+mlYRI81EzFXUOOk41WV1ghLM3kqmmctMdBO40DSO75jzP/VULBk0R2
-Tz1FeJdyS37kqY3R3Qbt9KRtjrAQS4sHdlsVXQIcGrVWqyHQPR6rcX6QfDlzqDUH
-UvIUdGdfY9nA1jWMCGR9/3a+f6o7ZbcDU9NRA5aq2QKBgQDElCfa3OPofC1qkaOV
-wW5YR9yQeudvsRUUuMvYUnG0aquzugtfttLh4R44ru/ulZSOF7LTN+n7hKg/5zvL
-y9MM8/1xynwZ5CeSRioLfFlqdFEvhLrm93K4jHf8QAcTTJBc4Tafv7xPtL2TCfy4
-hrDnIGYMggRJRGb5nKyECeSRLwKBgQDmhs/C+ftTGyWVBVv75tp9v5/QzOwE0qKj
-yZINrnHXY+ok2EaPcHchXNNW/NgWsxypqLw5ZO/HPsBHb6hdEYbEtMNtktiNfUOP
-tBWblb6oZWbUmqDPSTOIuSpPvX9oiUwLvzcadNG7BWbWP0+rAMtraNkbsvvBkM6Y
-xepbRUpwvQKBgQC2f8FcfFQOIzLazCjtwC2cQeLwM1onpGQo38NHqoqrb5jGe4NR
-sd6oG6I+B5LykeXf4PqBA1jzy92Tri4ibrEaRm5WNSDvvJRMRV2FWkV9Ak3Y6sXF
-5ZaY5LgD9MFc1mj0AZX/yzadXPPezZfVDB6yBK8ZD5/BEYL0W9MBplmPuwKBgQDj
-C1Xm/9STVoJeUkf1Qrpg7XGW8a1nVpmO3UF3Lh+7dxGuNkDQl4ENn+Iao66kNMZ/
-JswzbwFl6Jzx/rwA5fkpFawA6IdWW1BGYaSCdyqvqidsL9tALSWPfGd63/VzXP5D
-95FrAjFqlHhjfTmW/5JZ+IsUZ+TjER8Zgpw+RnF5tQKBgCGhhKkghJM9QTdxt7nu
-/xnK37dBPN/qGW/DxiBRJZiVmNH0m4Bc/UEBK2Q3JpJgvTK2SJ0BPG9cdvrfDpux
-WOTRQliEWzzom/wdnz7+bGlt4bV7OQ6pEU28BC70eAlCCXVFKTPTjm85GLTjMva4
-Qbpey4LMpO9D6NEDMrFGuzxL
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCx3uUjRXKyPEKu
+Hv5rVk/AMtBwYSPqef79icGgUCnUgMAgYBagb/hHOzi8KfsVTeIrqq+4eVwZ/tFN
+jyWVQW5lfz3XmREqpSgZr5btknyqxnV6s63RSODT9TJQLttPKM00hxmNKQgdAAyA
+j1xZB9jTBl1nFaz1/7nG/sI39LQ38QznXo7kAsf04UU1RWzvjN+0PmT8Zci5j/vg
+BOTMYXkWx04MVK9sIgEyIQGAxMY3qHxJpi9CVn5CWUVrvIpDNL2FUXeG2O3G0TYC
+k4zPu705JopTgJWqkzzVxcwwsSsNuYQs42SklbSNVr9octWC2ZmyXsFivCO946Hz
+pputgnarAgMBAAECggEBAI1Asn0xMKWkv1thl7AMCida8zbbndcebMZRuKekIaP1
+Xx4W0ME2SlffCu469H91q0/8K7H3BpJKT1Mlg7YlEROfWbA2iXBxWggT7mraMxC3
+rCH2QOn70zff98W/gEA76cJ2K29zj1LgcA1ETBUT6zeiTViI2SM+ov0J4ZjoRppJ
+CvnDD50xqoD81DOq06BXWoATO+q2/lLGzFK8ZlaxKbBW03lvgFPC+u3aP96pLKTg
+UAMdH5FwvtwtsHJ/HRQV5uRXxeg07gt5wIg/pTJbw9KfgsVVKmMuPFE5+pVwfHtN
+o/zVGbNlFOu8OnIT8m2d18s91LoGcB5NyKj+npFcQ6kCgYEA4eqBJAISnMNschv2
+7zuBQc/k/rlPxs6mVg2F5MO/Z24n+UAyEAL+UVMNXxrM/nM+aGIc+MsqHdzUYFF+
+nPVIbRYc3l/ZZqQdbAbYzjpHx4S8eAW2OE8LfaztZFVgIPaKyVte8ytbYgqI1Db3
+nxnyAVSB6K77Z2q+ee1VjzVxZ7cCgYEAyY6FVZe4vC/ca0ASWiJtwL/jJqv68ab3
+6rAic8DhOYm6yz8Iue1AosI2UX52oVseDZJiuDnkpNeiD3orv8UXabsOKU7szjww
+DZjwYw3rhAdl6wchx0XVz5TK1KduuE+weNhKRoyrBpM6QoA3BTvK9zN6ozIpK9w8
+8aXw1rdboK0CgYEA3ro3/6wbdXolnIp9dXaRBLVV6twADt0FmKlUbCmgtvQfbNkh
+gi+xU7Qx5qWhnOs5h+fS8GY8a5yftSYjUdNxSDsY0xRkXZFHgI1vikJjKg1vUlUv
+RWyIw6qNkPGrCFSIl+QBRHRmb847AB4BG1aVBUKvoRuCuH7As6yNQddKqxkCgYA/
+XSHHrcHyz20Q/nyGf4pXbTvA/ZIPhDkuO58pGrrzdrwVh0R8Bv0p7bpb1lD/GwEQ
+rTOBzRl3RR76lKLKT/CzWY3zKI/DqiJFNA5mZYrj39uHjp9s4SR9dL5rKhPht5O3
++e8nzLM7hu9q1pn1eD2vhyyHv4437q3uHgffyJbypQKBgQCqFntbZ+sD1p99nFs6
+25h2acT3JyPwmy+Uw2LYpLTIOoix+wpmzQFwZgEDTSmi+O90JbLpOd6Wes/HPrIJ
+OEK5GTVC/RaZNxojANf9JWg+C3uRs36Q7jdXX/G5824G/pntPl8tjCCnGrYAyQSI
+1a9duTqVdnbQQF3t4Jvf55mgYA==
-----END PRIVATE KEY-----
diff --git a/jstests/libs/tenant_migration_recipient.pem.digest.sha1 b/jstests/libs/tenant_migration_recipient.pem.digest.sha1
index 4902f7b880d..7f50f32f9ad 100644
--- a/jstests/libs/tenant_migration_recipient.pem.digest.sha1
+++ b/jstests/libs/tenant_migration_recipient.pem.digest.sha1
@@ -1 +1 @@
-491A525D18BB583F2BA3D706D89271B06DEC8152 \ No newline at end of file
+D5AF0896B086107B3EEDFB579A7748C24B23C0DD \ No newline at end of file
diff --git a/jstests/libs/tenant_migration_recipient.pem.digest.sha256 b/jstests/libs/tenant_migration_recipient.pem.digest.sha256
index da5e8a81a7c..3da24ef36f3 100644
--- a/jstests/libs/tenant_migration_recipient.pem.digest.sha256
+++ b/jstests/libs/tenant_migration_recipient.pem.digest.sha256
@@ -1 +1 @@
-45935AD86C4FE5B134434D563C370428D993994C3EDBE82ACC9B615D5DB59505 \ No newline at end of file
+DD249EE9850A5A78E4666A4B8DA3CAEF612FCAF56F4C3048CA2C05C1CDF8FA01 \ No newline at end of file
diff --git a/jstests/libs/tenant_migration_recipient_expired.pem b/jstests/libs/tenant_migration_recipient_expired.pem
index c79e8f6ddfb..f609209e8a0 100644
--- a/jstests/libs/tenant_migration_recipient_expired.pem
+++ b/jstests/libs/tenant_migration_recipient_expired.pem
@@ -3,53 +3,53 @@
#
# Client certificate file for tenant migration recipient which has passed its expiration date.
-----BEGIN CERTIFICATE-----
-MIID6zCCAtOgAwIBAgIEeTx9RzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIID6zCCAtOgAwIBAgIEFIcyAzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjMwOTI4MjIyNTAyWhcNMjQwMTExMDIyNTAyWjBvMQswCQYD
+IFRlc3QgQ0EwHhcNMjQwMjE3MjIyODA4WhcNMjQwNjAxMDIyODA4WjBvMQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxIzAhBgNVBAsMGnRlbmFudF9taWdyYXRpb25f
-cmVjaXBpZW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlkdjLLOi
-jbPQbxjx74lG5Zl+nZ3XFT5ZINsyqtrmMwZjUq/5a9oDx6pxeQ63lOzp/fIuXqRB
-n0HGmCPnoQGokt3+/QslM3ceSbC2Mmg87OAUgomuHP1i1uyQz+KBkytrWSzUzqT1
-3KC47gGQ7471bVioqWxoBM4t+xyygxWZxvu91oTFXUaORGLJ8syQZDR6tnUJocuo
-CShi0Etu3fnzc9DowUdQoHhiOTJQ7VIc8VAdQdMAfU2it5BcoO6ZG6+a54IWUjQZ
-MFiMnsCoU1dgk6Eb/TdMSTKbldDvayGrk3RVItYDetmOD7VGvrEgNz+s+AJUR/br
-Ks+7+7APUkjoZQIDAQABo4GJMIGGMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMBMG
-A1UdJQQMMAoGCCsGAQUFBwMCMB0GA1UdDgQWBBR3swiHitSEWxJc9yYrktc39fHa
-UTA4BgsrBgEEAYKOKQIBAQQpMScwJQwcdGVuYW50TWlncmF0aW9uUmVjaXBpZW50
-Um9sZQwFYWRtaW4wDQYJKoZIhvcNAQELBQADggEBAHyAAy02YdADFwZz/bJjmlej
-IckwQP7+be5376/RpKwTyob+qI2y+jlrIimhGvnFxAmAwLNVp/y5HqoxNDz5Hr8s
-cwvAUNwyjSk9jVsnFAvYVt2psXkskzfVMDarjgJNHjummY5VKwtqwiUo1kw7UsPs
-yyHq83qQVgR7khOFSG2o7foC/lTDmR0rRcd4LwPQlDbaw2hfuClKWub+d3jc0Yc5
-R5hOPXqigqvzoo9CL4iaFL/qPiWVwtusLxvJqrnYv6fUV+J0Dkn7ldtpGkZ3jHCI
-+aGgVYjuB8ENJRxj4lgBtd3VyWsCMMMKghM+3OrTVlRk49/anPCr9w1wNVdggbk=
+cmVjaXBpZW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmqT1Ht6F
+dy6GfAW2owAdBLj7EGhYReWMRyug4hE4Q58+6MqpzX3fzPO/TSYoNkQXM4twtpak
+ET3EAIZUW8nFerQEDJV8s4m5ShWUJT+hTmbpbglHYRuTrgGQogq6A6me17zyC4ge
+kpbct8NOfOVtSp+IN3bltFpKXjbXVF40dHL14rQ0XZKmH3nQrQx6jE6T7ZeD7J2O
+lkUXhGJfl/v4s5McoRgzRFf+E3VQGVWJYUV4rGuAPfZC4Mr6qGCrqFRCzyjPLUkP
+UlV71WMAOPYqE0ajFJ/MljiGcgdTqGJK7oz8ZVrtSCyIYYE7GmWXcYOkuB8dXyzG
+BoXrqtQOPkEX8QIDAQABo4GJMIGGMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMBMG
+A1UdJQQMMAoGCCsGAQUFBwMCMB0GA1UdDgQWBBTaae9NrS9EaNT1BVH8JQYoV9mE
+DjA4BgsrBgEEAYKOKQIBAQQpMScwJQwcdGVuYW50TWlncmF0aW9uUmVjaXBpZW50
+Um9sZQwFYWRtaW4wDQYJKoZIhvcNAQELBQADggEBAB1GZ6+s9Ok+wRPBwTHv1LjS
+A0Bm8iL3rtE0UEKjN9Z0Fi5tgKbaurfyJDn3I5GnyLONCCVT7GatlZoHQNfZaJHs
++Qt14/H+050PxtMeheY4cWvpQXpsyq8UJupOJQ7tbNx62bV7l5471Xz1gU1uHv+h
+2uMCbiVf8XRWJsvXAVI80LIK343/8iShc632f/vchJdafYp8W6mpddmD0v/iEERB
+M91J2LindHr2mdBBJ5TqWgUhjg4Bqyg5z/oh5wkAdchkZ/AU3w2gi9npLe+egvIu
+7um1ndabnRfI1SRyJmUeUd3mhYM7Ejef0f8L++GsXjDeHaOX2lRQcI5srzz8UYk=
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCWR2Mss6KNs9Bv
-GPHviUblmX6dndcVPlkg2zKq2uYzBmNSr/lr2gPHqnF5DreU7On98i5epEGfQcaY
-I+ehAaiS3f79CyUzdx5JsLYyaDzs4BSCia4c/WLW7JDP4oGTK2tZLNTOpPXcoLju
-AZDvjvVtWKipbGgEzi37HLKDFZnG+73WhMVdRo5EYsnyzJBkNHq2dQmhy6gJKGLQ
-S27d+fNz0OjBR1CgeGI5MlDtUhzxUB1B0wB9TaK3kFyg7pkbr5rnghZSNBkwWIye
-wKhTV2CToRv9N0xJMpuV0O9rIauTdFUi1gN62Y4PtUa+sSA3P6z4AlRH9usqz7v7
-sA9SSOhlAgMBAAECggEACacNMjZZlxN5LGGkTJf7M00wKkyUn5sxG2Co+Pt1dMqQ
-v6No+Gn4+y6x+i4dUZYEE5kmLFMNmf6eFHCd9KQIIWLb+YHpQkyA6AfPNB6o5ygf
-eSEBy3/lBNwOEyQ/4WWVEBXGl31WA3VZW4RDPHfowLzEnJlHdyONJYd62dud1H+G
-whRE6fMlKfMUQaR3yTxOz4wAM73xM9uMfuoJT/ZwyjMJWGcivDT/CqJamwVU3rq+
-hFOatyZZDpkAvtS5aH3vZ4zQ1lhn3RDlrzsPr4I9NWuus+xVPS+3oKSOEhXoJqWg
-PePiOOetoQWCIZXjDL9Q0js+OKdmA8GArkh/0zFrMwKBgQC72BOCXZ9cafU7jDFI
-+ghe9VQAUISGUw1Vs3ckWWd3Nufsg19ZJueZ/+2OQBepQvEIJFRCGjSFmsP00FVo
-jZ2L2hcGeIzO2llNzC5S9+/fgogqpYXavcC2tHexJu0D1iVe8anju4umtcPu+SyR
-PL252Lvj+waSIDZBtXAf+uwIHwKBgQDMzhAE7H4rEQ4n2oGHOj6X4uSKeTGq3Gda
-MplZBbJ1Y0OwGvgayZVzIsYB/hXg3tV5VW/2kIXeUxJxfpdpV8W+FBBk1EGvvxG3
-xoPs50CpIlCM5oO7OH8Cz0aHmb48ALRwH/RCPfzV4qVoAN85pa3alJ0KtzSaKilO
-/L575yzO+wKBgQCjD0zQK+k8VZZVnLrjuHgvxhKnOz3vRIUc0e8olJtmNzlYbCoG
-v+joG+vhQe3INp35DWA/CXRyTgiwqXCak+QhFK5MJbVFkvFWwVmtGCEYCr2dF5Z8
-bZ+uejY0h6/TVr+WDX4GfDUcAEkXVyHC6dFgVK21l6D6lA/FNnUgrbbazQKBgHOS
-qTmOF1jIRBu7U7Ly7FWb5Wo7IAsSW4Rr31t8OovB23Wqkm3TafHSIrkHIGOIfCD/
-VLJoNhMS/+pqDJmWvXEZM3Mi0HqTsTTq4pGyoiuPwLLydk4VgJ8eRufIm7CSmUBY
-1+b1whMU1lCNhWqrkyMxEDn2zslcl3kKaZfUCdY3AoGAeKh9PQOES8ITY7tC+Wi9
-kd6FLmEA1ZmTyUrEhVemsG29rZKxK+9FOJAPx31ZhM6uSs5p7RnEZIJRKpOQHU/R
-cKAgN202XO0I5/833/dgseTtKP9oc7pjG/FUIk4kEOnaqcuX+1VafOS2JyAkCu2z
-Wmcow8PNcvZSEZcJIw+wmfc=
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCapPUe3oV3LoZ8
+BbajAB0EuPsQaFhF5YxHK6DiEThDnz7oyqnNfd/M879NJig2RBczi3C2lqQRPcQA
+hlRbycV6tAQMlXyziblKFZQlP6FOZuluCUdhG5OuAZCiCroDqZ7XvPILiB6Slty3
+w0585W1Kn4g3duW0WkpeNtdUXjR0cvXitDRdkqYfedCtDHqMTpPtl4PsnY6WRReE
+Yl+X+/izkxyhGDNEV/4TdVAZVYlhRXisa4A99kLgyvqoYKuoVELPKM8tSQ9SVXvV
+YwA49ioTRqMUn8yWOIZyB1OoYkrujPxlWu1ILIhhgTsaZZdxg6S4Hx1fLMYGheuq
+1A4+QRfxAgMBAAECggEBAIKUpfKR/Wr820xgWq7ayqYRONbK9TbYNRJnsasS1Uqs
+bieN8cH19wOOEswnWy8vYdQBe4SCQTnZyOaUhykWgG0zEnQ5yhmkQtRe0kB9sUyN
+s7BZn29NJO96nNFnc1jiYqFTB6NbJk2rm+aDwYPPCvFHMnN7L02SLFfPwRWZknt8
+wzljalQYolz6jDu+fMraht56ciD00z9VGQa/qIwNm2aQQkMvX5mnBe27QahvDwDF
+JJOPjC8psu0qMccMxfkIxZnurWWetzjYZGR5oambBcH3KLbl1NEFCO9jyRtZxufU
+Z24u9Ri1lHq6OS0BnvlC9o+Rl30+oqgPu7FFQ5M1j1ECgYEAyiCTo3atCFZeCTv0
+f0HnsRRWcqSXTfovCtKOTrJbk4qib/tWOGLTcRYcOigbMYOSUuASphnyz2XcD1bU
+HxQ38UjejO7LAZFY4+A4sS+vJ20holJ5txNMo44e7eE1EO/QwWl/p06cJ0AgfTeh
+pYe11E76gA8qI0ZCvKg0lNMeib0CgYEAw9yOsdURgYpzBmojLcJSMMddJQvoyvk+
+WsOnaNgEG3BNicY/f8cH5k0LXwaZ+tP61e5gJzYy7qmu82FuqQUx9fHCwZHUcORK
+K8mr0+dvTlhGYZqnX6raoaNbgTzO1farsO5Ywy4SKXDXM3SR054yRhqQhWRfnpRq
+Q/dV68yxWEUCgYBDZsWUtthQdWx6K9IGNZXrSNri89u4lvrk4v2tZHCBLLOqH+fK
+eboEddkH06PtyPAcTrgpR3HekxrkypGFo5pcDW6ZFHABn9RCeNyuyTXhMdULafFI
+iVj/GT9bF8Q4V6AHPwTgZ6hOtmWfG9P9fNm3aHbECUqF5MIQYw7Vqej/CQKBgGmB
+WuCSnQ6B7PpMnEye+7VI/3TgWHNWFe/Aq2J/0p6RPUN1JmmHZkr5v6Fdpf6Gx/0L
+noIg4QjNIO/70Sd9I++PXtD05FI3t3ik90l7xuqWBLu5GmYfXAxsOfOBNQ3vBYeW
+rPveymvGXDZcmd07v2siDi285wE+g4u/JWqS5gldAoGBAIAozeVe1M+xZFeldxKF
+pkL13OS2GvioKgNtULMLIv0qQDHvSeJ08/xWGBS+nlZnzfGAk+kVR+5rWRv0vNaK
+kGJw7/8iqAK+//fthqgFLErW2F2kxg69rlvm/1RRwWG4bj9y6Ctxbi+nireuIL/Z
+cXWr54WtWgO4VZZZQjRISBkB
-----END PRIVATE KEY-----
diff --git a/jstests/libs/tenant_migration_recipient_expired.pem.digest.sha1 b/jstests/libs/tenant_migration_recipient_expired.pem.digest.sha1
index 4ba0e4b436b..f454514bd49 100644
--- a/jstests/libs/tenant_migration_recipient_expired.pem.digest.sha1
+++ b/jstests/libs/tenant_migration_recipient_expired.pem.digest.sha1
@@ -1 +1 @@
-FE18865C422236477FE3915D9C79FA4C6EA76E0B \ No newline at end of file
+E54A016595511F85C3DE35D130E298875AE74E98 \ No newline at end of file
diff --git a/jstests/libs/tenant_migration_recipient_expired.pem.digest.sha256 b/jstests/libs/tenant_migration_recipient_expired.pem.digest.sha256
index 248bd4fba84..97e9fb08b10 100644
--- a/jstests/libs/tenant_migration_recipient_expired.pem.digest.sha256
+++ b/jstests/libs/tenant_migration_recipient_expired.pem.digest.sha256
@@ -1 +1 @@
-6E733E3D3A47BEA905E0727E4650AF5DC9F1BF23A08EF484EE1EBCDD39FF8CFB \ No newline at end of file
+7C4EFFB547DDD4534473176B1954D792967C47E4DFA37C72A266D17BDCCB5B9A \ No newline at end of file
diff --git a/jstests/libs/tenant_migration_recipient_insufficient_privileges.pem b/jstests/libs/tenant_migration_recipient_insufficient_privileges.pem
index 3ce53a7b303..715d303c317 100644
--- a/jstests/libs/tenant_migration_recipient_insufficient_privileges.pem
+++ b/jstests/libs/tenant_migration_recipient_insufficient_privileges.pem
@@ -3,53 +3,53 @@
#
# Client certificate file for tenant migration recipient without the required privileges.
-----BEGIN CERTIFICATE-----
-MIID3DCCAsSgAwIBAgIECt91LzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIID3DCCAsSgAwIBAgIEFzyWVDANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTQyWhcNMjYwNDE4MTYxMTQyWjBvMQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ4WhcNMjYwOTA3MTYxNDQ4WjBvMQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxIzAhBgNVBAsMGnRlbmFudF9taWdyYXRpb25f
-cmVjaXBpZW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuS7545vP
-tlPGTjwd0W0wKc4/hl2wXMnFd5YPR2pynUy/V3+ShoarF4yrO3aTxorh7HqIALrT
-87dP6N1D++x4knqt6m6a+/woJyD/0FHcxbkbSlk2ToTb8BrP8NLk4ibq/f1IDL1O
-u7C6wxBH5k4wkOLOpV4qV1qCvsQ6HF+MF2rasCB4I5sxQ3PCkkrLBUmUmXYw+cl7
-DOmeqZlP/w+JZJ9+NH0PTkmcw8PXqfNrA5BBDIXog+3iwFDT+5PDxV8rcZEdevnA
-1XnUCIQs6Tpsa6DAaU5Wpo7kJX6Ih7QxEarbwcTCDkCTtWCNPSzU4OLgew4w6DkR
-9RskNh9qi9PptwIDAQABo3sweTAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDATBgNV
-HSUEDDAKBggrBgEFBQcDAjAdBgNVHQ4EFgQUouwEzLrbf6cuZjtd9Ay8JelZLZQw
+cmVjaXBpZW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsftfW3eF
+Ei7M+DMBdBC+/jIA/iu+ArJpblqM5R6zMhy5HBA1ug5AfAI9LWYZI84NnNAYhIdk
+OER1kyRam7DgxLTRUM84m1JzL1IHSmQapbgmLZeDkL+HJVI7wyOF4mnl6/Oc6WAS
+EqwifD9ZFkAZRz2EFSvNOpjqASya3dFS7P+fZ3wPhx7NwiciARQ/rc0oEjS4YqGC
+eMr5rqhmX31PsNPyxu2NuJuIaNkHOE4LNhrXOOXmGSb0n4d/wgyl6ruocxqf4fzI
+VMCXL6WoTVQ5OHoqa1BDARQQeG2hMVTMz/P7UZ5IGECpVa0hfVJz6zzhTtv7T3t9
+D4u8lIxiphbxWwIDAQABo3sweTAJBgNVHRMEAjAAMAsGA1UdDwQEAwIFoDATBgNV
+HSUEDDAKBggrBgEFBQcDAjAdBgNVHQ4EFgQUURVuSB3jtWAIyXQdmWCMmXiZs0gw
KwYLKwYBBAGCjikCAQEEHDEaMBgMD3JlYWRBbnlEYXRhYmFzZQwFYWRtaW4wDQYJ
-KoZIhvcNAQELBQADggEBAGLJRmY/aNJr6zm6uvCVlygjtf6YIkDI+XB9DRJIqj7H
-jlhdRx40I6siMkCIPz9kb55blH9SpnDwzeSu2GIsvsxIra1jq1oXeVriespsVG7z
-09OirtI4ujxOT7PVFDY6glF0qrKtrF7h8RjwYeStrCTs5vQn1AoujoZlye3NJnU8
-InTJPnyrDaGd3Aq14gZOmxeugjo3tESV1xEDfscBJHhxGN29dar/EdvtDubtTnL5
-qTfIzMtT5RG/ewyRU5uSoMlIE092IsiFE7nF7Ee1Wl9iVFl8j2MTm4YohqSwy7Bt
-b8FWXDw6XrcQWR+JE2qdgPwcXDUdWwrgYCx0cOIrPX8=
+KoZIhvcNAQELBQADggEBAHQ6ZG9x8H+VGvsPiUOOUc9zaA4LekYiyfDBXRhgZ+mS
+uY5cBmFTiC8vlMl405NmgJgjKWzlLoiManYZYjjif57cQOeX9bAgRKyHbHO5ACsr
+0BhkZ4SoCQIX63SqoWEDSITTKW2DroaNEc7XTj7uPK9BDkByn4M6oFjQzRgwQf9G
+LNDpCxMajl11WBaEqm+1Eh4jdh3qAi82LcfAppAqv40DK1rG2xuIIounT/j8Bdbv
+WEKpOWFz+oSm2aKO5tplSbigWus2t2AWnTNtQYr7BPhT7hym33oFH8YC3waYeri6
+LSle5Yn+Oy1itnVvRrfqjXCxOxrZsI4yJXe6gXgUA+k=
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC5Lvnjm8+2U8ZO
-PB3RbTApzj+GXbBcycV3lg9HanKdTL9Xf5KGhqsXjKs7dpPGiuHseogAutPzt0/o
-3UP77HiSeq3qbpr7/CgnIP/QUdzFuRtKWTZOhNvwGs/w0uTiJur9/UgMvU67sLrD
-EEfmTjCQ4s6lXipXWoK+xDocX4wXatqwIHgjmzFDc8KSSssFSZSZdjD5yXsM6Z6p
-mU//D4lkn340fQ9OSZzDw9ep82sDkEEMheiD7eLAUNP7k8PFXytxkR16+cDVedQI
-hCzpOmxroMBpTlamjuQlfoiHtDERqtvBxMIOQJO1YI09LNTg4uB7DjDoORH1GyQ2
-H2qL0+m3AgMBAAECggEASE8yD3DbaigLMqhhwlGe8WwSPQ7fW1QEUd5cB/hmWcrK
-mkl7tyDltPPeNwFl0ayQbG0qJxLMyYlGYDjqH3hmWlgiCfz3crazHRhTG46jpOdT
-YzQzsvRJB1gI41IOQsqMjvH0TNks4bgwLRPx51mXuDOAGm2LHgH/NKtdv4+FneyW
-/fFaGAe/kYIjVGQcZ1woPNn66Du2dbU+aykDLW3Ll+guqig3ddiIbYvadc6qYDH4
-TO6WknGPDUWtzBs4ZqMZZKyEWoEr91kEF9eFofwBGJtBA069B2aNRXnXg3HEtxWJ
-N5hAb+Uft56/pD0XWzMHvVabi/k0umHdXs2WrCCkAQKBgQDbOxay6ZQqdNEY4MVH
-wCp9sH40cUnOhnouoNOuALb95q+jAVvuJFAYiFiuO3Cq3FWA1VNSFRvY9AG1+/jM
-+jXSFZ5nT9Y1aDP3tuDZ2EY2VKtu5ivwVGcIMagq/oFKzvwmBwtYB5eI4jrlsEZj
-+np2yxaHGhA3PnjMA2Kpd/9cAQKBgQDYPgeBE9rYHgXWFvHcKxTHmbtr4Jw3s9wx
-FPUMCJHn7Jmp3jbOcVDzhIIGd5PuHd9ggY5qqpTSEvfMkL0vyULEqACRA7bGSdrc
-i5+UDibLVDZmv9/YvKtfC713W48fQMtT1jW0eOCJaMm3vxyI/v49Mno2gHAvDcfT
-bqer7/0ltwKBgQDVt8/UELNZhFIHT6/i16pUp4cQ9tP92sknxa82dQnvkUDtxrho
-+st+bwUMrXOTjYJpOw2j+mIQaSd10rLkmJN5P4wRqRnpLLFkrsqadCVWd8o8LXTu
-MEnVChun9j3ywL+9Dqb3ZUdLsUe7fNHSS2+xeSB4Cmd+g49dS3uWPB4cAQKBgQCi
-9GOdTsQNNtq5EgNjIgf/vobxbYrroxuc1Skwz0h8mNzXmMB+ZABX8pQ1oWkV+Ob7
-h8Y19aQ+htK8Epqu5yDsp5n9renPlZpbttAjt2JeuXBhj9h1MQCHmIZH6vR43dAb
-toI0JR84DYJteJRdXKNkpKRabAGeQ+lBGNM8C5ceEwKBgE/UiIklDeY6FelUz0Yh
-filG9chmS1zddiJOvtzyAxgTy6jFYkF/JCtqR5JVRmJWXGHHrMC+KGpnXhYFiszd
-eK63i8mT62d0LUPM9g7BTmc2RP5SY/Z5sD6yXbXMs8w1Z9tyOczfozkiyWnlc53w
-gyBvHxvAJSZY5pKyaiwR+Z6n
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCx+19bd4USLsz4
+MwF0EL7+MgD+K74CsmluWozlHrMyHLkcEDW6DkB8Aj0tZhkjzg2c0BiEh2Q4RHWT
+JFqbsODEtNFQzzibUnMvUgdKZBqluCYtl4OQv4clUjvDI4XiaeXr85zpYBISrCJ8
+P1kWQBlHPYQVK806mOoBLJrd0VLs/59nfA+HHs3CJyIBFD+tzSgSNLhioYJ4yvmu
+qGZffU+w0/LG7Y24m4ho2Qc4Tgs2Gtc45eYZJvSfh3/CDKXqu6hzGp/h/MhUwJcv
+pahNVDk4eiprUEMBFBB4baExVMzP8/tRnkgYQKlVrSF9UnPrPOFO2/tPe30Pi7yU
+jGKmFvFbAgMBAAECggEAPtQs+l37xMpuouNmjPFoatV+EjugzNTscP9YI32t5m/L
+TMPQI4jqbJxhukgDcedIWOYA8a/VyiMomjPIJJPRFL978JnmMrZtYPQFDNa/rWaP
+W6LT1+I0tBEOdblxhta5SozqBFxcpOjNF61JJpikE8j8enjG7vuSB64WUV2Wd4DC
+cuZZAMvvbHc2k9Yo7WPvpoqMOXN9BBDbIhWTRhcIYafDGCjQ4AKplWZe85qlru2B
+rBd+bndMPZxfiCd8L6OvxzgOkRKSYAPIcAzM28Qij0mLkpkX6qCFoBrwBGDJAe6W
+bJnIkGcuSzHrfvf141oQ2aHDxQ8GPQfNYC3oTVoSuQKBgQDh8oU1loS/OipvfWEY
+DhWr2Vc7f/Egttv79A5aThkm57xKVrBzlA2OCU4rdlvr0ydf8GbPmSRfzkHUrsxf
+U0u6w3ZobV4OFlsF8PFD7nnOBj7Rdg40+LShTZWvF/NB3vkcwr46hI8UEupSvAeN
+tbAkT+J7dcaz4/cIXjesQ5pODQKBgQDJp6Kntka7MU3Z4oiwJM2G+PW2eGWpnFWf
+DaPvi3kts7kvAbTf4osEV6+5iEbkYQYG9j6uVHtA8S2fEwpnuzadngbsUcjLJTLq
+ZsJTFHiYozK9dtmAnnAj7RpcAN+Hs8f/VP1GcL2agG0yiKSvqfhhjd4TH3cdVW4a
+YUuIqMVLBwKBgQCIjN/ylefeBdIVlQlz1zdDp1Mv00+vvLNQHpv5+Y770zsZFjEH
+eKeEep0yaRJ+gBsgwRHxTpUMDYP9fDJpPdbbpTtPOyGHk/0opwe4TUxxtZaLUjSd
+0NyhS1k1+1x5J78XoZ4DkY9Cy3evzpEmFHLCT0EJ6hDPMOtftEkjI6wClQKBgFCc
+OIM+dCvkW7Cbw/RV4erwnpigrFMO8ZMxSrU5VemVDJPj5MASuWu0+cP63AvzVQt3
+aDsb/mFJh+ktHV22EvES+MWDM/cxGZdmGIxJhKPPqTrfxbaKn11dLMpWdwSyM2K4
+QL7l1oVqjTxEL0Eheu7UXU/bpiwNuIPHHQC2JpgFAoGAL7syfuv2wRsyNTz8VWL+
+kj29I9heysjkemfnG2chKNZzxO2P/ALH9KNFJ2+RyloF8+nSLxczgCF7ZjhYlw5T
+L70y94W1bfp4e/XqDsfxRgs5a1GsjG0PtQD2Jhaa9XB3cWVh72/3di1Sb1BOvr9e
+51kmvd/NnSObADCGdA/kLtQ=
-----END PRIVATE KEY-----
diff --git a/jstests/libs/tenant_migration_recipient_insufficient_privileges.pem.digest.sha1 b/jstests/libs/tenant_migration_recipient_insufficient_privileges.pem.digest.sha1
index 45c4db6ad82..7d17e50aa44 100644
--- a/jstests/libs/tenant_migration_recipient_insufficient_privileges.pem.digest.sha1
+++ b/jstests/libs/tenant_migration_recipient_insufficient_privileges.pem.digest.sha1
@@ -1 +1 @@
-E1C374F8419D4D25F3A3B7BB879EA468F9861586 \ No newline at end of file
+95766B6B8637771FE52FEAAE1AFFEDB2F298A702 \ No newline at end of file
diff --git a/jstests/libs/tenant_migration_recipient_insufficient_privileges.pem.digest.sha256 b/jstests/libs/tenant_migration_recipient_insufficient_privileges.pem.digest.sha256
index bce5fea27ca..91393d00e2e 100644
--- a/jstests/libs/tenant_migration_recipient_insufficient_privileges.pem.digest.sha256
+++ b/jstests/libs/tenant_migration_recipient_insufficient_privileges.pem.digest.sha256
@@ -1 +1 @@
-D63C75EF0C76E52F7B7C2001FFC80AB98C09BE29B0E3BF13796A07E34DF12B7C \ No newline at end of file
+30BC29924DEE62B5DD2FCED7E5DF7ED2E71ABBDFD2476F150FC2FD6DB907A8B7 \ No newline at end of file
diff --git a/jstests/libs/trusted-ca.pem b/jstests/libs/trusted-ca.pem
index b26763396aa..7451f78944a 100644
--- a/jstests/libs/trusted-ca.pem
+++ b/jstests/libs/trusted-ca.pem
@@ -3,52 +3,52 @@
#
# CA for alternate client/server certificate chain.
-----BEGIN CERTIFICATE-----
-MIIDojCCAoqgAwIBAgIEfeXcIzANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJV
+MIIDojCCAoqgAwIBAgIEDSAeGjANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEfMB0GA1UEAwwWVHJ1c3Rl
-ZCBLZXJuZWwgVGVzdCBDQTAeFw0yNDAxMTUxNjExNDdaFw0yNjA0MTgxNjExNDda
+ZCBLZXJuZWwgVGVzdCBDQTAeFw0yNDA2MDUxNjE0NDlaFw0yNjA5MDcxNjE0NDla
MHwxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazEWMBQGA1UEBwwNTmV3
IFlvcmsgQ2l0eTEQMA4GA1UECgwHTW9uZ29EQjEPMA0GA1UECwwGS2VybmVsMR8w
HQYDVQQDDBZUcnVzdGVkIEtlcm5lbCBUZXN0IENBMIIBIjANBgkqhkiG9w0BAQEF
-AAOCAQ8AMIIBCgKCAQEAriuvWSir0Jv40+VJsUsYmurNHP2rrtNs8a1cd2kPaI0Q
-6OkoKDx1oPNj3RCs2hz2JZISozLdm7NmCkitbrp4vjLoYcviw5ACb47eCsN5zqWs
-CDTSM7pFVV9Z6CdHYUD1+bGDbjSX0Zm2ipTXUYSzLGY79VhVbVYJ40dLzLIrH/5J
-eZ9FqF4FR7qOai0sjG5Xiu3r2NXsXYyP/pR8y42U7YUo3coXNjSVxEiWAltMTzUh
-psStrdBuZTzxMHY/r2GFy/xMP7QRaf41eVduBzYDfG7OyZMQQM99fgAbI9faiUms
-0MxIAqJ/7qtvjvWWMnsEjHaYHsLAqORKs+P479Q8rQIDAQABoywwKjAMBgNVHRME
+AAOCAQ8AMIIBCgKCAQEAyfVq3WLPJGI78RjLcU6TWsL67KzIA5FH5Cs2VLttWK+f
+zDwGKdbn3UBbsL+jw0Ixfe7lv5EZXABXVb4sYJ2zZLojwnBjnbfcTuaS/aYJe5Sd
+nExjhEGErTu3gD0ErXD3Zf+nQMlqTw0B870TkRDyuU3ZNwkGcJYPnWbM+iktHPoq
+JQ6IzxUFYgas0TfwBlDOOSbJSW9wHQO7vmg3xQGt7/dj2E8NpWFXBbxC91RFEmbv
++v3cbwwhYLogIAZTFsL4AcTrEpbmcR8f2B27gZlCGelMi/C+KAcHeEwHbHokY/A8
+DeBSpkAS8eCU/A434hb9tNKNy9pQpreV+qyfYaSSSwIDAQABoywwKjAMBgNVHRME
BTADAQH/MBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAAATANBgkqhkiG9w0BAQsF
-AAOCAQEAGhaCW8lgIamq/+uMpzOTU1ECyuz7Bsp4Qui2Bc3XwXqYuUmI/KcfLVGA
-t2fx6myU9aFic20Vkl6KivkP5x8JDCvSHS9go3QXXzS+HhF3Cr0Qa3i4lg9Acbym
-KQW2qks6wBNWNHCZnT02wW2EFAzTXPokfRV29+FrxS0lUjOeCN/EHoAbbT8HTys0
-IKTZNuEN270qs5IerfxtBnFfXjNjDXIJDM1QMDxZsJv5B1JG72WOcOMMbtxykfWH
-httiVA7JV5AR1KSGa9qbyl3xVRBxHXTPG7WUiAi96wHbLMf1wSdW6zRwFKkTwVeg
-dy884V8Wgu/DW0rtBZefM7n9RYYWfA==
+AAOCAQEAtWS7ufCbscbsvYef2HPkBK0By6HwMdaZDy90OckUvfOR8vUHH8FNfav/
+BUzIlDnO2lKFClvbeT584fDbYVqwQS3/6Pz2lyQ64vvKcmMHzqiA+nUW/DN1x92t
+KLbcs853RgDDz1XtXwMw2VvLC5gYWB6GZ+VVRWuLYgd/l0i+ckk3jG1F9+KPs8F0
+1CaSPkAX0HAaiiBXgNCWAm+z/JZO3fRwCo2s5hRBZ40d9ZprPJyH7n2x9Uyf6SP3
+7BfGakoer9LtraSaMnhrOHUMFuunVfOk/3wstu51sNcdDI5UpkJFZUwD8y7gyN2Z
+GQIsgSNXW4rN/5jamADn3WkC7bo2Tg==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCuK69ZKKvQm/jT
-5UmxSxia6s0c/auu02zxrVx3aQ9ojRDo6SgoPHWg82PdEKzaHPYlkhKjMt2bs2YK
-SK1uuni+Muhhy+LDkAJvjt4Kw3nOpawINNIzukVVX1noJ0dhQPX5sYNuNJfRmbaK
-lNdRhLMsZjv1WFVtVgnjR0vMsisf/kl5n0WoXgVHuo5qLSyMbleK7evY1exdjI/+
-lHzLjZTthSjdyhc2NJXESJYCW0xPNSGmxK2t0G5lPPEwdj+vYYXL/Ew/tBFp/jV5
-V24HNgN8bs7JkxBAz31+ABsj19qJSazQzEgCon/uq2+O9ZYyewSMdpgewsCo5Eqz
-4/jv1DytAgMBAAECggEAAoeEYaNXUW1+cNdW2WIJjrBjv6zIaj7MSXs2yU4niOFp
-kjRWnrT4EVkPhXWZSQacJYIITsHtmXYCwJn7GM1Q9RQor0jmd2gXPPcCbv4VPgTG
-aY0Y02L8YEfE9rvhS76Fg/WJvtc5MDRPBBayxM6MSpQGgWLhxLd358rQhT2+JhYF
-Z8grYjGPkmDr1cu51swGHFi5WNp/7BwFXrBTjFPt0+cLHful2s76lux6jFoWdtdl
-xVsCkdbjcmiHsjvRAvJc0EOohP70nA0MeQmY/9+6UQ1irR8DxLEZJxjA6NcRR2J3
-pvUGoTxVVK0c6qUMm/I+FtSXJ/LNKPcnq7GbrJYfUQKBgQDJUv7O0R8++Dv2t4Rg
-8p8o/HyCvQmrakqVJ1EQqnpsHjefT+2ylGub6FZLn3BxX89x1FV95PweMNTQfQoj
-3S8PvWycZ/H8L50bWRt4yHa7dPS+mAFRicko9P4/XdtKW+Is2TAH5F0rOXEYRqWG
-/Jgw1FNrRXOeshv3TawmGun70QKBgQDdeNjFSOdJDNtmWWjPOdIqWtf5QpJqnMvn
-awOcXorhTpBwu9omgn5t4dh56BefTuvxp1J+TKPR+V9KY4hJErfwVzFmo6Z7+dll
-aqesfoBKCdfgC3Ug51eae/yt0fZYPiYyDRSpfMJjTCPJ/+ZIXpvf3vTY6s3cBm7a
-mf0WXDLWHQKBgASYeGiQLX5qfDPtjIAKCcgNu2ngls/q5TjyZM9UlObS6cIhOPPS
-n4I3k4C2awKrhTi7+BefmoG166W2tPyMl/5r/Ia1eLig/Z0aM55WNR+iU9Pl9GHA
-G29r6EHaCp9v6YHMk2QaumW6MfKz6iNisLasohrYwwLkXe8PPta/1oeBAoGAQRmE
-nnkPgymEVFFzvXYBkPGjCmHHKA9u4FdUeGJR8GhnjLurJCa3gxUfzLWsO+e28xF7
-7iQZA1+J4xPeu5wE9WCr5L+18DtA686t+sY0b471JaY4h7N4zLAlVfKhts6N66hs
-qmVBvm5jFr1hs2Qb7XJcBmb+m+5IJ3mcKzZuuwECgYATtvubZXGB98EaAdlYZ4gT
-WvWLISP0AnSxC4f4+Mml/ZVqmrnNn77L86iHS50jQjUPeJGQH+twPw2XXUMPp3Rk
-cMQThq1mDKneGJNAvl6ho9IU/OZ41l53CQ6O2d/QM0xRDz0bL3UTQ6kllOb2etuw
-7biq9SjwV9oipzzdL9CTew==
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDJ9WrdYs8kYjvx
+GMtxTpNawvrsrMgDkUfkKzZUu21Yr5/MPAYp1ufdQFuwv6PDQjF97uW/kRlcAFdV
+vixgnbNkuiPCcGOdt9xO5pL9pgl7lJ2cTGOEQYStO7eAPQStcPdl/6dAyWpPDQHz
+vROREPK5Tdk3CQZwlg+dZsz6KS0c+iolDojPFQViBqzRN/AGUM45JslJb3AdA7u+
+aDfFAa3v92PYTw2lYVcFvEL3VEUSZu/6/dxvDCFguiAgBlMWwvgBxOsSluZxHx/Y
+HbuBmUIZ6UyL8L4oBwd4TAdseiRj8DwN4FKmQBLx4JT8DjfiFv200o3L2lCmt5X6
+rJ9hpJJLAgMBAAECggEAXndkUD/KwqsMfL7rUom9lWPEuXYsbLbFGO45kLLG+AfW
+SFL/UwzKEgzrlqZddJT+z3gykUPOx+EE+P9mhJ7fbcs/tNCbWAfLjkB+GxVSNDMU
+8iotFo0LAXkAYYSpLnO71UMbOcu85VMhSaB0iZOS5aiLZRncoEcg8LBISu99waJQ
+6ua3xsa9gUpoj0sVr4fdJvyCe6jnriUdNT8E+3dJqSnNaNNsoV47i3jtGLRjKDeM
+iuXQhtUVmLrMGXTNvOjiRSJCRP/oaHdVKYNVqyBYRt92IPcUfN+QSJg6zg2l4FRE
+351MdGtG9a9RpQste5iLOX3M1egVYO9RXAOlL0/+AQKBgQD6IgkIz+tiLyJ+oV24
+CrcZMhZ/E2YfDGOeKNB6DkiABSSPOU0lw0rMaxmRwTJvCNN9DhBLT5pL2A7Df+/j
+Pg59VS4woNknkshhuBpdbFb0GjzZ+5x5HB09B0EzL6Thep9nl25/wu8hU79ArNbv
+vKJKmQB7FScaiGF4ROQsuwxtAQKBgQDOshyVuM86KNzMpC9S7SYKQDZd1aM0w1Jq
+NcvmR2TVSuxL3B8Y2uyNpXI1vJIogcH5cJH6Vw6nbfWnXV0rFBEsgBLSIknL/kAM
+OZRsRH3+iYAyDpx+ZtBAikZVwD++37X744QA2q75E1FHLbrbF6sKhtSEaBwDnIoO
+jNzwhpmjSwKBgACD527cNsjp/fEy1eWWKBBmOQOj/5bayK2/ucY2l1GkMRIWdSE5
+yMKpCdFyC2+NHhpo2AG/tTqoxEcE0XKvYwpBDapN+oSJWd5RqcQ9f+Ra1XtBeG4L
+b8f7Ztf7JiTMwt1Mw46B0UpJSOCSOpMd2Vu7+vNF9OGqHEFKKwoojHsBAoGANN8i
+qLnJaFsjf8VPxaqb3GtofMA1Kz37SufP7Gu+w0CTCSSZX8ZAVEtJ160QxgPLFn9R
+F/RE71cVS2Z6epZ7fiKUrePPdLrorzfbW4Z5pC6P+D38kejCxH+aVj0DEVQwPOqJ
+zZ4iu9vRIp/z+C8ptVuf6O6om9PjDK3DplMH4dkCgYEAh/IO/ApmJmZDdTsRKJpU
+lu3L/Nuik4U+rs0u41trYfeMpkRC6XbkpXUnXcOaIo5NYss27/qCKK0+990PbE8r
+/Q5eCrSC5b0CMIMmil3qEhQp38SQmiZIUK/BvsYiudEbLUU+kQ/VzAhCVrxWy/J4
+92NghK1glLBApc0Djc4N7UU=
-----END PRIVATE KEY-----
diff --git a/jstests/libs/trusted-ca.pem.digest.sha1 b/jstests/libs/trusted-ca.pem.digest.sha1
index 79f38d58026..c871decc4f4 100644
--- a/jstests/libs/trusted-ca.pem.digest.sha1
+++ b/jstests/libs/trusted-ca.pem.digest.sha1
@@ -1 +1 @@
-503F36A2CDB18EB6A369DB2B85956CFB828C0DB9 \ No newline at end of file
+70DD1B61A08F4536C27ED9EBF7E75C50C92A4BA2 \ No newline at end of file
diff --git a/jstests/libs/trusted-ca.pem.digest.sha256 b/jstests/libs/trusted-ca.pem.digest.sha256
index 5968f5ac46e..a23c62007b0 100644
--- a/jstests/libs/trusted-ca.pem.digest.sha256
+++ b/jstests/libs/trusted-ca.pem.digest.sha256
@@ -1 +1 @@
-436E3F116B8C2BA4212319CAA5669DE698045415E0E056521E6E56FB6C0FF61E \ No newline at end of file
+012CF379623361151DC484121E3381698B41E8FA614AD3824C8A2B373F42D07C \ No newline at end of file
diff --git a/jstests/libs/trusted-client.pem b/jstests/libs/trusted-client.pem
index c336f02a76a..0c18c04ab3d 100644
--- a/jstests/libs/trusted-client.pem
+++ b/jstests/libs/trusted-client.pem
@@ -3,52 +3,52 @@
#
# Client certificate for trusted chain.
-----BEGIN CERTIFICATE-----
-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
+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
-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
+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
-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
+DQEBAQUAA4IBDwAwggEKAoIBAQDdMLJxcTTTBy3vunaXIPyJQJwuQieimh7m+Kan
+ie6AcVM72SkchClog3C0pm4bNOE6+ifHXVJs6kIn6hINl1DPs8HNL3Jtw3K68Yjx
+Z0HOyBxs8YmrNJ95ZxspEd2QMtghovk73wP6ilI5lIaxQhFHGV7OJ9A8zPmzrQsE
+D6CwKy5kM3ojSDAoNZsnQrPHl82/jsTfeT1/KwLZuB0VAJ84fTFEqtdTDTt0IXRI
+b8aTbNBvVMmfz2UTqMno5DiRUtRNmNGXvGrcl7witBEOlMO16uaF4Kv29MJpZ/n5
+o0CvA+nfcdP2j2ZU89CBj0VRyUB7h2iWg2mrLZyeUW7wPmb7AgMBAAGjMzAxMBMG
A1UdJQQMMAoGCCsGAQUFBwMCMBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAAATAN
-BgkqhkiG9w0BAQsFAAOCAQEATzP5Fop4nkvF2MqKmGI16pTKr0KuRjSCTDZ58dU6
-bDALvjBKcY2gfnCqOUOjm+9kVcUodefBFfxxtPZGhsPiAGx0SO+IWYOiHgVamq57
-8DBi218AAOy0cCz3dKd/9nJ2VAhdUfg+vtqTRdtvLW2Mg4UlR40HfRmnBUVFxSxI
-CsP5xkwVWZ5YKIhYtGlzOh9tc0UrN96ZlG8a5ZvYN2iPlYdG8AuIsglQrLyYPlj1
-cvNN4PvqlhnKdXtjdf+d479bTDyEi3VDvng2srCb7y5Xp3SzpamH18YyNas3gMyr
-x5kbTveXExzaBEMbcGSvuU0uBd/ZEKUdTEUpw+ZfpsjYHQ==
+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
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCPtBsLG7x3Aete
-i4cY5Fd76l+AvEKjmgmJ9jT5dROHtGT4GgmhS01wX7Dl42PQLebmVrpeDzlGopCW
-UV5FAOu+5EZjjMqMpoTVFqs6fMqmlSEJIOCKfZ9Zp6zzcaql2p305keJW2J4skkv
-HoSrH/OBRTZMqfUS0D0g/WhBHDQV6TC2sVujEbeTVoegfsXySkIcAVld6sdR3QMF
-08H1/KVoyf91Xl9XG/nFbxzHiih9+M/N1MNEMGrDufthwb08FRqMxjsPFeLpTI/8
-PMn+ntzDAUEpl1c8TDVcElen0BSzkVfP6vXfcb3EbfTK9stoiGp/3j4hBv2YGqiu
-osBSB/HhAgMBAAECggEAECC/UT+XZwba3uVLb/5+mAxtlAHs+7YHwIlWmDGs07Pq
-ChNIBedw5T4EGUTsOJrSOYM9zt0oCTapAgnXSejIzIeLo9QTDnaI3W56IKoNR2Vg
-zAi50qk3J2WDal4VMCCJTklC+ZY9Rr0BrC1hZ+BB4L3/ElsXw3kGB0wRdY9ABD5Y
-1pejgm4DDRYf2KXLMuK2WgTbeDGA7scSfkJtP5+IcaHoN4NfMSijMGYUeu4b4n8Z
-c2RA0nItZScpPFszWwLKJiqcUjB2AVpUiIBG6+UXidGnKBtltKJrHQxTiEgTfT8T
-jbBPrPrff93cAYICfS/oxPTMttLwsb6zFLmqASIJfQKBgQDD22q7balIW7+V9CLY
-3F6k4TXk+TGVhaJ+tIA/CMscsbRAFSI6aGmljzUE7wRjaZt1T/GaLwkuMcV0CdBs
-q0BVBxwFGJNek2X1gE+5GinNj1p88/1y4tPP1+q7xbHEeFRtdLQaR8F3PElSbt8y
-WtBKHSg8TzSJvkdBJT1GtMCYTQKBgQC71NQ8Q3N3444s7ZrimCfEOH/BCE7lO/Yd
-j8K2nnjWrnVe/G2luAPbPtugsLYNCQ22bf3iIl7aGFglCTc9SzUN4iZ7lH0q5tW3
-38eZ3J3wtPjCY/WpfjYgtTA/GRAqF1oE+04PYYwu8Wp71cvYQLQZbePC2lpHWJ2c
-TcaFYHkJ5QKBgGXjyfzDqeNYx6yNG2vSCPKhrtX1xZPRt51O7cDdJD1DPVBxLiNQ
-mlVk0OJGLfRBxnwbIMdjXNVJUz1wtZsy4/7X+f20sUXsTIiRPeg/8itcPmjuzZVs
-52AjJZyV1ksthk6C/gcF+WG8XTCjOT4K/Hzx+jKVyfE2qf78DoqwEdmpAoGAJF37
-zcM9ixvq/jXvBCpzoKFT0vsZ03Z9m5GnIJakTOSwYvi6/hgX3w5XldBBH1r+ZbD8
-NBl1hgKqplkXce2q0wpTax//8BuLi7NvQRIfHmjbtT+HZA7EyiZqtfzTTWMCEe7a
-WU4Ix1oExP9LHY7BkB7ft21xh1jYA1hntJFOPiUCgYAncBKiv5/iBqEs2w7rC2Oc
-DhYHyh/tET35GyBMSA0J41IdmLOlMlX4CT+efjJrKmS9mXVf8SldgUftKVFG+WU/
-NGKGylB0oWIHuI1wENQZyW+sY4j7oJLx7GqpM3u9PmeDCdN+OAv41K+9XVUG7Zzw
-AewAgvXAQMMuWuBkzOuBMQ==
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDdMLJxcTTTBy3v
+unaXIPyJQJwuQieimh7m+Kanie6AcVM72SkchClog3C0pm4bNOE6+ifHXVJs6kIn
+6hINl1DPs8HNL3Jtw3K68YjxZ0HOyBxs8YmrNJ95ZxspEd2QMtghovk73wP6ilI5
+lIaxQhFHGV7OJ9A8zPmzrQsED6CwKy5kM3ojSDAoNZsnQrPHl82/jsTfeT1/KwLZ
+uB0VAJ84fTFEqtdTDTt0IXRIb8aTbNBvVMmfz2UTqMno5DiRUtRNmNGXvGrcl7wi
+tBEOlMO16uaF4Kv29MJpZ/n5o0CvA+nfcdP2j2ZU89CBj0VRyUB7h2iWg2mrLZye
+UW7wPmb7AgMBAAECggEBALqvDByE8JGfgJzRop/BPoNVHbxJJ4ysSaKlgHrtBngv
+rZFYosMnpI9KSIif41RhGCuf0I0KbbPxL27ituPzr0fuLobQIeMUT7QKgYtFnBw7
+dwpX/dqa6nIbnKfYJUk8MICLPZHTk1cVAXsJqXjYCx8YAZU7sxxt395PEXoW+odU
+CKhcATdoT3zDrAeyJTXMeymKswQfpoAqO8hmOF70PWK3AFdmzebuaOiHuYnZPP8k
+GRQnpy/0aRzJYFWsL7xbEbWy2p49TG3JlkZACC2lAclh2CPJDjYBmsRQVOUHP7Kx
+kH6xZY4rC9/qmnhZKWqohipFGTkIgf5gyXnz6jm1CjkCgYEA+AS5goeT/ZD+/Ou+
+G3P1n6ZpHLpRna8TiSX3ICFf/MkPtWpG3yvK5bZJjmLc79VIimddnmxc9j3f3/b3
+Nv9J6iK/p8s3cmmm3IcJooolVoPK/AQyo2sCObiPMfD3k5bFTlsUVjB2oZ9kUBK3
+1LxsYiUXO4nB2OTJjDyFWYxeqd8CgYEA5E7zXyYHgE6jQJfI+irQbOAH8h5bhHhj
+bwuL2kt7XdrODkKJ0nGmxupXM3/4usJD1j/e8EIIR7Pj5B9c9eekx03eCQo/BqSv
+T1yLexy3Xrnp0IQqDQM59R2+UPsYbSgC+z7ldSYbKmVOI+8RVvjG5Gy4xsCAxm9X
+Bun2PIcq3mUCgYEAiTYL74PUQucRupktXoDDtaRZ6JPHjWYLd8eyNWthcDdH4oS+
+Wr8ejAFSJlzZgDHN5QwUhg3LTEuk7IHz+NA5czfwMgNCVKDQuJZYpTyqNXfKN6yW
+20PbQlWxmt6GCXfTBmtrD9fV+cp1s7r3StFHYPDGLqEixjykqFnfKFB5Gp8CgYBC
+/oPd1Mv4s5qmFqQr/KpCeI78VjomqikLacj1Gpct2EoE1zOYJC97SUKjYxb6voyn
+bwCdYdMKL1hdFXLy2bF5pnjUEESkT2j+EbsAOlH4ovdgb5fjT6IPMlYpbzUgus/9
+J9yvPqpUC3wdgUaGTeQXHWwvLkfbcsqHxdmyszs6HQKBgGzbVal5oGDajtmye6B7
+1X6rHh0WwvtQmkSjfCPavlXgcTm88u2+JsLQoKTvaiAvGwM83f2H3vHeYb2dfZx/
+c/nJBhj8REz46ZoDJIn7BwdUMfbYnLKQjCzg1GdvgGSXcclYA8pZ99ucx+Omk1Lu
+ZCONsEcSVMQfwe8STNhkJUqX
-----END PRIVATE KEY-----
diff --git a/jstests/libs/trusted-client.pem.digest.sha1 b/jstests/libs/trusted-client.pem.digest.sha1
index 53973cfe0c8..7ea8e5bf8a7 100644
--- a/jstests/libs/trusted-client.pem.digest.sha1
+++ b/jstests/libs/trusted-client.pem.digest.sha1
@@ -1 +1 @@
-82679EF93897F94C1C5044153DDE7F3E7222A483 \ No newline at end of file
+2BB0789DD563FBF0E3747DE299EF5348BE5160B9 \ No newline at end of file
diff --git a/jstests/libs/trusted-client.pem.digest.sha256 b/jstests/libs/trusted-client.pem.digest.sha256
index 98c2e0cc2c4..9a0a949110b 100644
--- a/jstests/libs/trusted-client.pem.digest.sha256
+++ b/jstests/libs/trusted-client.pem.digest.sha256
@@ -1 +1 @@
-AA4D642A2E41621257CDFE6D52E6DA6A802AC70783FB1835D1FC90CEDB35F83A \ No newline at end of file
+32D27BCE106096500F8A6FC1BFAEF9943A0666E30D07B503FA39166EE8B711AD \ No newline at end of file
diff --git a/jstests/libs/trusted-client.pfx b/jstests/libs/trusted-client.pfx
index 39742de5989..da53725058d 100644
--- a/jstests/libs/trusted-client.pfx
+++ b/jstests/libs/trusted-client.pfx
Binary files differ
diff --git a/jstests/libs/trusted-server.pem b/jstests/libs/trusted-server.pem
index 3f73738abda..1290f1bc72c 100644
--- a/jstests/libs/trusted-server.pem
+++ b/jstests/libs/trusted-server.pem
@@ -3,52 +3,52 @@
#
# Server certificate for trusted chain.
-----BEGIN CERTIFICATE-----
-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
+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
-ZCBLZXJuZWwgVGVzdCBDQTAeFw0yNDAxMTUxNjExNDdaFw0yNjA0MTgxNjExNDda
+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
-DQEBAQUAA4IBDwAwggEKAoIBAQCkocDWP0OoNTf3BPGrUX7KfXrTgCJFBTJ9/zek
-AMztmHcYnL8O/DWiODUrwzf4TN7j5fqGlF6b7atJ2g8bcTV6q6MDLzZyMdpIfWcv
-bzverzaUBXc1MUUCLRlWFw6S+zIYN7ScCN0eUhkS6DyDioXwmj/DRXnZRtYxwEBD
-qyE3yC5990L9Mcgb0rwM7U4EYMOR7yGNnd/GfilFCCz5+1sIHDEAzD39bt1aHwPX
-1EkBoHDpgBU2Cr9sgUxXhy7QKHjlWnBId0Nq2sTHXoOYPJNY5h7CWYROgTL494Na
-6nGIdIyX+c8LnsHEubyognXjEvV9K8//AVk3eI9wzYRbBHz5AgMBAAGjMzAxMBMG
+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
-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
+BgkqhkiG9w0BAQsFAAOCAQEAUbsmwmdAgT0BWw7a91Jihf7cMAZ3WZSz1oBk1dMD
+2j4/2nkDM5yamMYWQB2SYD5XmhbhawAYWt8XmvK7dhrFoL2KtgWJKmf752hSJAbL
+twUMIAbH+F32UFYJZCyZr/zQlJmeQ9YY2QTuIz29cF2SXbMQp5hLVFrUSxmkwPbq
+7XP+chkF8GWjfNVfxYWZvuVu4OctcYI26rSHF18l1JZY1B4aBDndoouaMu98hPUl
+rRC1lxi05vymDsKWyYF6TInsxOAbLBIBWiEEICG80+wusf7rWItGjw9j8Wm0aBBa
+tOPJIHg9znBjMWoucFAO+5rfeBQXwpYOfF5lyDuQY5hD4g==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCkocDWP0OoNTf3
-BPGrUX7KfXrTgCJFBTJ9/zekAMztmHcYnL8O/DWiODUrwzf4TN7j5fqGlF6b7atJ
-2g8bcTV6q6MDLzZyMdpIfWcvbzverzaUBXc1MUUCLRlWFw6S+zIYN7ScCN0eUhkS
-6DyDioXwmj/DRXnZRtYxwEBDqyE3yC5990L9Mcgb0rwM7U4EYMOR7yGNnd/GfilF
-CCz5+1sIHDEAzD39bt1aHwPX1EkBoHDpgBU2Cr9sgUxXhy7QKHjlWnBId0Nq2sTH
-XoOYPJNY5h7CWYROgTL494Na6nGIdIyX+c8LnsHEubyognXjEvV9K8//AVk3eI9w
-zYRbBHz5AgMBAAECggEAOgoegkm2b/gnHUpcasHl2bxID4VGT5/n75yIwKRZms/b
-+MzV3JIU1HZNZHrD4iEzmROscUKgYgd1kikyl0GfkXouE4LTBopFwrWXKZVk/Xo2
-2xNcNeADTKOaoYuqYy30uK322eWUEsrttQkzwEoXMz4mCZEWRn/fJpX48gJESTYT
-VVpKRIdXXRk6hFU3hr0PNJg5nQPUIbdSq2nS76OD2w3A1/UmJ3ShCLcex3MvDJzY
-3lV20Ioa63CwyF0PDn68Hboz5rdoKRZPpfy2bboILBDi0JzzaeXjmzHxQ42Bd92J
-H0oehMpBN8wHwxohm4lgP8ACphwCxJgWCuhLBNT5OwKBgQC2s5qzPQCFE07rUSqY
-Xrchpzd8cABsTCNqE4Y1I1tf5nUY/VdWQbSdl3xnDmbV3Z5VRU0lBo9BDLCmpGqX
-2En2bKT8SEJLMs7st9B/IMkbaVVGgDCzeg02iu8Zmt3C6yDzuSZtD/V4h8/h+hzP
-uu/xOOLH7QAc3dIRiTOCMjXQTwKBgQDmrktY5phGUEpsvCPn22fZwNdGvm6hal84
-DABr3S3pV3NtsB+U62br3RISnJvlxDdosiaSOeu1LnO15IIsQsRysw2TxLE79QdU
-74YUWcBVDI5kT5GmVXjLdd2u49ipK4zyphfMhObdFadq1lpiQZDW4ZvP4FYnqZmy
-xf9b3jSENwKBgCrsVUsI6Oda2u60GgLENdglNgb5NVA8LxHL1nsDfIMyXI5rbqpo
-M2vW3DZGDujt8TXtWyt4uA07UwFDnXthKDdJ3RUcUN7j5/N7V/OWG0liXNN8aHSy
-FwqaZ4QnezRBE3PPKvTyi+QuXCumHEC9lYOhrr3zs1QU1TajekN7UmNHAoGBALb6
-0FevamBz9eU0g8K5njHzLpA2JCkz6F3b30WwR2fNb4k1aIfHBnfXfyt2QI9MSqto
-jQH2ocqxEyXYIY2cVJmq//0Ty4aEwZEVAiUIYHDWKejV2PG44L17PCIrJ8RhAEfF
-iiE31qzOLWOorj88RPi+Msr85zpE5N8TAZDMvJmXAoGAPcFjaeX5Lhlq5e8CbdyI
-4P8UOON2yG6zX3IUdn3ZaPCprp7zjoONtKMgPkk6HE+9EDGuGcpBRihfSa7JE77u
-+R+nvf5RtUNlQhTCxadTua3n3yh7Sn5v+/nwNt1/sY5CoOIGytzt3tdCwgHaEoDz
-SxUXO4+O2hSdFhAVKpFXjuM=
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDB9T4dHCPnbAB0
+3PVnX6jRePH03iS2KR2cIePQWLN9bz9lZ1gm+TOSa/R0uziHcR+/hnzlInMWA7S+
+hCCvh41QKlwmzZnV9ZEZOsnjFqgyYUSHngvil8DTefdoONicukGYbSM0+iSfI6nu
+s+TeqxSPIKDW01OWyH9Ro7BXfMn12s+0Vh1ras7x7qhceD1qzA8jcZcaebMfJCrZ
+SMR5KAbUflWnPxulAgPR4amVHza+mAwRukrP6VraEwslHHb0dYZI1e1gJJVjPOfA
+nZvH++ZyCj2aTeBMiJcORLZsA+Fw8R4geh/bmWbKctm03P/dowFzvZH9KVyE6foq
+YGuraP8TAgMBAAECggEBAK6/bBUCE38fmVGw+hEG6KzB0Q0TT/QnGxxelEhUgnKS
+1oVgFNYYU9SqGvdI7udojngajVBMN3AwKpozpNdAw5rkb14ug1l4BCC9DMPi1+t8
+IygkxwSCQSLHkpZ+EPsz/IF+YugKLxCKK0J7JctQTBegCAlFINyLC9rcJbbNIZC0
+390fFFXYzLwMTe6oBwR8/k4EZosxuNRUcHblzrBZ9PWC/VXJs8N82Sviqr8H9F0/
+b8PSsoA1cKgW1q1DLhFCLdjdRVkl2ThdAVwqtVXCCJiP20Ej0MMgQWrWX5QMJsrS
+Ut7ASZsc8RHzRHiAaskDsDqkLNBO4Pw0HfXRCLridvECgYEA6PmW1/QYrKR1OEST
+dLLNjCqEBTDmW2Y6i2YKl4ywEM5r1AbGyh58SaKN1tTRF6FF66YK6/2ib7eUnpHG
+JdgLBXMGbqabl4jyUuDXeho0Q7C6OvdGSbu2lxxBMhRDxoWJD6HI9ML1alqMl+NI
+m+R3OD0GG4VLlE9udVLsOIDtAr8CgYEA1SB/6cgLen5o/1H0zRqntZua/dyr8VmO
++rM8NXtDYb+Xy+RwZ1HZzyGedB1uTZHT9wKa+WzQxQJuDuii7gpjNLtvwVx0BeYO
+o4GLLZ33XoTR+9oEjbv9ZZWhsf6uU1bAS9Agg4Tl8EAM3j+LRYFTAlaU4mWJZ9dT
+ZYNJcJWe3K0CgYAQfbJWwPmKJu4BOKFzbkCsfknwECEOMTNNsMBpL9U6q1HopT4n
+CndjwvTlUxUl5g2L+6nkQITiAY2sl8b94MgO77Bx3qs+07vLcAzwoLA4ZmcYS26X
+Q4lOMvrOb67Ie6VTDPGrma1DhPtUuQrntglWWsN26T2LVwALn/4GleGxAwKBgChA
+CAhFwG003G2Ds+DcbNnudjoFZ++fw1HzcaaEDfiy718RWG0a1zC4H628NS2vIcHf
+mxcKBu9+Av0L0GF2UsANuhBhfoPyq8cTWw6Va7dNDD8tMHj4DOYXeT8dYxzYIF7x
+AoL0IVzbK9L5WzsYLm4dneaX2HhlARoFzmPVzffNAoGBAMibGUrLe0uUDEp3s7X0
+GoZ2bYJ8CGh5VfhkvlbxNSIhvJ3EvXk2PtM+Us/6DPnSoeczvIBGvoh6nNgKaolI
+C5/8eD5wNgPsslGcfE4SZwsEuwondsyzmPhYYPpYf/ffpoEpMkBVTDyh7iN/WD0Q
+5jfCbsm6xWieAT9QhKC58W6E
-----END PRIVATE KEY-----
diff --git a/jstests/libs/trusted-server.pem.digest.sha1 b/jstests/libs/trusted-server.pem.digest.sha1
index 9790bddc508..bed14ae8841 100644
--- a/jstests/libs/trusted-server.pem.digest.sha1
+++ b/jstests/libs/trusted-server.pem.digest.sha1
@@ -1 +1 @@
-FB99C61E428E28FDFB692725543703996B5E43DB \ No newline at end of file
+496B9987B8E7F5E5C1F998BC7D1AE9F4064ABE70 \ No newline at end of file
diff --git a/jstests/libs/trusted-server.pem.digest.sha256 b/jstests/libs/trusted-server.pem.digest.sha256
index a5550b94b7e..01ed4517147 100644
--- a/jstests/libs/trusted-server.pem.digest.sha256
+++ b/jstests/libs/trusted-server.pem.digest.sha256
@@ -1 +1 @@
-132169A496E561C20EEE5097D58347272561ED3C82952BDE374D18B5B448BB52 \ No newline at end of file
+1CCBA15D77CC7DA4CDF7E36EBEE46D89B28379F378EAD01C0C873DA7A75AF275 \ No newline at end of file
diff --git a/jstests/libs/trusted-server.pfx b/jstests/libs/trusted-server.pfx
index 5a80dd676ea..0985e6e4adb 100644
--- a/jstests/libs/trusted-server.pfx
+++ b/jstests/libs/trusted-server.pfx
Binary files differ
diff --git a/jstests/multiVersion/genericBinVersion/query_stats_key_hash_version_consistency.js b/jstests/multiVersion/genericBinVersion/query_stats_key_hash_version_consistency.js
new file mode 100644
index 00000000000..1e61d5280fc
--- /dev/null
+++ b/jstests/multiVersion/genericBinVersion/query_stats_key_hash_version_consistency.js
@@ -0,0 +1,56 @@
+/**
+ * Tests that query stats key hashes are consistent across versions.
+ * @tags: [requires_fcv_60]
+ */
+(function() {
+'use strict';
+
+load("jstests/multiVersion/libs/multi_rs.js");
+load("jstests/libs/query_stats_utils.js"); // For getQueryStatsFindCmd and getQueryStatsKeyHashes.
+
+// TODO SERVER-87729 Start from the previous version.
+const rst = new ReplSetTest(
+ {nodes: {n1: {binVersion: "latest"}, n2: {binVersion: "latest"}, n3: {binVersion: "latest"}}});
+
+// Turn on the collecting of query stats metrics.
+rst.startSet({setParameter: {internalQueryStatsRateLimit: -1}});
+rst.initiate();
+
+let conn = rst.getPrimary();
+const collName = jsTestName();
+let coll = conn.getDB("test")[collName];
+coll.drop();
+coll.insert({x: 5});
+
+// Run a few unique queries so that they generate different query stats entries.
+function runQueries() {
+ coll.find({x: 5}).toArray();
+ coll.find({y: 5}).toArray();
+ coll.find({y: 5}).sort({x: -1}).toArray();
+ coll.find({y: 5}).maxTimeMS(123).toArray();
+}
+
+// First, collect and save query stats entries on the older version.
+runQueries();
+const preUpgradeEntries = getQueryStatsFindCmd(conn, {collName, transformIdentifiers: false});
+assert.eq(preUpgradeEntries.length, 4, tojson(preUpgradeEntries));
+const preUpgradeKeyHashes = getQueryStatsKeyHashes(preUpgradeEntries);
+
+// Upgrade to the latest.
+rst.upgradeSet({binVersion: 'latest'});
+conn = rst.getPrimary();
+coll = conn.getDB("test")[collName];
+
+// Run the same queries again and check that we got the same query stats key hash values as we did
+// on the old version.
+runQueries();
+const postUpgradeEntries = getQueryStatsFindCmd(conn, {collName, transformIdentifiers: false});
+assert.eq(postUpgradeEntries.length, 4, tojson(postUpgradeEntries));
+const postUpgradeKeyHashes = getQueryStatsKeyHashes(postUpgradeEntries);
+assert.sameMembers(postUpgradeKeyHashes,
+ preUpgradeKeyHashes,
+ `preUpgradeEntries = ${tojson(preUpgradeEntries)}, postUpgradeEntries = ${
+ tojson(postUpgradeEntries)}`);
+
+rst.stopSet();
+})(); \ No newline at end of file
diff --git a/jstests/multiVersion/genericBinVersion/remove_invalid_index_options.js b/jstests/multiVersion/genericBinVersion/remove_invalid_index_options.js
index c49422423c4..b9a9405c182 100644
--- a/jstests/multiVersion/genericBinVersion/remove_invalid_index_options.js
+++ b/jstests/multiVersion/genericBinVersion/remove_invalid_index_options.js
@@ -44,10 +44,15 @@ fpSecondary.off();
// Verify that the primary (latest) and secondary (last-lts) detect invalid index options.
let validateRes = assert.commandWorked(primaryDB.runCommand({validate: collName}));
-assert(!validateRes.valid);
+assert(validateRes.valid);
+assert.eq(validateRes.errors.length, 0);
+assert.eq(validateRes.warnings.length, 2);
validateRes = assert.commandWorked(secondaryDB.runCommand({validate: collName}));
-assert(!validateRes.valid);
+// TODO (SERVER-87985): Enable assertions.
+// assert(validateRes.valid);
+// assert.eq(validateRes.errors.length, 0);
+// assert.eq(validateRes.warnings.length, 2);
// Use collMod to remove the invalid index options in the collection.
assert.commandWorked(primaryDB.runCommand({collMod: collName}));
@@ -64,9 +69,13 @@ checkLog.containsJson(secondary, 23878, {fieldName: "xyz"});
// Verify that the index no longer has invalid index options.
validateRes = assert.commandWorked(primaryDB.runCommand({validate: collName}));
assert(validateRes.valid);
+assert.eq(validateRes.errors.length, 0);
+assert.eq(validateRes.warnings.length, 0);
validateRes = assert.commandWorked(secondaryDB.runCommand({validate: collName}));
assert(validateRes.valid);
+assert.eq(validateRes.errors.length, 0);
+assert.eq(validateRes.warnings.length, 0);
rst.stopSet();
})();
diff --git a/jstests/multiVersion/genericBinVersion/timeseries_collection_mixed_type.js b/jstests/multiVersion/genericBinVersion/timeseries_collection_mixed_type.js
index 4e94668a46f..85943e6c9d1 100644
--- a/jstests/multiVersion/genericBinVersion/timeseries_collection_mixed_type.js
+++ b/jstests/multiVersion/genericBinVersion/timeseries_collection_mixed_type.js
@@ -17,7 +17,9 @@ const timeFieldName = "time";
* one bucket was created.
*/
function runTest(docs, query, results, path, bounds) {
- const oldVersion = "last-lts";
+ // Since v5.0 no longer supports writing mixed schema buckets as of 5.0.29, pin the version
+ // to 5.0.28 to retain coverage as v5.0 still supports the presence of mixed schema data.
+ const oldVersion = "5.0.28";
const nodes = {
n1: {binVersion: oldVersion},
n2: {binVersion: oldVersion},
diff --git a/jstests/multiVersion/prepare_unique_fcv_check.js b/jstests/multiVersion/prepare_unique_fcv_check.js
new file mode 100644
index 00000000000..7cf27162d64
--- /dev/null
+++ b/jstests/multiVersion/prepare_unique_fcv_check.js
@@ -0,0 +1,48 @@
+/* Test that an index that contains prepareUnique cannot be created when
+ * featureFlagCollModIndexUnique is not enabled.
+ *
+ * @tags: [requires_persistence]
+ */
+(function() {
+"use strict";
+
+const mongod = MongoRunner.runMongod();
+assert.neq(null, mongod, "mongod was unable to start up");
+const db = mongod.getDB("test");
+const admin = db.getSiblingDB("admin");
+const coll = db.test;
+try {
+ checkFCV(admin, "6.0");
+} catch (e) {
+ jsTestLog("Expecting FCV 6.0: " + tojson(e));
+ quit();
+}
+
+// createIndex with prepareUnique should work by default.
+assert.commandWorked(db.runCommand(
+ {createIndexes: coll.getName(), indexes: [{key: {a: 1}, name: 'a_1', prepareUnique: true}]}));
+// coll should be created implicitly.
+assert(Array.contains(db.getCollectionNames(), coll.getName()));
+
+// Downgrade FCV
+assert.commandWorked(coll.dropIndex({a: 1}));
+assert.commandWorked(db.adminCommand({setFeatureCompatibilityVersion: lastLTSFCV}));
+
+// Now createIndex with prepareUnique:true should fail on an existing collection.
+let res = db.runCommand(
+ {createIndexes: coll.getName(), indexes: [{key: {a: 1}, name: 'a_1', prepareUnique: true}]});
+assert.commandFailedWithCode(res, ErrorCodes.InvalidOptions);
+
+// createIndex with prepareUnique:true should also fail on a new collection.
+assert(coll.drop());
+res = db.runCommand(
+ {createIndexes: coll.getName(), indexes: [{key: {a: 1}, name: 'a_1', prepareUnique: true}]});
+assert.commandFailedWithCode(res, ErrorCodes.InvalidOptions);
+
+// Upgrade FCV and createIndex with prepareUnique should now work.
+assert.commandWorked(db.adminCommand({setFeatureCompatibilityVersion: latestFCV}));
+assert.commandWorked(db.runCommand(
+ {createIndexes: coll.getName(), indexes: [{key: {a: 1}, name: 'a_1', prepareUnique: true}]}));
+
+MongoRunner.stopMongod(mongod);
+})();
diff --git a/jstests/multiVersion/targetedTestsLastLtsFeatures/change_streams_split_event_v1_v2_tokens.js b/jstests/multiVersion/targetedTestsLastLtsFeatures/change_streams_split_event_v1_v2_tokens.js
index e59bc2e106a..3b183f18bef 100644
--- a/jstests/multiVersion/targetedTestsLastLtsFeatures/change_streams_split_event_v1_v2_tokens.js
+++ b/jstests/multiVersion/targetedTestsLastLtsFeatures/change_streams_split_event_v1_v2_tokens.js
@@ -20,7 +20,11 @@ const st = new ShardingTest({
rsOptions: {
binVersion: "last-lts",
},
- rs: {nodes: 2},
+ rs: {
+ nodes: 2,
+ // Reserving enough of oplog space to accommodate 4 nearly 16MB-large changes.
+ oplogSize: 16 * 5
+ }
}
});
@@ -97,7 +101,8 @@ assert.commandWorked(
st.s.adminCommand({refineCollectionShardKey: testColl.getFullName(), key: {shard: 1, _id: 1}}));
// Produces no events on v5.0.
-assert.commandWorked(st.s.adminCommand({reshardCollection: testColl.getFullName(), key: {_id: 1}}));
+assert.commandWorked(st.s.adminCommand(
+ {reshardCollection: testColl.getFullName(), key: {_id: 1}, numInitialChunks: 1}));
// Produces no events on v5.0.
assert.commandWorked(testColl.dropIndex({largeField: 1}));
@@ -118,6 +123,28 @@ expectedEvents.push({operationType: "dropDatabase"},
{operationType: "invalidate"},
{operationType: "dropDatabase"});
+// Leave only the last of the events with identical resume tokens, because the previous events will
+// be skipped when resuming from such a token.
+// TODO SERVER-90266: Remove this workaround when no longer needed.
+{
+ const csCursor = testDB.watch([], {startAfter: testStartV1HWMToken});
+
+ // The 'drop' and 'rename' events coming from different shards are likely to get identical
+ // resume tokens in v5.0.
+ for (let prevEvent = csCursor.next(), nextEvent; csCursor.hasNext(); prevEvent = nextEvent) {
+ nextEvent = csCursor.next();
+ if (bsonWoCompare(nextEvent._id, prevEvent._id) === 0) {
+ // If two or more consecutive events have identical resume tokens, remove all but the
+ // last from the expected events.
+ expectedEvents.splice(expectedEvents.findIndex(
+ (event) => (event.operationType === prevEvent.operationType)),
+ 1);
+ }
+ }
+
+ csCursor.close();
+}
+
// Helper function to assert on the given event fields.
function assertEventMatches(event, expectedEvent, errorMsg) {
for (const k in expectedEvent) {
diff --git a/jstests/multiVersion/targetedTestsLastLtsFeatures/fix_invalid_index_options.js b/jstests/multiVersion/targetedTestsLastLtsFeatures/fix_invalid_index_options.js
index 5844b6bfec3..a18683b2956 100644
--- a/jstests/multiVersion/targetedTestsLastLtsFeatures/fix_invalid_index_options.js
+++ b/jstests/multiVersion/targetedTestsLastLtsFeatures/fix_invalid_index_options.js
@@ -45,10 +45,14 @@ secondaryDB = secondary.getDB(dbName);
// Verify that the primary and secondary in 6.0 detect invalid index options.
let validateRes = assert.commandWorked(primaryDB.runCommand({validate: collName}));
-assert(!validateRes.valid, "validate should fail: " + tojson(validateRes));
+assert(validateRes.valid, "validate should succeed: " + tojson(validateRes));
+assert.eq(validateRes.errors.length, 0, "validate should not error: " + tojson(validateRes));
+assert.eq(validateRes.warnings.length, 1, "validate should warn: " + tojson(validateRes));
validateRes = assert.commandWorked(secondaryDB.runCommand({validate: collName}));
-assert(!validateRes.valid, "validate should fail: " + tojson(validateRes));
+assert(validateRes.valid, "validate should succeed: " + tojson(validateRes));
+assert.eq(validateRes.errors.length, 0, "validate should not error: " + tojson(validateRes));
+assert.eq(validateRes.warnings.length, 1, "validate should warn: " + tojson(validateRes));
// Use collMod to fix the invalid index options in the collection.
assert.commandWorked(primaryDB.runCommand({collMod: collName}));
@@ -62,9 +66,13 @@ assert.commandWorked(primaryDB.runCommand({listIndexes: collName}));
validateRes = assert.commandWorked(primaryDB.runCommand({validate: collName}));
assert(validateRes.valid, "validate should succeed: " + tojson(validateRes));
+assert.eq(validateRes.errors.length, 0, "validate should not error: " + tojson(validateRes));
+assert.eq(validateRes.warnings.length, 0, "validate should not warn: " + tojson(validateRes));
validateRes = assert.commandWorked(secondaryDB.runCommand({validate: collName}));
assert(validateRes.valid, "validate should succeed: " + tojson(validateRes));
+assert.eq(validateRes.errors.length, 0, "validate should not error: " + tojson(validateRes));
+assert.eq(validateRes.warnings.length, 0, "validate should not warn: " + tojson(validateRes));
rst.stopSet();
})();
diff --git a/jstests/multiVersion/targetedTestsLastLtsFeatures/invalid_index_options.js b/jstests/multiVersion/targetedTestsLastLtsFeatures/invalid_index_options.js
index 51c5d5b03e7..c4c23061617 100644
--- a/jstests/multiVersion/targetedTestsLastLtsFeatures/invalid_index_options.js
+++ b/jstests/multiVersion/targetedTestsLastLtsFeatures/invalid_index_options.js
@@ -59,13 +59,19 @@ const secondaryDB2 = secondary2.getDB(dbName);
// Verify that the existing nodes detect invalid index options, but the new node has the repaired
// index spec.
let validateRes = assert.commandWorked(primaryDB.runCommand({validate: collName}));
-assert(!validateRes.valid, "validate should fail: " + tojson(validateRes));
+assert(validateRes.valid, "validate should succeed: " + tojson(validateRes));
+assert.eq(validateRes.errors.length, 0, "validate should not error: " + tojson(validateRes));
+assert.eq(validateRes.warnings.length, 1, "validate should warn: " + tojson(validateRes));
validateRes = assert.commandWorked(secondaryDB1.runCommand({validate: collName}));
-assert(!validateRes.valid, "validate should fail: " + tojson(validateRes));
+assert(validateRes.valid, "validate should succeed: " + tojson(validateRes));
+assert.eq(validateRes.errors.length, 0, "validate should not error: " + tojson(validateRes));
+assert.eq(validateRes.warnings.length, 1, "validate should warn: " + tojson(validateRes));
validateRes = assert.commandWorked(secondaryDB2.runCommand({validate: collName}));
assert(validateRes.valid, "validate should succeed: " + tojson(validateRes));
+assert.eq(validateRes.errors.length, 0, "validate should not error: " + tojson(validateRes));
+assert.eq(validateRes.warnings.length, 0, "validate should not warn: " + tojson(validateRes));
// Use collMod to fix the invalid index options in the collection.
assert.commandWorked(primaryDB.runCommand({collMod: collName}));
@@ -79,12 +85,18 @@ assert.commandWorked(primaryDB.runCommand({listIndexes: collName}));
validateRes = assert.commandWorked(primaryDB.runCommand({validate: collName}));
assert(validateRes.valid, "validate should succeed: " + tojson(validateRes));
+assert.eq(validateRes.errors.length, 0, "validate should not error: " + tojson(validateRes));
+assert.eq(validateRes.warnings.length, 0, "validate should not warn: " + tojson(validateRes));
validateRes = assert.commandWorked(secondaryDB1.runCommand({validate: collName}));
assert(validateRes.valid, "validate should succeed: " + tojson(validateRes));
+assert.eq(validateRes.errors.length, 0, "validate should not error: " + tojson(validateRes));
+assert.eq(validateRes.warnings.length, 0, "validate should not warn: " + tojson(validateRes));
validateRes = assert.commandWorked(secondaryDB2.runCommand({validate: collName}));
assert(validateRes.valid, "validate should succeed: " + tojson(validateRes));
+assert.eq(validateRes.errors.length, 0, "validate should not error: " + tojson(validateRes));
+assert.eq(validateRes.warnings.length, 0, "validate should not warn: " + tojson(validateRes));
rst.stopSet();
})(); \ No newline at end of file
diff --git a/jstests/multiVersion/targetedTestsLastLtsFeatures/query_stats_upgrade_downgrade.js b/jstests/multiVersion/targetedTestsLastLtsFeatures/query_stats_upgrade_downgrade.js
new file mode 100644
index 00000000000..20ff7add9cd
--- /dev/null
+++ b/jstests/multiVersion/targetedTestsLastLtsFeatures/query_stats_upgrade_downgrade.js
@@ -0,0 +1,272 @@
+/**
+ * Verifies that $queryStats operates correctly when upgrading and downgrading.
+ */
+
+load("jstests/multiVersion/libs/multi_rs.js");
+load("jstests/multiVersion/libs/multi_cluster.js");
+load("jstests/libs/collection_drop_recreate.js");
+load("jstests/libs/query_stats_utils.js");
+
+(function() {
+"use strict";
+
+const lastLTSVersion = "last-lts";
+
+class UpgradeDowngradeTestFixture {
+ constructor() {
+ this.collectionName = "coll";
+ }
+
+ getTestDB() {
+ return this.rst.getPrimary().getDB(jsTestName());
+ }
+
+ createAndPopulateTestCollection() {
+ let testDB = this.getTestDB();
+ let coll = assertDropAndRecreateCollection(testDB, "coll");
+ assert.commandWorked(coll.insertMany([{x: 0}, {x: 1}, {x: 2}]));
+ }
+
+ setup() {
+ jsTestLog("Starting ReplicaSet Upgrade/Downgrade Test!");
+
+ this.rst = new ReplSetTest({
+ name: jsTestName(),
+ nodes: [{binVersion: lastLTSVersion}, {binVersion: lastLTSVersion}]
+ });
+ this.rst.startSet();
+ this.rst.initiate();
+ this.createAndPopulateTestCollection();
+ }
+
+ teardown() {
+ jsTestLog("Teardown ReplicaSet Upgrade/Downgrade Test!");
+
+ this.rst.stopSet();
+ }
+
+ getTestCollection() {
+ return this.getTestDB().getCollection(this.collectionName);
+ }
+
+ adminCommand(command) {
+ return this.rst.getPrimary().getDB("admin").runCommand(command);
+ }
+
+ upgradeBinaries() {
+ this.rst.upgradeSet({binVersion: "latest"});
+ }
+
+ upgradeFCV() {
+ assert.commandWorked(this.adminCommand({setFeatureCompatibilityVersion: latestFCV}));
+ }
+
+ downgradeFCV() {
+ // Downgrade FCV (without restarting) and check that $queryStats returns an error.
+ assert.commandWorked(this.adminCommand({setFeatureCompatibilityVersion: lastLTSFCV}));
+ }
+
+ testQueryStatsParam(expectedResult) {
+ if (expectedResult === true) {
+ assert.commandWorked(
+ this.adminCommand({setParameter: 1, internalQueryStatsRateLimit: -1}));
+ } else {
+ // Check that $queryStats related parameter does not work.
+ assert.commandFailed(
+ this.adminCommand({setParameter: 1, internalQueryStatsRateLimit: -1}));
+ }
+ }
+
+ testQueryStatsCommandFailure() {
+ assert.commandFailedWithCode(
+ this.adminCommand({aggregate: 1, pipeline: [{$queryStats: {}}], cursor: {}}),
+ [ErrorCodes.QueryFeatureNotAllowed, 40324]);
+ }
+
+ isShardedCluster() {
+ return false;
+ }
+
+ verifyQueryStatsOutput({expectedNShapes}) {
+ const queryStats = getQueryStats(this, {collName: this.collectionName});
+ assert.eq(expectedNShapes, queryStats.length, queryStats);
+ verifyMetrics(queryStats);
+ }
+}
+
+class ShardedClusterUpgradeDowngradeTestFixture extends UpgradeDowngradeTestFixture {
+ setup() {
+ jsTestLog("Starting Sharded Upgrade/Downgrade Test!");
+ this.shardedTest = new ShardingTest({
+ name: jsTestName(),
+ shards: 1,
+ mongos: 1,
+ config: 1,
+ rs: {nodes: [{binVersion: lastLTSVersion}, {binVersion: lastLTSVersion}]},
+ mongosOptions: {binVersion: lastLTSVersion},
+ });
+ this.createAndPopulateTestCollection();
+ }
+
+ isShardedCluster() {
+ return true;
+ }
+
+ adminCommand(command) {
+ return this.shardedTest.s.adminCommand(command);
+ }
+
+ getTestDB() {
+ return this.shardedTest.s.getDB(jsTestName());
+ }
+
+ upgradeBinaries() {
+ this.shardedTest.upgradeCluster('latest');
+ }
+
+ teardown() {
+ jsTestLog("Teardown ReplicaSet Upgrade/Downgrade Test!");
+ this.shardedTest.stop();
+ }
+}
+
+function runTest(fixture) {
+ // 0. Initialize the fixture, we begin with a binary version that doesn't support queryStats.
+ fixture.setup();
+
+ // 1. Test that queryStats related features don't work in the base binary.
+ // 1.a. Verify queryStats is disabled by checking that setting queryStats related parameters and
+ // running the $queryStats stage both fail.
+ fixture.testQueryStatsParam(false);
+ fixture.testQueryStatsCommandFailure();
+
+ // 1.b. Run some queries while running base binary. We don't expect these queries to be
+ // collected by queryStats.
+ {
+ let coll = fixture.getTestCollection();
+ let res = coll.aggregate([{$match: {x: 2}}]).toArray();
+ assert.eq(1, res.length, res);
+
+ res = coll.find({x: 2}).toArray();
+ assert.eq(1, res.length, res);
+ }
+
+ // 2. Upgrade both the binaries and FCV. After the upgrade we expect query stats features
+ // to work. Further, we verify that the previously executed queries were not collected by
+ // checking the results from the $queryStats stage.
+ fixture.upgradeBinaries();
+ fixture.upgradeFCV();
+
+ // 2.a. Verify that queryStats parameters can be set after the upgrade, and that previously
+ // executed queries were not collected.
+ fixture.testQueryStatsParam(true);
+ fixture.verifyQueryStatsOutput({expectedNShapes: 0});
+
+ // 2.b. Execute two new queries (i.e new query shapes) and check that they are collected.
+ {
+ let coll = fixture.getTestCollection();
+ let res = coll.aggregate([{$match: {x: 2}}, {$sort: {x: -1}}]).toArray();
+ assert.eq(1, res.length, res);
+
+ res = coll.find({x: 2}, {noCursorTimeout: true}).toArray();
+ assert.eq(1, res.length, res);
+
+ fixture.verifyQueryStatsOutput({
+ expectedNShapes: 2 /* 1 each for the above. $queryStats is not included because we
+ filter on the collection name. */
+ });
+ }
+
+ // 3. Downgrade FCV (without restarting). Without restarting the server, we expect the
+ // queryStatsStore to keep existing entries, but to not collect any more statistics while an FCV
+ // that doesn't support queryStats is in place.
+ fixture.downgradeFCV();
+
+ // 3.a. Run additional queries (new query shapes) after the downgrade.
+ {
+ let coll = fixture.getTestCollection();
+ let res = coll.aggregate([{$match: {x: 2}}]).toArray();
+ assert.eq(1, res.length, res);
+
+ res = coll.find({x: 2}).toArray();
+ assert.eq(1, res.length, res);
+ }
+
+ // 3.b. If we are testing a sharded cluster, we don't expect queryStats to be disabled after the
+ // FCV downgrade. This is because in a sharded cluster, query stats resides on mongos, and
+ // mongos doesn't have a concept of its own in memory FCV settings. When a sharded cluster has
+ // its FCV downgraded, it forwards the downgrade request to the shards and the config
+ // servers. However, the router itself bases its FCV on its binaries. In our case, once we
+ // upgrade the binary on the mongos, we can no longer downgrade the FCV to "disable" queryStats.
+ // As a result, in the sharded scenario we expect the two queries run after the downgrade to
+ // have been collected by query stats.
+ if (fixture.isShardedCluster()) {
+ fixture.verifyQueryStatsOutput({
+ expectedNShapes: 4 /* 2 from the previous queries + the two additional ones captured
+ after the downgrade. */
+ });
+ fixture.teardown();
+ return;
+ }
+
+ // 3.c. After the FCV downgrade (i.e FCV v5.0), running $queryStats should return an error.
+ fixture.testQueryStatsCommandFailure();
+
+ // 3.d. Upgrade the FCV without restart. QueryStatsStore should not have been cleared. Previous
+ // stats collected should be returned. The queries made during the downgrade should not
+ // have been collected. Note that getQueryStats() uses the same query to collect the statistics,
+ // so running $queryStats doesn't result in additional entries.
+ fixture.upgradeFCV();
+ fixture.verifyQueryStatsOutput({expectedNShapes: 2});
+
+ // 4. Test query stats during a failed FCV downgrade. During the failed FCV downgrade, the FCV
+ // reverts back to the lastLTSFCV which doesn't support queryStats.
+ jsTestLog("Turning the failpoint on.");
+ assert.commandWorked(
+ fixture.adminCommand({configureFailPoint: 'failDowngrading', mode: "alwaysOn"}));
+
+ assert.commandFailedWithCode(fixture.adminCommand({setFeatureCompatibilityVersion: lastLTSFCV}),
+ 549181);
+
+ // 4.a. Current FCV is lower than the FCV necessary (7.2) for queryStats to run. These queries
+ // should not be collected.
+ {
+ let coll = fixture.getTestCollection();
+ let res = coll.aggregate([{$match: {x: 2}}]).toArray();
+ assert.eq(1, res.length, res);
+
+ res = coll.find({x: 2}).toArray();
+ assert.eq(1, res.length, res);
+ }
+ // 4.b. Running $queryStats should return an error.
+ fixture.testQueryStatsCommandFailure(ErrorCodes.QueryFeatureNotAllowed);
+
+ // 4.c. Complete the downgrade, then successfully upgrade FCV. Check that the queries run during
+ // the failed downgrade were not collected.
+ assert.commandWorked(
+ fixture.adminCommand({configureFailPoint: 'failDowngrading', mode: "off"}));
+ assert.commandWorked(fixture.adminCommand({setFeatureCompatibilityVersion: lastLTSFCV}));
+
+ fixture.upgradeFCV();
+ fixture.verifyQueryStatsOutput({expectedNShapes: 2});
+
+ // 4.d. Execute two new queries (new query shapes), these should result in new entries.
+ {
+ let coll = fixture.getTestCollection();
+ let res = coll.aggregate([{$match: {x: 2}}], {allowDiskUse: false}).toArray();
+ assert.eq(1, res.length, res);
+
+ res = coll.find({x: 2}, {allowPartialResults: true}).toArray();
+ assert.eq(1, res.length, res);
+
+ fixture.verifyQueryStatsOutput({expectedNShapes: 4});
+ }
+
+ fixture.teardown();
+}
+
+// Perform Upgrade/Downgrade test on replica set.
+runTest(new UpgradeDowngradeTestFixture());
+// Perform Upgrade/Downgrade test on sharded cluster.
+runTest(new ShardedClusterUpgradeDowngradeTestFixture());
+})(); \ No newline at end of file
diff --git a/jstests/multiVersion/targetedTestsLastLtsFeatures/timeseries_collection_mixed_schema_index_build_stepdown.js b/jstests/multiVersion/targetedTestsLastLtsFeatures/timeseries_collection_mixed_schema_index_build_stepdown.js
index 7575c514c20..b66de0c43f0 100644
--- a/jstests/multiVersion/targetedTestsLastLtsFeatures/timeseries_collection_mixed_schema_index_build_stepdown.js
+++ b/jstests/multiVersion/targetedTestsLastLtsFeatures/timeseries_collection_mixed_schema_index_build_stepdown.js
@@ -13,7 +13,9 @@ load("jstests/libs/fail_point_util.js");
load("jstests/multiVersion/libs/multi_rs.js");
load('jstests/noPassthrough/libs/index_build.js');
-const oldVersion = "last-lts";
+// Since v5.0 no longer supports writing mixed schema buckets as of 5.0.29, pin the version
+// to 5.0.28 to retain coverage as v5.0 still supports the presence of mixed schema data.
+const oldVersion = "5.0.28";
const nodes = {
n1: {binVersion: oldVersion},
n2: {binVersion: oldVersion}
diff --git a/jstests/multiVersion/targetedTestsLastLtsFeatures/upgrade_downgrade_timeseries_collection_from_last_lts.js b/jstests/multiVersion/targetedTestsLastLtsFeatures/upgrade_downgrade_timeseries_collection_from_last_lts.js
index e714a38d698..d2fc1d83f3c 100644
--- a/jstests/multiVersion/targetedTestsLastLtsFeatures/upgrade_downgrade_timeseries_collection_from_last_lts.js
+++ b/jstests/multiVersion/targetedTestsLastLtsFeatures/upgrade_downgrade_timeseries_collection_from_last_lts.js
@@ -13,7 +13,9 @@
load("jstests/core/timeseries/libs/timeseries.js");
load("jstests/multiVersion/libs/multi_rs.js");
-const oldVersion = "last-lts";
+// Since v5.0 no longer supports writing mixed schema buckets as of 5.0.29, pin the version
+// to 5.0.28 to retain coverage as v5.0 still supports the presence of mixed schema data.
+const oldVersion = "5.0.28";
const nodes = {
n1: {binVersion: oldVersion},
n2: {binVersion: oldVersion}
diff --git a/jstests/noPassthrough/change_streams_per_shard_cursor.js b/jstests/noPassthrough/change_streams_per_shard_cursor.js
index dcd56fc80e9..caa945e6fce 100644
--- a/jstests/noPassthrough/change_streams_per_shard_cursor.js
+++ b/jstests/noPassthrough/change_streams_per_shard_cursor.js
@@ -67,9 +67,11 @@ assert.commandFailedWithCode(sdb.runCommand({
}),
6273801);
-// $out can't passthrough so it's not allowed.
+// $out can't passthrough so it's not allowed. This may be caught in parsing, or when preparing
+// the aggregation.
assert.commandFailedWithCode(
- assert.throws(() => pscWatch(sdb, "coll", shardId, {pipeline: [{$out: "h"}]})), 6273802);
+ assert.throws(() => pscWatch(sdb, "coll", shardId, {pipeline: [{$out: "h"}]})),
+ [6273802, ErrorCodes.IllegalOperation]);
// Shard option should be specified.
assert.commandFailedWithCode(
diff --git a/jstests/noPassthrough/change_streams_split_event_v1_v2_tokens.js b/jstests/noPassthrough/change_streams_split_event_v1_v2_tokens.js
index c4cdfa3b5c0..6913f42a11c 100644
--- a/jstests/noPassthrough/change_streams_split_event_v1_v2_tokens.js
+++ b/jstests/noPassthrough/change_streams_split_event_v1_v2_tokens.js
@@ -7,7 +7,17 @@ load("jstests/libs/collection_drop_recreate.js"); // For 'assert[Drop|Create]Co
const kLargeStringSize = 15 * 1024 * 1024;
-const st = new ShardingTest({shards: 2, config: 1, other: {rs: {nodes: 2}}});
+const st = new ShardingTest({
+ shards: 2,
+ config: 1,
+ other: {
+ rs: {
+ nodes: 2,
+ // Reserving enough of oplog space to accommodate 4 nearly 16MB-large changes.
+ oplogSize: 16 * 5
+ }
+ }
+});
let testDB = st.s.getDB(jsTestName());
let testColl = testDB["test"];
@@ -86,11 +96,12 @@ expectedEvents.push({operationType: "delete", documentKey: {_id: "b", shard: 2}}
assert.commandWorked(
st.s.adminCommand({refineCollectionShardKey: testColl.getFullName(), key: {shard: 1, _id: 1}}));
-assert.commandWorked(st.s.adminCommand({reshardCollection: testColl.getFullName(), key: {_id: 1}}));
+assert.commandWorked(st.s.adminCommand(
+ {reshardCollection: testColl.getFullName(), key: {_id: 1}, numInitialChunks: 2}));
expectedEvents.push({operationType: "reshardCollection"});
assert.commandWorked(testColl.dropIndex({largeField: 1}));
-expectedEvents.push({operationType: "dropIndexes"});
+expectedEvents.push({operationType: "dropIndexes"}, {operationType: "dropIndexes"});
const newTestCollectionName = "test_";
assert.commandWorked(testColl.renameCollection(newTestCollectionName));
@@ -108,6 +119,32 @@ expectedEvents.push({operationType: "dropDatabase"},
{operationType: "invalidate"},
{operationType: "dropDatabase"});
+// Leave only the last of the events with identical resume tokens, because the previous events will
+// be skipped when resuming from such a token.
+// TODO SERVER-90023: Remove this workaround when no longer needed.
+{
+ const csCursor = testDB.watch([], {
+ showExpandedEvents: true,
+ startAfter: testStartV1HWMToken,
+ $_generateV2ResumeTokens: false
+ });
+
+ // The 'drop', 'dropIndexes', and 'rename' events coming from different shards are likely to get
+ // identical resume tokens in v6.0.
+ for (let prevEvent = csCursor.next(), nextEvent; csCursor.hasNext(); prevEvent = nextEvent) {
+ nextEvent = csCursor.next();
+ if (bsonWoCompare(nextEvent._id, prevEvent._id) === 0) {
+ // If two or more consecutive events have identical resume tokens, remove all but the
+ // last from the expected events.
+ expectedEvents.splice(expectedEvents.findIndex(
+ (event) => (event.operationType === prevEvent.operationType)),
+ 1);
+ }
+ }
+
+ csCursor.close();
+}
+
// Helper function to assert on the given event fields.
function assertEventMatches(event, expectedEvent, errorMsg) {
for (const k in expectedEvent) {
diff --git a/jstests/noPassthrough/collmod_removes_invalid_index_options.js b/jstests/noPassthrough/collmod_removes_invalid_index_options.js
index 00d925568a3..69fa8f3b108 100644
--- a/jstests/noPassthrough/collmod_removes_invalid_index_options.js
+++ b/jstests/noPassthrough/collmod_removes_invalid_index_options.js
@@ -39,10 +39,14 @@ fpSecondary.off();
// Verify that validate detects indexes with invalid index options on both the primary and
// secondary nodes.
let validateRes = assert.commandWorked(primaryDB.runCommand({validate: collName}));
-assert(!validateRes.valid);
+assert(validateRes.valid, validateRes);
+assert.eq(validateRes.errors.length, 0, validateRes);
+assert.eq(validateRes.warnings.length, 2, validateRes);
validateRes = assert.commandWorked(secondaryDB.runCommand({validate: collName}));
-assert(!validateRes.valid);
+assert(validateRes.valid, validateRes);
+assert.eq(validateRes.errors.length, 0, validateRes);
+assert.eq(validateRes.warnings.length, 2, validateRes);
// Use collMod to remove the invalid index options in the collection.
assert.commandWorked(primaryDB.runCommand({collMod: collName}));
@@ -59,10 +63,14 @@ checkLog.containsJson(secondary, 23878, {fieldName: "xyz"});
// Verify that validate no longer detects indexes with invalid options on both the primary and
// secondary nodes.
validateRes = assert.commandWorked(primaryDB.runCommand({validate: collName}));
-assert(validateRes.valid);
+assert(validateRes.valid, validateRes);
+assert.eq(validateRes.errors.length, 0, validateRes);
+assert.eq(validateRes.warnings.length, 0, validateRes);
validateRes = assert.commandWorked(secondaryDB.runCommand({validate: collName}));
-assert(validateRes.valid);
+assert(validateRes.valid, validateRes);
+assert.eq(validateRes.errors.length, 0, validateRes);
+assert.eq(validateRes.warnings.length, 0, validateRes);
rst.stopSet();
}());
diff --git a/jstests/noPassthrough/comment_field_passthrough.js b/jstests/noPassthrough/comment_field_passthrough.js
index 221b56f4950..daf40821ea7 100644
--- a/jstests/noPassthrough/comment_field_passthrough.js
+++ b/jstests/noPassthrough/comment_field_passthrough.js
@@ -19,8 +19,13 @@ load("jstests/libs/fail_point_util.js"); // Helper to enable/disable failpoint
const tests = authCommandsLib.tests;
// The following commands require additional start up configuration and hence need to be skipped.
-const denylistedTests =
- ["startRecordingTraffic", "stopRecordingTraffic", "addShardToZone", "removeShardFromZone"];
+const denylistedTests = [
+ "startRecordingTraffic",
+ "stopRecordingTraffic",
+ "addShardToZone",
+ "removeShardFromZone",
+ "aggregate_$search" // TODO SERVER-82767 enable this test.
+];
function runTests(tests, conn, impls) {
const firstDb = conn.getDB(firstDbName);
diff --git a/jstests/noPassthrough/compound_2dsphere_max_index_keys.js b/jstests/noPassthrough/compound_2dsphere_max_index_keys.js
index d6eaa272afa..1585b5a568e 100644
--- a/jstests/noPassthrough/compound_2dsphere_max_index_keys.js
+++ b/jstests/noPassthrough/compound_2dsphere_max_index_keys.js
@@ -55,10 +55,10 @@ const runTest = (indexDefinition) => {
assert.commandFailed(coll.insert(
{x: polygon, y: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]}));
- // We should also get an error when we try to validate.
+ // We should also get a warning when we try to validate.
const validation = assert.commandWorked(coll.validate());
- assert.eq(validation.errors.length, 1);
- assert(validation.errors[0].includes('CannotBuildIndexKeys'));
+ assert.eq(validation.warnings.length, 1);
+ assert(validation.warnings[0].includes('CannotBuildIndexKeys'));
// We should be able to remove a problem document.
assert.commandWorked(coll.deleteOne({_id: 'problem1'}));
diff --git a/jstests/noPassthrough/deep_merge_server_parameters.js b/jstests/noPassthrough/deep_merge_server_parameters.js
new file mode 100644
index 00000000000..a3d33615c3a
--- /dev/null
+++ b/jstests/noPassthrough/deep_merge_server_parameters.js
@@ -0,0 +1,98 @@
+/**
+ * Tests that ShardingTest parameters that are specified in the other field do not overwrite general
+ * parameters. Also includes unit tests to test new deepMerge helper function.
+ */
+
+// Basic test to ensure both parameters are appended in config options instead of replaced.
+let st = new ShardingTest({
+ configOptions: {
+ setParameter: {
+ reshardingCriticalSectionTimeoutMillis: 86400000,
+ }
+ },
+ shards: 1,
+ other: {
+ configOptions: {
+ setParameter: {
+ logComponentVerbosity:
+ "{verbosity: 0, command: {verbosity: 1}, network: {verbosity: 1, asio: {verbosity: 2}}}",
+ }
+ }
+ }
+});
+// Check that reshardingCriticalSectionTimeoutMillis is in config options with the proper value.
+assert(st._otherParams.configOptions.setParameter.hasOwnProperty(
+ "reshardingCriticalSectionTimeoutMillis"),
+ "setParameter does not contain reshardingCriticalSectionTimeoutMillis");
+assert.eq(st._otherParams.configOptions.setParameter.reshardingCriticalSectionTimeoutMillis,
+ 86400000,
+ "The value of reshardingCriticalSectionTimeoutMillis is not correct");
+// Check that logComponentVerbosity is in config options with the proper value.
+assert(st._otherParams.configOptions.setParameter.hasOwnProperty("logComponentVerbosity"),
+ "setParameter does not contain logComponentVerbosity");
+assert.eq(st._otherParams.configOptions.setParameter.logComponentVerbosity,
+ "{verbosity: 0, command: {verbosity: 1}, network: {verbosity: 1, asio: {verbosity: 2}}}",
+ "The value of logComponentVerbosity is not correct");
+
+st.stop();
+
+// Additional unit tests for new deepMerge function
+
+// deepMerge with empty object.
+let emptyTest = Object.deepMerge({});
+assert(Object.keys(emptyTest).length === 0);
+
+// deepMerge with one empty object.
+let oneArgumentTest = Object.deepMerge({}, {int: 1});
+assert(Object.keys(oneArgumentTest).length === 1);
+assert(oneArgumentTest.hasOwnProperty("int"));
+assert.eq(oneArgumentTest.int, 1);
+
+// deepMerge with matching keys and two array fields.
+let arrayTest = Object.deepMerge({arr: [1, 2, 3]}, {arr: [4, 5, 6]});
+assert(arrayTest.hasOwnProperty("arr"));
+assert.eq(arrayTest.arr, [1, 2, 3, 4, 5, 6]);
+
+// deepMerge with matching keys and two object fields.
+let twoObjectTest = Object.deepMerge({nest: {one: 1}}, {nest: {two: 2}});
+assert(twoObjectTest.hasOwnProperty("nest"));
+assert(twoObjectTest.nest.hasOwnProperty("one"));
+assert(twoObjectTest.nest.hasOwnProperty("two"));
+assert.eq(twoObjectTest.nest.one, 1);
+assert.eq(twoObjectTest.nest.two, 2);
+
+// deepMerge with 3 objects, two of which have a matching key.
+let obj1 = {a: {num: 123}};
+let obj2 = {a: {letter: "a"}};
+let obj3 = {b: "hello"};
+let threeObjectTest = Object.deepMerge(obj1, obj2, obj3);
+assert(threeObjectTest.hasOwnProperty("a"));
+assert(threeObjectTest.hasOwnProperty("b"));
+assert(threeObjectTest.a.hasOwnProperty("num"));
+assert(threeObjectTest.a.hasOwnProperty("letter"));
+assert.eq(threeObjectTest.a.num, 123);
+assert.eq(threeObjectTest.a.letter, "a");
+assert.eq(threeObjectTest.b, "hello");
+
+// deepMerge with one undefined object.
+let undefinedTest = Object.deepMerge(undefined);
+assert.eq(Object.keys(undefinedTest).length, 0);
+
+// deepMerge with two objects, one of which is undefined
+let undefinedMergeTest = Object.deepMerge(undefined, {a: 1});
+assert(undefinedMergeTest.hasOwnProperty("a"));
+assert.eq(undefinedMergeTest.a, 1);
+assert.eq(Object.keys(undefinedMergeTest).length, 1);
+
+// deepMerge with two objects with a swapped order from the previous test.
+let orderTest = Object.deepMerge({a: 1}, undefined);
+assert(orderTest.hasOwnProperty("a"));
+assert.eq(orderTest.a, 1);
+assert.eq(Object.keys(orderTest).length, 1);
+
+// deepMerge with two objects, one of which has a undefined value with a defined key.
+let undefinedValueTest = Object.deepMerge({a: 1}, {b: undefined});
+assert(undefinedValueTest.hasOwnProperty("a"));
+assert(undefinedValueTest.hasOwnProperty("b"));
+assert.eq(undefinedValueTest.a, 1);
+assert.eq(undefinedValueTest.b, undefined);
diff --git a/jstests/noPassthrough/disable_test_parameters_when_no_set_parameters.js b/jstests/noPassthrough/disable_test_parameters_when_no_set_parameters.js
new file mode 100644
index 00000000000..2ae8f18102c
--- /dev/null
+++ b/jstests/noPassthrough/disable_test_parameters_when_no_set_parameters.js
@@ -0,0 +1,48 @@
+/**
+ * Tests that when setParameter is not included in the startup options, we still disable test-only
+ * parameters. This was a bug fixed in SERVER-89495.
+ *
+ * Incompatible with concurrency because we modify MongoRunner._startWithArgs.
+ * @tags: [incompatible_with_concurrency_simultaneous]
+ */
+const originalStartWithArgs = MongoRunner._startWithArgs;
+
+MongoRunner._startWithArgs = function(argArray, env, waitForConnect) {
+ // Remove all setParameters by iteratively matching the pattern ["--setParameter", "name=value"]
+ // and deleting both entries from the arg array.
+ let idx = argArray.indexOf("--setParameter");
+ while (idx !== -1) {
+ argArray.splice(idx, 2);
+ idx = argArray.indexOf("--setParameter");
+ }
+
+ // Here and below is equivalent to the original code, minus a case that we never hit.
+ const port = MongoRunner.parsePort.apply(null, argArray);
+ let pid = -1;
+ if (env === undefined) {
+ pid = _startMongoProgram.apply(null, argArray);
+ } else {
+ pid = _startMongoProgram({args: argArray, env: env});
+ }
+
+ if (!waitForConnect) {
+ print("Skip waiting to connect to node with pid=" + pid + ", port=" + port);
+ return {
+ pid: pid,
+ port: port,
+ };
+ }
+
+ return MongoRunner.awaitConnection({pid, port});
+};
+
+const conn = MongoRunner.runMongod();
+const db = conn.getDB('admin');
+
+// We shouldn't be able to fetch test-only server parameters.
+const res = db.runCommand({getParameter: 1, requireApiVersion: 1});
+assert(!res.ok);
+assert.eq(res.errmsg, "no option found to get", res);
+
+MongoRunner.stopMongod(conn);
+MongoRunner._startWithArgs = originalStartWithArgs;
diff --git a/jstests/noPassthrough/dispatch_pipeline_to_all_shardservers.js b/jstests/noPassthrough/dispatch_pipeline_to_all_shardservers.js
new file mode 100644
index 00000000000..3864ceec682
--- /dev/null
+++ b/jstests/noPassthrough/dispatch_pipeline_to_all_shardservers.js
@@ -0,0 +1,90 @@
+/**
+ * Test that mongos can establish cursors on all nodes within a sharded cluster.
+ */
+
+(function() {
+"use strict";
+function runTest({shards, nodes}) {
+ const st = new ShardingTest({
+ mongos: 1,
+ shards,
+ config: 1,
+ rs: {nodes},
+ });
+ const db = st.s.getDB(jsTestName());
+ const results = db.getSiblingDB("admin")
+ .aggregate([
+ {$_internalShardServerInfo: {}},
+ ])
+ .toArray();
+
+ // Assert there are $currentOp results from all hosts.
+ const totalHosts = shards * nodes;
+ assert.eq(totalHosts, results.length);
+ st.stop();
+}
+
+runTest({shards: 1, nodes: 2});
+runTest({shards: 1, nodes: 1});
+runTest({shards: 2, nodes: 1});
+runTest({shards: 2, nodes: 2});
+runTest({shards: 2, nodes: 3});
+runTest({shards: 3, nodes: 2});
+}());
+
+/**
+ * Test that remote cursors are closed on all nodes when there is an error on one or more nodes.
+ */
+(function() {
+"use strict";
+const st = new ShardingTest({
+ mongos: 1,
+ shards: 1,
+ config: 1,
+ rs: {nodes: 2},
+});
+const db = st.s.getDB(jsTestName());
+const primary = st.rs0.nodes[0];
+const secondary = st.rs0.nodes[1];
+
+assert.commandWorked(primary.adminCommand({
+ configureFailPoint: 'failCommand',
+ mode: 'alwaysOn',
+ data: {
+ errorCode: ErrorCodes.FailPointEnabled,
+ failCommands: ["aggregate"],
+ failInternalCommands: true,
+ }
+}));
+assert.commandFailed(db.adminCommand({
+ aggregate: 1,
+ pipeline: [
+ {$_internalShardServerInfo: {}},
+ ],
+ cursor: {batchSize: 1},
+}));
+primary.adminCommand({configureFailPoint: 'failCommand', mode: 'off'});
+
+assert.soon(() => {
+ const primaryCursors =
+ primary.getDB("admin")
+ .aggregate([{$currentOp: {idleCursors: true}}, {$match: {type: "idleCursor"}}])
+ .toArray();
+ const secondaryCursors =
+ secondary.getDB("admin")
+ .aggregate([{$currentOp: {idleCursors: true}}, {$match: {type: "idleCursor"}}])
+ .toArray();
+
+ try {
+ assert.eq(0, primaryCursors.length, tojson(primaryCursors));
+ assert.eq(0, secondaryCursors.length, tojson(secondaryCursors));
+ } catch (err) {
+ jsTestLog(tojson(err));
+ return false;
+ }
+
+ return true;
+});
+
+st.stop();
+}());
diff --git a/jstests/noPassthrough/durable_history_index_usage.js b/jstests/noPassthrough/durable_history_index_usage.js
index 9e4c93a90ed..b2f7c01f6c5 100644
--- a/jstests/noPassthrough/durable_history_index_usage.js
+++ b/jstests/noPassthrough/durable_history_index_usage.js
@@ -109,13 +109,15 @@ replTest.start(
true /* restart */);
const checkLogs = function() {
- // The index build was not yet completed at the recovery timestamp, it will be dropped and
- // rebuilt.
- checkLog.containsJson(primary(), 22206, {
+ // Found index from unfinished build.
+ checkLog.containsJson(primary(), 22253, {
index: "a_1",
namespace: coll().getFullName(),
});
+ // Resetting unfinished index.
+ checkLog.containsJson(primary(), 6987700, {namespace: coll().getFullName(), index: "a_1"});
+
// Index build restarting.
checkLog.containsJson(primary(), 20660);
};
diff --git a/jstests/noPassthrough/index_build_external_and_internal_abort_do_not_deadlock_single_phase.js b/jstests/noPassthrough/index_build_external_and_internal_abort_do_not_deadlock_single_phase.js
new file mode 100644
index 00000000000..c49e47bb25a
--- /dev/null
+++ b/jstests/noPassthrough/index_build_external_and_internal_abort_do_not_deadlock_single_phase.js
@@ -0,0 +1,58 @@
+/**
+ * Tests dropping a collection (causing an external index build abort) does not deadlock with an
+ * internal self abort for single-phase index builds.
+ */
+(function() {
+"use strict";
+
+load('jstests/noPassthrough/libs/index_build.js');
+load("jstests/libs/fail_point_util.js");
+
+// A standalone configuration is key to running the index build single-phase.
+const conn = MongoRunner.runMongod();
+
+const dbName = 'test';
+const collName = 'coll';
+const db = conn.getDB(dbName);
+const coll = db.getCollection(collName);
+
+coll.drop();
+assert.commandWorked(coll.insert({a: 1}));
+
+// Hang after the index build has checked if the build is already aborted, but before taking
+// collection locks for cleanup.
+const hangBeforeCleanup = configureFailPoint(db, 'hangIndexBuildBeforeAbortCleanUp');
+const hangAfterIndexBuildDumpsInsertsFromBulk =
+ configureFailPoint(db, "hangAfterIndexBuildDumpsInsertsFromBulk");
+
+const createIdx = IndexBuildTest.startIndexBuild(
+ conn, coll.getFullName(), {a: 1}, null, [ErrorCodes.Interrupted]);
+// Make sure we get the builder's opId, instead of the connection's.
+const filter = {
+ "desc": {$regex: /IndexBuildsCoordinatorMongod.*/}
+};
+const opId = IndexBuildTest.waitForIndexBuildToStart(db, collName, 'a_1', filter);
+
+hangAfterIndexBuildDumpsInsertsFromBulk.wait();
+jsTestLog("Running killOp to force self-abort");
+assert.commandWorked(db.killOp(opId));
+hangAfterIndexBuildDumpsInsertsFromBulk.off();
+
+hangBeforeCleanup.wait();
+
+const hangAfterCollDropHasLocks =
+ configureFailPoint(db, 'hangAbortIndexBuildByBuildUUIDAfterLocks');
+const collDrop = startParallelShell(funWithArgs(function(dbName, collName) {
+ db.getSiblingDB(dbName).getCollection(collName).drop();
+ }, dbName, collName), conn.port);
+
+hangAfterCollDropHasLocks.wait();
+hangBeforeCleanup.off();
+hangAfterCollDropHasLocks.off();
+
+jsTestLog("Waiting for collection drop shell to return");
+collDrop();
+createIdx();
+
+MongoRunner.stopMongod(conn);
+})();
diff --git a/jstests/noPassthrough/index_build_external_and_internal_abort_do_not_deadlock_two_phase.js b/jstests/noPassthrough/index_build_external_and_internal_abort_do_not_deadlock_two_phase.js
new file mode 100644
index 00000000000..0ba1afaf14b
--- /dev/null
+++ b/jstests/noPassthrough/index_build_external_and_internal_abort_do_not_deadlock_two_phase.js
@@ -0,0 +1,92 @@
+/**
+ * Tests dropping a collection (causing an external index build abort) does not deadlock with an
+ * internal self abort for two-phase index builds.
+ *
+ * @tags: [
+ * requires_replication,
+ * ]
+ */
+(function() {
+"use strict";
+
+load('jstests/noPassthrough/libs/index_build.js');
+load("jstests/libs/fail_point_util.js");
+
+const rst = new ReplSetTest({
+ nodes: [
+ {},
+ {
+ // Disallow elections on secondary.
+ rsConfig: {
+ priority: 0,
+ },
+ },
+ ]
+});
+rst.startSet();
+rst.initiate();
+
+const primary = rst.getPrimary();
+const primaryDB = primary.getDB('test');
+const primaryColl = primaryDB.getCollection('test');
+
+primaryColl.drop();
+assert.commandWorked(primaryColl.insert({a: 1}));
+
+// Pause the index builds on the secondary, using the 'hangAfterStartingIndexBuild' failpoint.
+const hangBeforeCleanup = configureFailPoint(primaryDB, 'hangIndexBuildBeforeAbortCleanUp');
+const hangAfterIndexBuildSecondDrain =
+ configureFailPoint(primaryDB, "hangAfterIndexBuildSecondDrain");
+
+// Block secondary to avoid commitQuorum being fullfilled.
+IndexBuildTest.pauseIndexBuilds(rst.getSecondary());
+
+jsTestLog("Waiting for index build to start");
+const createIdx = IndexBuildTest.startIndexBuild(
+ primary, primaryColl.getFullName(), {a: 1}, null, [ErrorCodes.Interrupted]);
+
+// Make sure we get the builder's opId, instead of the connection's.
+const filter = {
+ "desc": {$regex: /IndexBuildsCoordinatorMongod.*/}
+};
+const opId =
+ IndexBuildTest.waitForIndexBuildToStart(primaryDB, primaryColl.getName(), 'a_1', filter);
+const buildUUID =
+ IndexBuildTest
+ .assertIndexesSoon(primaryColl, 2, ['_id_'], ['a_1'], {includeBuildUUIDs: true})['a_1']
+ .buildUUID;
+
+hangAfterIndexBuildSecondDrain.wait();
+jsTestLog("Running killOp to force self-abort on primary");
+assert.commandWorked(primaryDB.killOp(opId));
+hangAfterIndexBuildSecondDrain.off();
+
+// Wait for the index build to be in clean up path.
+hangBeforeCleanup.wait();
+
+const hangAfterCollDropHasLocks =
+ configureFailPoint(primaryDB, 'hangAbortIndexBuildByBuildUUIDAfterLocks');
+
+const collDrop = startParallelShell(funWithArgs(function(dbName, collName) {
+ jsTestLog("Dropping collection");
+ db.getSiblingDB(dbName).getCollection(collName).drop();
+ }, primaryDB.getName(), primaryColl.getName()), primary.port);
+
+hangAfterCollDropHasLocks.wait();
+hangBeforeCleanup.off();
+hangAfterCollDropHasLocks.off();
+
+jsTestLog("Waiting for the index build to be killed");
+// "Index build: joined after abort".
+checkLog.containsJson(primary, 20655, {
+ buildUUID: function(uuid) {
+ return uuid && uuid["uuid"]["$uuid"] === extractUUIDFromObject(buildUUID);
+ }
+});
+
+jsTestLog("Waiting for collection drop shell to return");
+collDrop();
+createIdx();
+
+rst.stopSet();
+})();
diff --git a/jstests/noPassthrough/index_startup_prepareunique.js b/jstests/noPassthrough/index_startup_prepareunique.js
new file mode 100644
index 00000000000..dfa93cd6827
--- /dev/null
+++ b/jstests/noPassthrough/index_startup_prepareunique.js
@@ -0,0 +1,24 @@
+/**
+ * Checks that a prepareUnique index does not block startup.
+ *
+ * @tags: [requires_persistence, requires_replication]
+ */
+(function() {
+'use strict';
+
+const rst = new ReplSetTest({nodes: 1});
+rst.startSet();
+rst.initiate();
+
+let primary = rst.getPrimary();
+assert.commandWorked(primary.getDB("admin").system.version.createIndex({"version": 1}));
+assert.commandWorked(primary.getDB("admin").runCommand(
+ {collMod: "system.version", index: {keyPattern: {version: 1}, prepareUnique: true}}));
+
+// Restarting the node after prepareUnique: true should succeed.
+rst.restart(primary);
+rst.waitForPrimary();
+primary = rst.getPrimary();
+
+rst.stopSet();
+})();
diff --git a/jstests/noPassthrough/initial_sync_same_index_spec.js b/jstests/noPassthrough/initial_sync_same_index_spec.js
new file mode 100644
index 00000000000..5746a6091b3
--- /dev/null
+++ b/jstests/noPassthrough/initial_sync_same_index_spec.js
@@ -0,0 +1,98 @@
+/**
+ * Test that initial sync does not fail if an identical index spec is created, dropped and
+ * recreated.
+ */
+
+(function() {
+"use strict";
+
+load("jstests/libs/fail_point_util.js"); // for kDefaultWaitForFailPointTimeout
+
+const testName = "initial_sync_same_index_spec";
+const dbName = testName;
+const collName = "testcoll";
+
+// Set up a stable two node replica set.
+let replTest = new ReplSetTest({
+ name: testName,
+ nodes: [{}, {rsConfig: {priority: 0, votes: 0}}],
+});
+replTest.startSet();
+replTest.initiateWithHighElectionTimeout();
+
+let primary = replTest.getPrimary();
+let secondary = replTest.getSecondary();
+
+let primaryDB = primary.getDB(dbName);
+let secondaryDB = secondary.getDB(dbName);
+
+let primaryColl = primaryDB[collName];
+let secondaryColl = secondaryDB[collName];
+
+// Insert data into the collection for initial sync to copy.
+assert.commandWorked(primaryColl.insert([{_id: 1, a: 1}, {_id: 2, a: 2}]));
+
+// Set WC to 1. The default WC is majority and the replica set will not be able to satisfy majority
+// index create/drop later.
+assert.commandWorked(primary.adminCommand(
+ {setDefaultRWConcern: 1, defaultWriteConcern: {w: 1}, writeConcern: {w: "majority"}}));
+
+/**
+ * Restart the the secondary with no data in order to provoke an initial sync from the primary.
+ * Use startup setParameter to set failpoints to pause the initial sync before indexes are fetched.
+ */
+
+const fp = 'hangBeforeClonerStage';
+let secondaryStartupParams = {};
+secondaryStartupParams['failpoint.' + fp] = tojson({
+ mode: 'alwaysOn',
+ data: {cloner: "CollectionCloner", stage: "listIndexes", nss: primaryColl.getFullName()}
+});
+
+// Only try initial sync once, so any failure syncing indexes will be surfaced.
+secondaryStartupParams['numInitialSyncAttempts'] = 1;
+
+const startupOptions = {
+ startClean: true,
+ setParameter: secondaryStartupParams
+};
+
+jsTestLog(
+ "Restarting the the secondary with no data in order to provoke an initial sync from the " +
+ "primary. Using startup options: " + tojson(startupOptions));
+secondary = replTest.restart(secondary, startupOptions);
+secondaryDB = secondary.getDB(dbName);
+secondaryColl = secondaryDB[collName];
+
+jsTestLog("Waiting for secondary to reach failPoint '" + fp + "'");
+assert.commandWorked(secondary.adminCommand(
+ {waitForFailPoint: fp, timesEntered: 1, maxTimeMS: kDefaultWaitForFailPointTimeout}));
+
+// Restarting the secondary may have resulted in an election. Wait until the system stabilizes and
+// reaches RS_STARTUP2 state.
+replTest.getPrimary();
+replTest.waitForState(secondary, ReplSetTest.State.STARTUP_2);
+
+/**
+ * Now that the secondary is hanging in initial sync, create, drop and recreate identical indexes to
+ * ensure it is correctly handled by initial sync (when the failpoint is removed).
+ */
+
+jsTestLog("Creating index on the primary.");
+assert.commandWorked(primaryColl.createIndex({a: 1}, {name: "a1"}));
+
+jsTestLog("Dropping index on the primary.");
+assert.commandWorked(primaryColl.dropIndex("a1"));
+
+jsTestLog("Recreating index with same spec on the primary.");
+assert.commandWorked(primaryColl.createIndex({a: 1}, {name: "a2"}));
+
+jsTestLog("Allowing secondary initial sync to resume.");
+assert.commandWorked(
+ secondary.adminCommand({configureFailPoint: "hangBeforeClonerStage", mode: 'off'}));
+
+jsTestLog("Waiting for initial sync to complete successfully.");
+replTest.waitForState(secondary, ReplSetTest.State.SECONDARY);
+
+replTest.stopSet();
+})();
diff --git a/jstests/noPassthrough/libs/index_build.js b/jstests/noPassthrough/libs/index_build.js
index 25e9c6ba7af..a8016754872 100644
--- a/jstests/noPassthrough/libs/index_build.js
+++ b/jstests/noPassthrough/libs/index_build.js
@@ -215,6 +215,16 @@ var IndexBuildTest = class {
return indexMap;
}
+ static assertIndexesSoon(coll, numIndexes, readyIndexes, notReadyIndexes, options) {
+ var indexMap;
+ assert.soonNoExcept(function() {
+ indexMap = IndexBuildTest.assertIndexes(
+ coll, numIndexes, readyIndexes, notReadyIndexes, options);
+ return true;
+ });
+ return indexMap;
+ }
+
/**
* Prevent subsequent index builds from running to completion.
*/
diff --git a/jstests/noPassthrough/libs/missing_index_ident.js b/jstests/noPassthrough/libs/missing_index_ident.js
index ae18d297158..3be61a404c2 100644
--- a/jstests/noPassthrough/libs/missing_index_ident.js
+++ b/jstests/noPassthrough/libs/missing_index_ident.js
@@ -76,17 +76,11 @@ const MissingIndexIdent = class {
});
// Since the index build was not yet completed at the recovery timestamp, its ident will
- // be dropped.
- checkLog.containsJson(conn, 22206, {
+ // be reset.
+ checkLog.containsJson(conn, 6987700, {
index: 'a_1',
namespace: coll.getFullName(),
ident: ident,
});
-
- // The oldest timestamp moving forward will cause the ident reaper to drop the ident.
- checkLog.containsJson(conn, 22237, {
- ident: ident,
- dropTimestamp: {$timestamp: {t: 0, i: 0}},
- });
}
};
diff --git a/jstests/core/notablescan.js b/jstests/noPassthrough/notablescan.js
index e99ecd013e8..07aeb12d8e6 100644
--- a/jstests/core/notablescan.js
+++ b/jstests/noPassthrough/notablescan.js
@@ -24,6 +24,9 @@ function checkError(err) {
assert.includes(err.toString(), "'notablescan'");
}
+const conn = MongoRunner.runMongod();
+assert.neq(null, conn, "mongod failed to start.");
+let db = conn.getDB(jsTestName());
const colName = jsTestName();
let coll = db.getCollection(colName);
coll.drop();
@@ -81,6 +84,5 @@ assert.commandWorked(db.adminCommand({setParameter: 1, notablescan: true}));
assert.commandWorked(
db.runCommand({aggregate: colName, pipeline: [{$match: {_id: 22}}], cursor: {}}));
}
-// Set it back to the original value.
-assert.commandWorked(db.adminCommand({setParameter: 1, notablescan: false}));
+MongoRunner.stopMongod(conn);
})();
diff --git a/jstests/noPassthrough/oplog_application_while_recovering_must_succeed.js b/jstests/noPassthrough/oplog_application_while_recovering_must_succeed.js
index 07a68e02b7f..99ef9bb517f 100644
--- a/jstests/noPassthrough/oplog_application_while_recovering_must_succeed.js
+++ b/jstests/noPassthrough/oplog_application_while_recovering_must_succeed.js
@@ -5,6 +5,7 @@
* @tags: [
* requires_persistence,
* requires_replication,
+ * incompatible_with_windows_tls,
* ]
*/
(function() {
diff --git a/jstests/noPassthrough/or_pushdown_disable_optimization.js b/jstests/noPassthrough/or_pushdown_disable_optimization.js
new file mode 100644
index 00000000000..58c4ea1f8d2
--- /dev/null
+++ b/jstests/noPassthrough/or_pushdown_disable_optimization.js
@@ -0,0 +1,39 @@
+/**
+ * Test that queries eligible for OR-pushdown optimization do not crash the server when the
+ * 'disableMatchExpressionOptimization' failpoint is enabled.
+ *
+ * Originally designed to reproduce SERVER-70597.
+ */
+(function() {
+"use strict";
+
+const conn = MongoRunner.runMongod();
+const db = conn.getDB("test");
+
+assert.commandWorked(
+ db.adminCommand({configureFailPoint: "disableMatchExpressionOptimization", mode: "alwaysOn"}));
+
+const coll = db.getCollection(jsTestName());
+coll.drop();
+assert.commandWorked(coll.createIndex({a: 1, b: 1}));
+
+let docs = [];
+for (let a = 1; a <= 3; ++a) {
+ for (let b = 1; b <= 3; ++b) {
+ docs.push({a, b});
+ }
+}
+assert.commandWorked(coll.insert(docs));
+
+// This query has a nested $and, and a one-argument contained $or. Normally we canonicalize this
+// predicate by flattening the $and and unwrapping the $or. The OR-pushdown optimization assumes the
+// predicate has been canonicalized, but this assumption is broken by the failpoint.
+const results = coll.aggregate([
+ {$match: {$and: [{$and: [{a: 2}]}, {$or: [{b: 3}]}]}},
+ {$unset: "_id"},
+ ])
+ .toArray();
+assert.eq(results, [{a: 2, b: 3}]);
+
+MongoRunner.stopMongod(conn);
+})();
diff --git a/jstests/noPassthrough/profile_query_planning_time_metric.js b/jstests/noPassthrough/profile_query_planning_time_metric.js
new file mode 100644
index 00000000000..d8748514015
--- /dev/null
+++ b/jstests/noPassthrough/profile_query_planning_time_metric.js
@@ -0,0 +1,70 @@
+/**
+ * Tests that the query planning time is captured in the profiler.
+ */
+(function() {
+"use strict";
+
+load('jstests/libs/analyze_plan.js');
+load("jstests/libs/profiler.js"); // For getLatestProfilerEntry.
+
+const conn = MongoRunner.runMongod();
+const testDB = conn.getDB('test');
+var coll = testDB[jsTestName()];
+
+var coll = testDB[jsTestName()];
+var collTwo = testDB[jsTestName() + 'Two'];
+coll.drop();
+
+for (var i = 0; i < 100; i++) {
+ coll.insert({foo: 0});
+ coll.insert({foo: 1});
+ collTwo.insert({foo: Math.random(0, 1), bar: Math.random(0, 1)});
+}
+assert.commandWorked(testDB.setProfilingLevel(2));
+var commandProfilerFilter = {op: "command", ns: "test.profile_query_planning_time_metric"};
+var findProfilerFilter = {op: "query", ns: "test.profile_query_planning_time_metric"};
+
+function verifyProfilerLog(profilerFilter) {
+ let profileObj = getLatestProfilerEntry(testDB, profilerFilter);
+ assert.gt(profileObj.planningTimeMicros, 0);
+}
+
+// agg query
+coll.aggregate([{
+ $setWindowFields: {
+ sortBy: {_id: 1},
+ output: {foo: {$linearFill: "$foo"}},
+ }
+}]);
+verifyProfilerLog(commandProfilerFilter);
+
+// agg query with some stages pushed to find layer.
+coll.aggregate([{$match: {foo: 0}}, {$group: {_id: null, count: {$sum: 1}}}]);
+verifyProfilerLog(commandProfilerFilter);
+
+// agg query with all stages pushed to find layer.
+coll.aggregate([{$sort: {foo: 1}}]);
+verifyProfilerLog(commandProfilerFilter);
+
+// multiple batches require multiple plan executors. We want to confirm we are only storing the
+// metrics for the outer executor associated with planning the query, and not a subsequent executor
+// that is constructed when a new operation context gets created during getMore() calls.
+coll.aggregate([{$unionWith: {coll: collTwo.getName()}}], {cursor: {batchSize: 2}});
+verifyProfilerLog(commandProfilerFilter);
+
+// $lookup has inner executor/cursor, we want to confirm we are only reporting metrics from the
+// outer executor associated with planning the query.
+coll.aggregate({
+ $lookup: {from: collTwo.getName(), localField: "foo", foreignField: "bar", as: "merged_docs"}
+});
+verifyProfilerLog(commandProfilerFilter);
+
+// Count and find have different entry points (eg different run() methods) from agg and we want to
+// confirm we are starting the timer as planning begins in each of these workflows/paths.
+coll.count({foo: 0});
+verifyProfilerLog(commandProfilerFilter);
+
+coll.findOne({});
+verifyProfilerLog(findProfilerFilter);
+MongoRunner.stopMongod(conn);
+}());
diff --git a/jstests/noPassthrough/queryStats/agg_cmd_one_way_tokenization.js b/jstests/noPassthrough/queryStats/agg_cmd_one_way_tokenization.js
new file mode 100644
index 00000000000..27e4b317faa
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/agg_cmd_one_way_tokenization.js
@@ -0,0 +1,187 @@
+/**
+ * Test that $queryStats properly tokenizes aggregation commands, on mongod and mongos.
+ * @tags: [requires_fcv_60]
+ */
+load("jstests/libs/query_stats_utils.js");
+(function() {
+"use strict";
+
+const kHashedDbName = "iDlS7h5jf5HHxWPJpeHRbA+jLTNNZaqxVVkplrEkfko=";
+const kHashedCollName = "w6Ax20mVkbJu4wQWAMjL8Sl+DfXAr2Zqdc3kJRB7Oo0=";
+const kHashedFieldA = "GDiF6ZEXkeo4kbKyKEAAViZ+2RHIVxBQV9S6b6Lu7gU=";
+const kHashedFieldB = "m1xtUkfSpZNxXjNZYKwo86vGD37Zxmd2gtt+TXDO558=";
+
+function verifyConsistentFields(key) {
+ assert.eq({"db": `${kHashedDbName}`, "coll": `${kHashedCollName}`}, key.queryShape.cmdNs);
+ assert.eq("aggregate", key.queryShape.command);
+ assert.eq(kShellApplicationName, key.client.application.name);
+}
+
+function runTest(conn) {
+ const db = conn.getDB("testDB");
+ const admin = conn.getDB("admin");
+
+ db.test.drop();
+ db.otherColl.drop();
+ assert.commandWorked(db.test.insert({a: "foobar", b: 15}));
+ assert.commandWorked(db.test.insert({a: "foobar", b: 20}));
+ assert.commandWorked(db.otherColl.insert({a: "foobar", price: 2.50}));
+
+ // First checks proper tokenization on a basic pipeline.
+ {
+ db.test
+ .aggregate([
+ {$sort: {a: -1}},
+ {$match: {a: {$regex: "foo(.*)"}, b: {$gt: 10}}},
+ {$skip: 5},
+ ])
+ .toArray();
+
+ const stats = getQueryStatsAggCmd(admin, {transformIdentifiers: true});
+
+ assert.eq(1,
+ stats.length,
+ {allStats: getQueryStats(admin), metrics: db.serverStatus().metrics.queryStats});
+ const key = stats[0].key;
+ verifyConsistentFields(key);
+ // Make sure there is no otherNss field when there are no secondary namespaces.
+ assert(!key.hasOwnProperty('otherNss'), key);
+ // Ensure the query stats key pipeline holds the raw input without optimization (e.g., the
+ // $sort stays before the $match, as in the raw query).
+ assert.eq(
+ [
+ {"$sort": {[kHashedFieldA]: -1}},
+ {
+ "$match": {
+ "$and": [
+ {[kHashedFieldA]: {"$regex": "?string"}},
+ {[kHashedFieldB]: {"$gt": "?number"}}
+ ]
+ }
+ },
+ {"$skip": "?number"}
+ ],
+ key.queryShape.pipeline,
+ key.queryShape.pipeline);
+ }
+
+ // Checks proper tokenization on another basic pipeline that is a subset of the original
+ // pipeline to make sure there are separate query stats entries per separate query shape.
+ {
+ db.test.aggregate([{$match: {a: {$regex: "foo(.*)"}, b: {$gt: 0}}}]).toArray();
+ const stats = getQueryStatsAggCmd(admin, {transformIdentifiers: true});
+
+ assert.eq(2, stats.length);
+ const key = stats[0].key;
+ verifyConsistentFields(key);
+ // Make sure there is no otherNss field when there are no secondary namespaces.
+ assert(!key.hasOwnProperty('otherNss'), key);
+ assert.eq([{
+ "$match": {
+ "$and": [
+ {[kHashedFieldA]: {"$regex": "?string"}},
+ {[kHashedFieldB]: {"$gt": "?number"}}
+ ]
+ }
+ }],
+ key.queryShape.pipeline,
+ key.queryShape.pipeline);
+ }
+ // Checks proper tokenization on a pipeline that involves a let variable and a $lookup stage
+ // that has its own subpipeline and references another namespace.
+ {
+ const kHashedOtherCollName = "8Rfz9QKu4P3BbyJ3Zpf5kxlUGx7gMvVk2PXZlJVfikE=";
+ const kHashedAsOutputName = "OsoJyz+7myXF2CkbE5dKd9DJ1gDAUw5uyt12k1ENQpY=";
+ const kHashedFieldOrderName = "KcpgS5iaiD5/3BKdQRG5rodz+aEE9FkcTPTYZ+G7cpA=";
+ const kHashedFieldPrice = "LiAftyHzrbrVhwtTPaiHd8Lu9gUILkWgcP682amX7lI=";
+ const kHashedFieldMaxPrice = "lFzklZZ6KbbYMBTi8KtTTp1GZCcPaUKUmOe3iko+IF8=";
+ const kHashedFieldTime = "+TNONlWFBKVmiDN2ujCAexPQ1bat38CEzAQgkn2bvIg=";
+
+ db.test.aggregate([{
+ $lookup: {
+ from: "otherColl",
+ let: { order_name: "$a", price: "$price"},
+ pipeline: [{
+ $match: {
+ $expr: {
+ $and: [
+ { $eq: ["$a", "$$order_name"] },
+ { $lte: ["$$price", "$$max_price"] }
+ ]
+ }
+ }
+ }],
+ as: "my_output"
+ }},
+ {
+ $match: {$expr: {$lte: ["$$CURRENT.time", "$$NOW"]}}
+ }], {let: {max_price: 3.00}}).toArray();
+ const stats = getQueryStatsAggCmd(admin, {transformIdentifiers: true});
+
+ assert.eq(3, stats.length);
+ // This one will sort last because of the 'let' parameters.
+ const key = stats[2].key;
+ verifyConsistentFields(key);
+ assert.eq(
+ [
+ {
+ "$lookup": {
+ "from": `${kHashedOtherCollName}`,
+ "as": `${kHashedAsOutputName}`,
+ "let": {
+ [kHashedFieldOrderName]: asFieldPath(kHashedFieldA),
+ [kHashedFieldPrice]: asFieldPath(kHashedFieldPrice)
+ },
+ "pipeline": [{
+ "$match": {
+ "$expr": {
+ "$and": [
+ {
+ "$eq": [
+ asFieldPath(kHashedFieldA),
+ asVarRef(kHashedFieldOrderName)
+ ],
+ },
+ {
+ "$lte": [
+ asVarRef(kHashedFieldPrice),
+ asVarRef(kHashedFieldMaxPrice)
+ ]
+ }
+ ]
+ }
+ }
+ }]
+ }
+ },
+ {"$match": {"$expr": {"$lte": [asFieldPath(kHashedFieldTime), asVarRef("NOW")]}}}
+ ],
+ key.queryShape.pipeline,
+ key.queryShape.pipeline);
+ assert.eq({[kHashedFieldMaxPrice]: "?number"}, key.queryShape.let);
+ assert.eq([{"db": `${kHashedDbName}`, "coll": `${kHashedOtherCollName}`}], key.otherNss);
+ }
+}
+
+const conn = MongoRunner.runMongod({
+ setParameter: {
+ internalQueryStatsRateLimit: -1,
+ }
+});
+runTest(conn);
+MongoRunner.stopMongod(conn);
+
+const st = new ShardingTest({
+ mongos: 1,
+ shards: 1,
+ config: 1,
+ rs: {nodes: 1},
+ mongosOptions: {
+ setParameter: {
+ internalQueryStatsRateLimit: -1,
+ }
+ },
+});
+runTest(st.s);
+st.stop();
+}());
diff --git a/jstests/noPassthrough/queryStats/application_name_find.js b/jstests/noPassthrough/queryStats/application_name_find.js
new file mode 100644
index 00000000000..c0dc2bcf848
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/application_name_find.js
@@ -0,0 +1,37 @@
+/**
+ * Test that applicationName and namespace appear in queryStats for the find command.
+ * @tags: [requires_fcv_60]
+ */
+load("jstests/libs/query_stats_utils.js");
+(function() {
+"use strict";
+
+const kApplicationName = "MongoDB Shell";
+
+// Turn on the collecting of queryStats metrics.
+let options = {
+ setParameter: {internalQueryStatsRateLimit: -1},
+};
+
+const conn = MongoRunner.runMongod(options);
+conn.setLogLevel(3, "query");
+const testDB = conn.getDB('test');
+var coll = testDB[jsTestName()];
+coll.drop();
+
+coll.insert({v: 1});
+coll.insert({v: 2});
+coll.insert({v: 3});
+
+coll.find({v: 1}).toArray();
+
+let queryStats = getQueryStats(conn);
+assert.eq(1, queryStats.length, queryStats);
+assert.eq(kApplicationName, queryStats[0].key.client.application.name, queryStats);
+
+queryStats = getQueryStatsFindCmd(conn, {transformIdentifiers: true});
+assert.eq(1, queryStats.length, queryStats);
+assert.eq(kApplicationName, queryStats[0].key.client.application.name, queryStats);
+
+MongoRunner.stopMongod(conn);
+}());
diff --git a/jstests/noPassthrough/queryStats/clear_query_stats_store.js b/jstests/noPassthrough/queryStats/clear_query_stats_store.js
new file mode 100644
index 00000000000..1aafd2b9b87
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/clear_query_stats_store.js
@@ -0,0 +1,46 @@
+/**
+ * Test that the queryStats store can be cleared when the cache size is reset to 0.
+ * @tags: [requires_fcv_60]
+ */
+load("jstests/libs/query_stats_utils.js"); // For verifyMetrics and getQueryStats.
+
+(function() {
+"use strict";
+
+// Turn on the collecting of queryStats metrics.
+let options = {
+ setParameter: {internalQueryStatsRateLimit: -1, internalQueryStatsCacheSize: "10MB"},
+};
+
+const conn = MongoRunner.runMongod(options);
+const testDB = conn.getDB('test');
+var coll = testDB[jsTestName()];
+coll.drop();
+
+let query = {};
+for (var j = 0; j < 10; ++j) {
+ query["foo.field.xyz." + j] = 1;
+ query["bar.field.xyz." + j] = 2;
+ query["baz.field.xyz." + j] = 3;
+ coll.aggregate([{$match: query}]).itcount();
+}
+
+// Confirm number of entries in the store and that none have been evicted.
+let res = getQueryStats(conn);
+assert.eq(res.length, 10, res);
+assert.eq(testDB.serverStatus().metrics.queryStats.numEvicted, 0);
+assert.gt(testDB.serverStatus().metrics.queryStats.queryStatsStoreSizeEstimateBytes, 0);
+
+// Command to clear the cache.
+assert.commandWorked(testDB.adminCommand({setParameter: 1, internalQueryStatsCacheSize: "0MB"}));
+
+// 10 regular queries plus the $queryStats query, means 11 entries evicted when the cache is
+// cleared.
+assert.eq(testDB.serverStatus().metrics.queryStats.numEvicted, 11);
+assert.eq(testDB.serverStatus().metrics.queryStats.queryStatsStoreSizeEstimateBytes, 0);
+
+// Calling $queryStats should fail when the query stats store size is 0 bytes.
+assert.throwsWithCode(() => testDB.getSiblingDB("admin").aggregate([{$queryStats: {}}]),
+ ErrorCodes.QueryFeatureNotAllowed);
+MongoRunner.stopMongod(conn);
+}());
diff --git a/jstests/noPassthrough/queryStats/documentSourceQueryStats_redaction_parameters.js b/jstests/noPassthrough/queryStats/documentSourceQueryStats_redaction_parameters.js
new file mode 100644
index 00000000000..40db2885967
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/documentSourceQueryStats_redaction_parameters.js
@@ -0,0 +1,126 @@
+/**
+ * Test the $queryStats hmac properties.
+ * @tags: [requires_fcv_60]
+ */
+
+load("jstests/aggregation/extras/utils.js"); // For assertAdminDBErrCodeAndErrMsgContains.
+load("jstests/libs/query_stats_utils.js"); // For getQueryStatsFindCmd
+
+(function() {
+"use strict";
+
+// Assert the expected queryStats key with no hmac.
+function assertQueryStatsKeyWithoutHmac(queryStatsKey) {
+ assert.eq(queryStatsKey.filter, {"foo": {"$lte": "?number"}});
+ assert.eq(queryStatsKey.sort, {"bar": -1});
+ assert.eq(queryStatsKey.limit, "?number");
+}
+
+function runTest(conn) {
+ const testDB = conn.getDB('test');
+ const coll = testDB[jsTestName()];
+ coll.drop();
+
+ coll.insert({foo: 1});
+ coll.find({foo: {$lte: 2}}).sort({bar: -1}).limit(2).toArray();
+ // Default is no hmac.
+ assertQueryStatsKeyWithoutHmac(getQueryStatsFindCmd(conn)[0].key.queryShape);
+
+ // Turning on hmac should apply hmac to all field names on all entries, even previously cached
+ // ones.
+ const queryStatsKey = getQueryStatsFindCmd(conn, {transformIdentifiers: true})[0]["key"];
+ assert.eq(queryStatsKey.queryShape.filter,
+ {"fNWkKfogMv6MJ77LpBcuPrO7Nq+R+7TqtD+Lgu3Umc4=": {"$lte": "?number"}});
+ assert.eq(queryStatsKey.queryShape.sort, {"CDDQIXZmDehLKmQcRxtdOQjMqoNqfI2nGt2r4CgJ52o=": -1});
+ assert.eq(queryStatsKey.queryShape.limit, "?number");
+
+ // Turning hmac back off should preserve field names on all entries, even previously cached
+ // ones.
+ const queryStats = getQueryStatsFindCmd(conn)[0]["key"];
+ assertQueryStatsKeyWithoutHmac(queryStats.queryShape);
+
+ // Explicitly set transformIdentifiers to false.
+ assertQueryStatsKeyWithoutHmac(
+ getQueryStatsFindCmd(conn, {transformIdentifiers: false})[0]["key"].queryShape);
+
+ // Wrong parameter name throws error.
+ let pipeline = [{$queryStats: {redactFields: true}}];
+ assertAdminDBErrCodeAndErrMsgContains(
+ coll, pipeline, 40415, "BSON field '$queryStats.redactFields' is an unknown field.");
+
+ // Wrong parameter name throws error.
+ pipeline = [{$queryStats: {algorithm: "hmac-sha-256"}}];
+ assertAdminDBErrCodeAndErrMsgContains(
+ coll, pipeline, 40415, "BSON field '$queryStats.algorithm' is an unknown field.");
+
+ // Wrong parameter type throws error.
+ pipeline = [{$queryStats: {transformIdentifiers: {algorithm: 1}}}];
+ assertAdminDBErrCodeAndErrMsgContains(
+ coll,
+ pipeline,
+ ErrorCodes.TypeMismatch,
+ "BSON field '$queryStats.transformIdentifiers.algorithm' is the wrong type 'double', expected type 'string'");
+
+ pipeline = [{$queryStats: {transformIdentifiers: {algorithm: "hmac-sha-256", hmacKey: 1}}}];
+ assertAdminDBErrCodeAndErrMsgContains(
+ coll,
+ pipeline,
+ ErrorCodes.TypeMismatch,
+ "BSON field '$queryStats.transformIdentifiers.hmacKey' is the wrong type 'double', expected type 'binData'");
+
+ // Unsupported algorithm throws error.
+ pipeline = [{$queryStats: {transformIdentifiers: {algorithm: "hmac-sha-1"}}}];
+ assertAdminDBErrCodeAndErrMsgContains(
+ coll,
+ pipeline,
+ ErrorCodes.BadValue,
+ "Enumeration value 'hmac-sha-1' for field '$queryStats.transformIdentifiers.algorithm' is not a valid value.");
+
+ // TransformIdentifiers with missing algorithm throws error.
+ pipeline = [{$queryStats: {transformIdentifiers: {}}}];
+ assertAdminDBErrCodeAndErrMsgContains(
+ coll,
+ pipeline,
+ 40414,
+ "BSON field '$queryStats.transformIdentifiers.algorithm' is missing but a required field");
+
+ // TransformIdentifiers with algorithm but missing hmacKey throws error.
+ pipeline = [{$queryStats: {transformIdentifiers: {algorithm: "hmac-sha-256"}}}];
+ assertAdminDBErrCodeAndErrMsgContains(
+ coll,
+ pipeline,
+ ErrorCodes.FailedToParse,
+ "The 'hmacKey' parameter of the $queryStats stage must be specified when applying the hmac-sha-256 algorithm");
+
+ // Parameter object with unrecognized key throws error.
+ pipeline =
+ [{$queryStats: {transformIdentifiers: {algorithm: "hmac-sha-256", hmacStrategy: "on"}}}];
+ assertAdminDBErrCodeAndErrMsgContains(
+ coll,
+ pipeline,
+ 40415,
+ "BSON field '$queryStats.transformIdentifiers.hmacStrategy' is an unknown field.");
+}
+
+const conn = MongoRunner.runMongod({
+ setParameter: {
+ internalQueryStatsRateLimit: -1,
+ }
+});
+runTest(conn);
+MongoRunner.stopMongod(conn);
+
+const st = new ShardingTest({
+ mongos: 1,
+ shards: 1,
+ config: 1,
+ rs: {nodes: 1},
+ mongosOptions: {
+ setParameter: {
+ internalQueryStatsRateLimit: -1,
+ }
+ },
+});
+runTest(st.s);
+st.stop();
+}());
diff --git a/jstests/noPassthrough/queryStats/feature_flag_off_sampling_rate_on.js b/jstests/noPassthrough/queryStats/feature_flag_off_sampling_rate_on.js
new file mode 100644
index 00000000000..77388690062
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/feature_flag_off_sampling_rate_on.js
@@ -0,0 +1,44 @@
+/**
+ * Test that calls to read from query stats store fail when feature flag is turned off and sampling
+ * rate > 0.
+ */
+load('jstests/libs/analyze_plan.js');
+load("jstests/libs/feature_flag_util.js");
+
+(function() {
+"use strict";
+
+// Set sampling rate to -1.
+let options = {
+ setParameter: {internalQueryStatsRateLimit: -1, featureFlagQueryStats: false},
+};
+const conn = MongoRunner.runMongod(options);
+const testdb = conn.getDB('test');
+
+var coll = testdb[jsTestName()];
+coll.drop();
+
+// Bulk insert documents to reduces roundtrips and make timeout on a slow machine less likely.
+const bulk = coll.initializeUnorderedBulkOp();
+for (let i = 1; i <= 20; i++) {
+ bulk.insert({foo: 0, bar: Math.floor(Math.random() * 3)});
+}
+assert.commandWorked(bulk.execute());
+
+// Pipeline to read queryStats store should fail without feature flag turned on even though sampling
+// rate is > 0.
+assert.commandFailedWithCode(
+ testdb.adminCommand({aggregate: 1, pipeline: [{$queryStats: {}}], cursor: {}}),
+ ErrorCodes.QueryFeatureNotAllowed);
+
+// Pipeline, with a filter, to read queryStats store fails without feature flag turned on even
+// though sampling rate is > 0.
+assert.commandFailedWithCode(testdb.adminCommand({
+ aggregate: 1,
+ pipeline: [{$queryStats: {}}, {$match: {"key.queryShape.find": {$eq: "###"}}}],
+ cursor: {}
+}),
+ ErrorCodes.QueryFeatureNotAllowed);
+
+MongoRunner.stopMongod(conn);
+}());
diff --git a/jstests/noPassthrough/queryStats/find_cmd_one_way_tokenization.js b/jstests/noPassthrough/queryStats/find_cmd_one_way_tokenization.js
new file mode 100644
index 00000000000..55a8f322f90
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/find_cmd_one_way_tokenization.js
@@ -0,0 +1,66 @@
+/**
+ * Test that $queryStats properly tokenizes find commands, on mongod and mongos.
+ * @tags: [requires_fcv_60]
+ */
+load("jstests/libs/query_stats_utils.js");
+(function() {
+"use strict";
+
+const kHashedFieldName = "lU7Z0mLRPRUL+RfAD5jhYPRRpXBsZBxS/20EzDwfOG4=";
+
+function runTest(conn) {
+ const db = conn.getDB("test");
+ const admin = conn.getDB("admin");
+
+ db.test.drop();
+ db.test.insert({v: 1});
+
+ db.test.find({v: 1}).toArray();
+
+ let queryStats = getQueryStatsFindCmd(admin, {transformIdentifiers: true});
+
+ assert.eq(1, queryStats.length);
+ assert.eq("find", queryStats[0].key.queryShape.command);
+ assert.eq({[kHashedFieldName]: {$eq: "?number"}}, queryStats[0].key.queryShape.filter);
+
+ db.test.insert({v: 2});
+
+ const cursor = db.test.find({v: {$gt: 0, $lt: 3}}).batchSize(1);
+ queryStats = getQueryStatsFindCmd(admin, {transformIdentifiers: true});
+ // Cursor isn't exhausted, so there shouldn't be another entry yet.
+ assert.eq(1, queryStats.length);
+
+ assert.commandWorked(
+ db.runCommand({getMore: cursor.getId(), collection: db.test.getName(), batchSize: 2}));
+
+ queryStats = getQueryStatsFindCmd(admin, {transformIdentifiers: true});
+ assert.eq(2, queryStats.length);
+ assert.eq("find", queryStats[1].key.queryShape.command);
+ assert.eq({
+ "$and": [{[kHashedFieldName]: {"$gt": "?number"}}, {[kHashedFieldName]: {"$lt": "?number"}}]
+ },
+ queryStats[1].key.queryShape.filter);
+}
+
+let conn = MongoRunner.runMongod({
+ setParameter: {
+ internalQueryStatsRateLimit: -1,
+ }
+});
+runTest(conn);
+MongoRunner.stopMongod(conn);
+
+let st = new ShardingTest({
+ mongos: 1,
+ shards: 1,
+ config: 1,
+ rs: {nodes: 1},
+ mongosOptions: {
+ setParameter: {
+ internalQueryStatsRateLimit: -1,
+ }
+ },
+});
+runTest(st.s);
+st.stop();
+}());
diff --git a/jstests/noPassthrough/queryStats/geometry_without_coordinates.js b/jstests/noPassthrough/queryStats/geometry_without_coordinates.js
new file mode 100644
index 00000000000..72a5015bfab
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/geometry_without_coordinates.js
@@ -0,0 +1,22 @@
+// This test was designed to reproduce SERVER-77430. There was a mistaken assertion in a parser that
+// we are interested in proving will not fail here.
+// @tags: [requires_fcv_60]
+(function() {
+"use strict";
+
+const st = new ShardingTest({
+ mongos: 1,
+ shards: 1,
+ config: 1,
+ rs: {nodes: 1},
+ mongosOptions: {
+ setParameter: {
+ internalQueryStatsRateLimit: -1,
+ }
+ },
+});
+const coll = st.s.getDB("test").geometry_without_coordinates;
+// This is a query that once mistakenly threw an error.
+assert.doesNotThrow(() => coll.find({geo: {$geoIntersects: {$geometry: {x: 40, y: 5}}}}).itcount());
+st.stop();
+}());
diff --git a/jstests/noPassthrough/queryStats/query_stats_agg_cmd_collect_on_mongos.js b/jstests/noPassthrough/queryStats/query_stats_agg_cmd_collect_on_mongos.js
new file mode 100644
index 00000000000..30cdcce8a18
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_agg_cmd_collect_on_mongos.js
@@ -0,0 +1,143 @@
+/**
+ * Test that mongos is collecting query stats metrics for agg queries.
+ * @tags: [requires_fcv_60]
+ */
+
+load('jstests/libs/query_stats_utils.js');
+
+(function() {
+"use strict";
+
+const st = new ShardingTest({
+ mongos: 1,
+ shards: 1,
+ config: 1,
+ rs: {nodes: 1},
+ mongosOptions: {
+ setParameter: {
+ internalQueryStatsRateLimit: -1,
+ }
+ },
+});
+const mongos = st.s;
+const db = mongos.getDB("test");
+
+// Assert that, for agg queries, no query stats results are written until a cursor has reached
+// exhaustion; ensure accurate results once they're written.
+{
+ const coll = db.coll;
+ coll.insert({v: 1});
+ coll.insert({v: 4});
+ const queryStatsKey = {
+ queryShape: {
+ cmdNs: {db: "test", coll: "coll"},
+ command: "aggregate",
+ pipeline: [
+ {$match: {$and: [{v: {$gt: "?number"}}, {v: {$lt: "?number"}}]}},
+ {$project: {_id: true, hello: true}}
+ ]
+
+ },
+ cursor: {batchSize: "?number"},
+ applicationName: "MongoDB Shell",
+ };
+
+ const cursor = coll.aggregate(
+ [
+ {$match: {v: {$gt: 0, $lt: 5}}},
+ {$project: {hello: true}},
+ ],
+ {cursor: {batchSize: 1}}); // returns 1 doc
+
+ // Since the cursor hasn't been exhausted yet, ensure no query stats results have been written
+ // yet.
+ let queryStats = getQueryStats(db);
+ assert.eq(0, queryStats.length, queryStats);
+
+ // Run a getMore to exhaust the cursor, then ensure query stats results have been written
+ // accurately. batchSize must be 2 so the cursor recognizes exhaustion.
+ assert.commandWorked(db.runCommand({
+ getMore: cursor.getId(),
+ collection: coll.getName(),
+ batchSize: 2
+ })); // returns 1 doc, exhausts the cursor
+ queryStats = getQueryStatsAggCmd(db);
+ assert.eq(1, queryStats.length, queryStats);
+ assertExpectedResults(queryStats[0],
+ queryStatsKey,
+ /* expectedExecCount */ 1,
+ /* expectedDocsReturnedSum */ 2,
+ /* expectedDocsReturnedMax */ 2,
+ /* expectedDocsReturnedMin */ 2,
+ /* expectedDocsReturnedSumOfSq */ NumberDecimal("4"),
+ /* getMores */ true);
+
+ // Run more queries (to exhaustion) with the same query shape, and ensure query stats results
+ // are accurate.
+ coll.aggregate([
+ {$match: {v: {$gt: 0, $lt: 5}}},
+ {$project: {hello: true}},
+ ]); // returns 2 docs
+ coll.aggregate([
+ {$match: {v: {$gt: 2, $lt: 3}}},
+ {$project: {hello: true}},
+ ]); // returns 0 docs
+ coll.aggregate([
+ {$match: {v: {$gt: 0, $lt: 2}}},
+ {$project: {hello: true}},
+ ]); // returns 1 doc
+ queryStats = getQueryStatsAggCmd(db);
+ assert.eq(1, queryStats.length, queryStats);
+ assertExpectedResults(queryStats[0],
+ queryStatsKey,
+ /* expectedExecCount */ 4,
+ /* expectedDocsReturnedSum */ 5,
+ /* expectedDocsReturnedMax */ 2,
+ /* expectedDocsReturnedMin */ 0,
+ /* expectedDocsReturnedSumOfSq */ NumberDecimal("9"),
+ /* getMores */ true);
+}
+
+// Assert on batchSize-limited agg queries that killCursors will write metrics with partial results
+// to the query stats store.
+{
+ const coll = db.coll2;
+ coll.insert({v: 1});
+ coll.insert({v: 4});
+
+ const queryStatsKey = {
+ queryShape: {
+ cmdNs: {db: "test", coll: "coll2"},
+ command: "aggregate",
+ pipeline: [{$match: {$and: [{v: {$gt: "?number"}}, {v: {$lt: "?number"}}]}}]
+ },
+ cursor: {batchSize: "?number"},
+ applicationName: "MongoDB Shell",
+ };
+
+ const cursor1 = coll.aggregate(
+ [
+ {$match: {v: {$gt: 0, $lt: 5}}},
+ ],
+ {cursor: {batchSize: 1}}); // returns 1 doc
+ const cursor2 = coll.aggregate(
+ [
+ {$match: {v: {$gt: 0, $lt: 2}}},
+ ],
+ {cursor: {batchSize: 1}}); // returns 1 doc
+
+ assert.commandWorked(
+ db.runCommand({killCursors: coll.getName(), cursors: [cursor1.getId(), cursor2.getId()]}));
+ const queryStats = getLatestQueryStatsEntry(db, {collName: coll.getName()});
+ assertExpectedResults(queryStats,
+ queryStatsKey,
+ /* expectedExecCount */ 2,
+ /* expectedDocsReturnedSum */ 2,
+ /* expectedDocsReturnedMax */ 1,
+ /* expectedDocsReturnedMin */ 1,
+ /* expectedDocsReturnedSumOfSq */ NumberDecimal("2"),
+ /* getMores */ false);
+}
+
+st.stop();
+}());
diff --git a/jstests/noPassthrough/queryStats/query_stats_agg_key.js b/jstests/noPassthrough/queryStats/query_stats_agg_key.js
new file mode 100644
index 00000000000..0eec5525733
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_agg_key.js
@@ -0,0 +1,64 @@
+/**
+ * This test confirms that query stats store key fields for an aggregate command are properly nested
+ * and none are missing.
+ * @tags: [requires_fcv_60]
+ */
+load("jstests/libs/query_stats_utils.js"); // For runCommandAndValidateQueryStats and
+ // withQueryStatsEnabled
+(function() {
+"use strict";
+
+const collName = jsTestName();
+const aggregateCommandObj = {
+ aggregate: collName,
+ pipeline: [{"$out": "collOut"}],
+ allowDiskUse: false,
+ cursor: {batchSize: 2},
+ maxTimeMS: 50 * 1000,
+ bypassDocumentValidation: false,
+ readConcern: {level: "local"},
+ writeConcern: {w: 1},
+ collation: {locale: "en_US", strength: 2},
+ hint: {"v": 1},
+ comment: "",
+ let : {},
+ apiDeprecationErrors: false,
+ apiVersion: "1",
+ apiStrict: false,
+};
+
+const queryShapeAggregateFields =
+ ["cmdNs", "command", "pipeline", "allowDiskUse", "collation", "let"];
+
+// The outer fields not nested inside queryShape.
+const queryStatsAggregateKeyFields = [
+ "queryShape",
+ "cursor",
+ "maxTimeMS",
+ "bypassDocumentValidation",
+ "comment",
+ "otherNss",
+ "apiDeprecationErrors",
+ "apiVersion",
+ "apiStrict",
+ "collectionType",
+ "client",
+ "hint",
+ "readConcern",
+ "writeConcern",
+ "cursor.batchSize",
+];
+
+withQueryStatsEnabled(collName, (coll) => {
+ // Have to create an index for hint not to fail.
+ assert.commandWorked(coll.createIndex({v: 1}));
+
+ runCommandAndValidateQueryStats({
+ coll: coll,
+ commandName: "aggregate",
+ commandObj: aggregateCommandObj,
+ shapeFields: queryShapeAggregateFields,
+ keyFields: queryStatsAggregateKeyFields
+ });
+});
+}()); \ No newline at end of file
diff --git a/jstests/noPassthrough/queryStats/query_stats_agg_key_change_stream.js b/jstests/noPassthrough/queryStats/query_stats_agg_key_change_stream.js
new file mode 100644
index 00000000000..63f917c6c07
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_agg_key_change_stream.js
@@ -0,0 +1,182 @@
+/**
+ * This test confirms that query stats store key fields for an aggregate command are properly nested
+ * and none are missing. It also validates the exact pipeline in the query shape.
+ * @tags: [
+ * uses_change_streams,
+ * requires_fcv_60
+ * ]
+ */
+
+load("jstests/libs/query_stats_utils.js"); // For runCommandAndValidateQueryStats.
+load("jstests/libs/collection_drop_recreate.js"); // For assertDropAndRecreateCollection.
+const dbName = jsTestName();
+const collName = "coll";
+
+const queryShapeAggregateFields =
+ ["cmdNs", "command", "pipeline", "allowDiskUse", "collation", "let"];
+
+// The outer fields not nested inside queryShape.
+const queryStatsAggregateKeyFields = [
+ "queryShape",
+ "cursor",
+ "maxTimeMS",
+ "bypassDocumentValidation",
+ "comment",
+ "apiDeprecationErrors",
+ "apiVersion",
+ "apiStrict",
+ "collectionType",
+ "client",
+ "hint",
+ "readConcern",
+ "cursor.batchSize",
+];
+
+const testCases = [
+ // Default fields.
+ {
+ pipeline: [{"$changeStream": {}}],
+ expectedShapifiedPipeline: [{
+ "$changeStream": {
+ startAtOperationTime: "?timestamp",
+ fullDocument: "default",
+ fullDocumentBeforeChange: "off"
+ }
+ }]
+ },
+ // Non default field values.
+ {
+ pipeline: [{
+ "$changeStream": {
+ fullDocument: "updateLookup",
+ fullDocumentBeforeChange: "required",
+ showExpandedEvents: true,
+ }
+ }],
+ expectedShapifiedPipeline: [{
+ "$changeStream": {
+ startAtOperationTime: "?timestamp",
+ fullDocument: "updateLookup",
+ fullDocumentBeforeChange: "required",
+ showExpandedEvents: true,
+ }
+ }],
+ },
+ // $changeStream followed by a $match. $changeStream internally creates another $match stage
+ // which shouldn't appear in the query shape, but a $match in the user specified pipeline should
+ // appear in the query shape.
+ {
+ pipeline: [{$changeStream: {}}, {$match: {a: "field"}}],
+ expectedShapifiedPipeline: [
+ {
+ "$changeStream": {
+ startAtOperationTime: "?timestamp",
+ fullDocument: "default",
+ fullDocumentBeforeChange: "off"
+ }
+ },
+ {$match: {a: {$eq: "?string"}}}
+ ]
+ }
+];
+
+function assertPipelineField(conn, expectedPipeline) {
+ const entry = getLatestQueryStatsEntry(conn, {collName: collName});
+ const statsPipeline = getValueAtPath(entry, "key.queryShape.pipeline");
+ assert.eq(statsPipeline, expectedPipeline);
+}
+
+function validateResumeTokenQueryShape(conn, coll) {
+ // Start a change stream.
+ const changeStream = coll.watch([]);
+
+ // Going to create an invalid event by checking a change stream on a dropped collection.
+ assert.commandWorked(coll.insert({_id: 1}));
+ assert(coll.drop());
+ assert.soon(() => changeStream.hasNext());
+ changeStream.next();
+ const invalidateResumeToken = changeStream.getResumeToken();
+
+ // Resume the change stream using 'startAfter' field.
+ coll.watch([], {startAfter: invalidateResumeToken});
+ assert.commandWorked(coll.insert({_id: 2}));
+
+ const expectedShapifiedPipeline = [{
+ "$changeStream": {
+ startAfter: {_data: "?string"},
+ fullDocument: "default",
+ fullDocumentBeforeChange: "off"
+ }
+ }];
+ assertPipelineField(conn, expectedShapifiedPipeline);
+}
+
+function validateChangeStreamAggKey(conn) {
+ const db = conn.getDB("test");
+ assertDropAndRecreateCollection(db, collName);
+
+ // Change streams with 'startAfter' or 'resumeAfter' are only executed after a certain event and
+ // require re-parsing a resume token. To validate the query shape of these pipelines, we have to
+ // execute the events to register the pipeline.
+ validateResumeTokenQueryShape(conn, db[collName]);
+
+ // Validate the key for the rest of the pipelines.
+ testCases.forEach(input => {
+ const pipeline = input.pipeline;
+ const aggCmdObj = {
+ aggregate: collName,
+ pipeline: pipeline,
+ allowDiskUse: false,
+ cursor: {batchSize: 2},
+ maxTimeMS: 50 * 1000,
+ bypassDocumentValidation: false,
+ readConcern: {level: "majority"},
+ collation: {locale: "en_US", strength: 2},
+ hint: {"v": 1},
+ comment: "",
+ let : {},
+ apiDeprecationErrors: false,
+ apiVersion: "1",
+ apiStrict: false,
+ };
+
+ runCommandAndValidateQueryStats({
+ coll: db[collName],
+ commandName: "aggregate",
+ commandObj: aggCmdObj,
+ shapeFields: queryShapeAggregateFields,
+ keyFields: queryStatsAggregateKeyFields
+ });
+ assertPipelineField(conn, input.expectedShapifiedPipeline);
+ });
+}
+
+{
+ // Test on a sharded cluster.
+ const st = new ShardingTest({
+ mongos: 1,
+ shards: 2,
+ config: 1,
+ rs: {nodes: 1, setParameter: {writePeriodicNoops: true, periodicNoopIntervalSecs: 1}},
+ mongosOptions: {
+ setParameter: {
+ internalQueryStatsRateLimit: -1,
+ }
+ },
+ });
+ validateChangeStreamAggKey(st.s);
+ st.stop();
+}
+
+{
+ // Test the non-sharded case.
+ const rst = new ReplSetTest({nodes: 2});
+ rst.startSet({setParameter: {internalQueryStatsRateLimit: -1}});
+ rst.initiate();
+ rst.getPrimary().getDB("admin").setLogLevel(3, "queryStats");
+
+ // Only aggregations run on replica sets have the '$readPreference' field in the key.
+ queryStatsAggregateKeyFields.push("$readPreference");
+ validateChangeStreamAggKey(rst.getPrimary());
+ rst.stopSet();
+}
diff --git a/jstests/noPassthrough/queryStats/query_stats_agg_key_change_stream_passthrough_shard.js b/jstests/noPassthrough/queryStats/query_stats_agg_key_change_stream_passthrough_shard.js
new file mode 100644
index 00000000000..3a8123021d2
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_agg_key_change_stream_passthrough_shard.js
@@ -0,0 +1,94 @@
+/**
+ * This test confirms that query stats store key fields for an aggregate command are properly nested
+ * and none are missing when running a change stream query with $_passthroughToShard.
+ * @tags: [
+ * requires_sharding,
+ * uses_change_streams,
+ * requires_fcv_60
+ * ]
+ */
+
+load("jstests/libs/query_stats_utils.js");
+const dbName = jsTestName();
+const collName = "coll";
+
+// $_passthroughToShard is only possible on a sharded cluster.
+const st = new ShardingTest({
+ shards: 2,
+ mongos: 1,
+ config: 1,
+ rs: {nodes: 1},
+ other: {
+ mongosOptions: {
+ setParameter: {
+ internalQueryStatsRateLimit: -1,
+ }
+ }
+ }
+});
+
+const sdb = st.s0.getDB(dbName);
+assert.commandWorked(sdb.dropDatabase());
+
+sdb.setProfilingLevel(0, -1);
+st.shard0.getDB(dbName).setProfilingLevel(0, -1);
+
+// Shard the relevant collections.
+assert.commandWorked(st.s.adminCommand({enableSharding: dbName, primaryShard: st.shard0.name}));
+// Shard the collection on {_id: 1}, split at {_id: 0} and move the empty upper chunk to
+// shard1.
+st.shardColl(collName, {_id: 1}, {_id: 0}, {_id: 0}, dbName);
+
+const shardId = st.shard0.shardName;
+let coll = sdb[collName];
+
+const aggregateCommandObj = {
+ aggregate: coll.getName(),
+ pipeline: [{"$changeStream": {}}],
+ allowDiskUse: false,
+ cursor: {batchSize: 2},
+ maxTimeMS: 50 * 1000,
+ bypassDocumentValidation: false,
+ readConcern: {level: "majority"},
+ collation: {locale: "en_US", strength: 2},
+ hint: {"v": 1},
+ comment: "",
+ let : {},
+ apiDeprecationErrors: false,
+ apiVersion: "1",
+ apiStrict: false,
+ $_passthroughToShard: {shard: shardId}
+};
+
+const queryShapeAggregateFields =
+ ["cmdNs", "command", "pipeline", "allowDiskUse", "collation", "let"];
+
+// The outer fields not nested inside queryShape.
+const queryStatsAggregateKeyFields = [
+ "queryShape",
+ "cursor",
+ "maxTimeMS",
+ "bypassDocumentValidation",
+ "comment",
+ "apiDeprecationErrors",
+ "apiVersion",
+ "apiStrict",
+ "collectionType",
+ "client",
+ "hint",
+ "readConcern",
+ "cursor.batchSize",
+ "$_passthroughToShard",
+ "$_passthroughToShard.shard"
+];
+assert.commandWorked(coll.createIndex({v: 1}));
+
+runCommandAndValidateQueryStats({
+ coll: coll,
+ commandName: "aggregate",
+ commandObj: aggregateCommandObj,
+ shapeFields: queryShapeAggregateFields,
+ keyFields: queryStatsAggregateKeyFields
+});
+
+st.stop(); \ No newline at end of file
diff --git a/jstests/noPassthrough/queryStats/query_stats_agg_key_explain.js b/jstests/noPassthrough/queryStats/query_stats_agg_key_explain.js
new file mode 100644
index 00000000000..4d1b68c7b6d
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_agg_key_explain.js
@@ -0,0 +1,84 @@
+/**
+ * This test confirms that query stats store key fields for an aggregate command are properly nested
+ * and none are missing when running an explain query.
+ * @tags: [requires_fcv_60]
+ */
+load("jstests/libs/query_stats_utils.js");
+
+const collName = jsTestName();
+
+const aggregateCommandObj = {
+ aggregate: collName,
+ pipeline: [{"$out": "collOut"}],
+ allowDiskUse: false,
+ cursor: {batchSize: 2},
+ maxTimeMS: 50 * 1000,
+ bypassDocumentValidation: false,
+ readConcern: {level: "local"},
+ // This flag sets the explain verbosity to 'queryPlanner'.
+ explain: true,
+ collation: {locale: "en_US", strength: 2},
+ hint: {"v": 1},
+ comment: "",
+ let : {},
+ apiDeprecationErrors: false,
+ apiVersion: "1",
+ apiStrict: false,
+};
+
+const queryShapeAggregateFields =
+ ["cmdNs", "command", "pipeline", "allowDiskUse", "collation", "let"];
+
+// The outer fields not nested inside queryShape.
+const queryStatsAggregateKeyFields = [
+ "queryShape",
+ "cursor",
+ "maxTimeMS",
+ "bypassDocumentValidation",
+ "comment",
+ "otherNss",
+ "apiDeprecationErrors",
+ "apiVersion",
+ "apiStrict",
+ "collectionType",
+ "client",
+ "hint",
+ "readConcern",
+ "explain",
+ "cursor.batchSize",
+];
+
+// Copy the command object to test {explain: false}.
+const aggregateCommandObjExplainFalse = Object.assign({}, aggregateCommandObj);
+aggregateCommandObjExplainFalse.explain = false;
+
+// Setting the explain flag to 'false' has the same behavior as having no explain flag at all,
+// making it not appear on the key.
+const queryStatsAggregateKeyFieldsExplainFalse =
+ queryStatsAggregateKeyFields.filter(e => e !== "explain");
+
+withQueryStatsEnabled(collName, (coll) => {
+ // Create an index for hint not to fail.
+ assert.commandWorked(coll.createIndex({v: 1}));
+
+ // Run an aggregate with {explain: true} and make sure that the 'explain'
+ // field shows up in the query stats store key.
+ runCommandAndValidateQueryStats({
+ coll: coll,
+ commandName: "aggregate",
+ commandObj: aggregateCommandObj,
+ shapeFields: queryShapeAggregateFields,
+ keyFields: queryStatsAggregateKeyFields
+ });
+
+ // Run an aggregate with {explain: false} and make sure that the 'explain'
+ // field doesn't shows up in the query stats store key.
+ runCommandAndValidateQueryStats({
+ coll: coll,
+ commandName: "aggregate",
+ commandObj: aggregateCommandObjExplainFalse,
+ // The shape remains the same since 'explain' is at the key level.
+ shapeFields: queryShapeAggregateFields,
+ keyFields: queryStatsAggregateKeyFieldsExplainFalse
+ });
+});
diff --git a/jstests/noPassthrough/queryStats/query_stats_change_stream.js b/jstests/noPassthrough/queryStats/query_stats_change_stream.js
new file mode 100644
index 00000000000..a610ff5f0bc
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_change_stream.js
@@ -0,0 +1,227 @@
+// Tests the collection of query stats for a change stream query.
+// @tags: [
+// uses_change_streams,
+// requires_replication,
+// requires_sharding,
+// requires_fcv_60
+// ]
+
+load("jstests/libs/query_stats_utils.js"); // For getLatestQueryStatsEntry.
+load("jstests/libs/fixture_helpers.js"); // For FixtureHelpers.
+load("jstests/libs/collection_drop_recreate.js"); // For assertDropAndRecreateCollection.
+
+function testCollectionChangeStream(conn) {
+ const db = conn.getDB("test");
+ assertDropAndRecreateCollection(db, "coll");
+
+ // Check change stream explain is recorded.
+ assert.commandWorked(
+ db.coll.explain({"verbosity": "queryPlanner"}).aggregate([{"$changeStream": {}}]));
+ let queryStatsEntry = getLatestQueryStatsEntry(db);
+ checkChangeStreamEntry({
+ queryStatsEntry: queryStatsEntry,
+ db: db,
+ collectionName: "coll",
+ numExecs: 1,
+ numDocsReturned: 0
+ });
+ assert(queryStatsEntry.key.hasOwnProperty("explain"));
+
+ // Check creation of change stream cursor is recorded.
+ let cursor = db.coll.watch([], {batchSize: 1});
+
+ let numExecs = 1;
+ let numDocsReturned = 0;
+
+ checkChangeStreamEntry({
+ queryStatsEntry: getLatestQueryStatsEntry(db),
+ db: db,
+ collectionName: "coll",
+ numExecs: numExecs,
+ numDocsReturned: numDocsReturned
+ });
+
+ // Insert document into a collection and make sure retrieving the information updates the query
+ // stats entry.
+ assert.commandWorked(db.coll.insert({_id: 0, a: 1}));
+ numExecs += getNumberOfGetMoresUntilNextDocForChangeStream(cursor);
+ numDocsReturned++;
+
+ checkChangeStreamEntry({
+ queryStatsEntry: getLatestQueryStatsEntry(db),
+ db: db,
+ collectionName: "coll",
+ numExecs: numExecs,
+ numDocsReturned: numDocsReturned
+ });
+
+ // Close cursor and check that it updates query stats entry.
+ cursor.close();
+ numExecs++;
+ queryStatsEntry = getLatestQueryStatsEntry(db);
+ checkChangeStreamEntry({
+ queryStatsEntry: queryStatsEntry,
+ db: db,
+ collectionName: "coll",
+ numExecs: numExecs,
+ numDocsReturned: numDocsReturned
+ });
+ // Closing the cursor should result in 0 ms for the operation.
+ assert.eq(queryStatsEntry.metrics.lastExecutionMicros, 0);
+}
+
+function testDatabaseChangeStream(conn) {
+ const db = conn.getDB("test");
+ assertDropAndRecreateCollection(db, "coll1");
+ assertDropAndRecreateCollection(db, "coll2");
+
+ // Check creation of change stream cursor is recorded.
+ let wholeDBCursor = db.watch([]);
+ let numExecs = 1;
+ let numDocsReturned = 0;
+
+ checkChangeStreamEntry({
+ queryStatsEntry: getLatestQueryStatsEntry(db),
+ db: db,
+ collectionName: "$cmd.aggregate",
+ numExecs: numExecs,
+ numDocsReturned: numDocsReturned
+ });
+
+ // Insert document into a collection and make sure retrieving the information updates the query
+ // stats entry.
+ assert.commandWorked(db.coll1.insert({_id: 1, a: 2}));
+ numExecs += getNumberOfGetMoresUntilNextDocForChangeStream(wholeDBCursor);
+ numDocsReturned++;
+
+ checkChangeStreamEntry({
+ queryStatsEntry: getLatestQueryStatsEntry(db),
+ db: db,
+ collectionName: "$cmd.aggregate",
+ numExecs: numExecs,
+ numDocsReturned: numDocsReturned
+ });
+
+ // Insert document into a different collection and make sure retrieving the information updates
+ // the query stats entry.
+ assert.commandWorked(db.coll2.insert({_id: 1, a: 2}));
+ numExecs += getNumberOfGetMoresUntilNextDocForChangeStream(wholeDBCursor);
+ numDocsReturned++;
+ checkChangeStreamEntry({
+ queryStatsEntry: getLatestQueryStatsEntry(db),
+ db: db,
+ collectionName: "$cmd.aggregate",
+ numExecs: numExecs,
+ numDocsReturned: numDocsReturned
+ });
+
+ // Close cursor and check that it increases numExecs.
+ wholeDBCursor.close();
+ numExecs++;
+ let queryStatsEntry = getLatestQueryStatsEntry(db);
+ checkChangeStreamEntry({
+ queryStatsEntry: queryStatsEntry,
+ db: db,
+ collectionName: "$cmd.aggregate",
+ numExecs: numExecs,
+ numDocsReturned: numDocsReturned
+ });
+
+ // Closing the cursor should result in 0 ms for the operation.
+ assert.eq(queryStatsEntry.metrics.lastExecutionMicros, 0);
+}
+
+function testWholeClusterChangeStream(conn) {
+ const dbA = conn.getDB("testA");
+ const dbB = conn.getDB("testB");
+ assertDropAndRecreateCollection(dbA, "collA");
+ assertDropAndRecreateCollection(dbB, "collB");
+
+ // Creating the change stream cursor should create a query stats entry.
+ let wholeClusterCursor = dbA.getMongo().watch([]);
+ let numExecs = 1;
+ let numDocsReturned = 0;
+
+ checkChangeStreamEntry({
+ queryStatsEntry: getLatestQueryStatsEntry(dbA),
+ db: dbA,
+ collectionName: "$cmd.aggregate",
+ numExecs: numExecs,
+ numDocsReturned: numDocsReturned
+ });
+
+ // Insert document into a database and make sure retrieving the information updates the query
+ // stats entry.
+ assert.commandWorked(dbA.collA.insert({_id: 1, a: 2}));
+ numExecs += getNumberOfGetMoresUntilNextDocForChangeStream(wholeClusterCursor);
+ numDocsReturned++;
+
+ checkChangeStreamEntry({
+ queryStatsEntry: getLatestQueryStatsEntry(dbA),
+ db: dbA,
+ collectionName: "$cmd.aggregate",
+ numExecs: numExecs,
+ numDocsReturned: numDocsReturned
+ });
+
+ // Insert document into different database and make sure retrieving the information updates the
+ // query stats entry.
+ assert.commandWorked(dbB.collB.insert({_id: 1, a: 2}));
+ numExecs += getNumberOfGetMoresUntilNextDocForChangeStream(wholeClusterCursor);
+ numDocsReturned++;
+
+ checkChangeStreamEntry({
+ queryStatsEntry: getLatestQueryStatsEntry(dbA),
+ db: dbA,
+ collectionName: "$cmd.aggregate",
+ numExecs: numExecs,
+ numDocsReturned: numDocsReturned
+ });
+
+ // Close cursor and check that it increases numExecs.
+ wholeClusterCursor.close();
+ numExecs++;
+ let queryStatsEntry = getLatestQueryStatsEntry(dbA);
+ checkChangeStreamEntry({
+ queryStatsEntry: queryStatsEntry,
+ db: dbA,
+ collectionName: "$cmd.aggregate",
+ numExecs: numExecs,
+ numDocsReturned: numDocsReturned
+ });
+ // Closing the cursor should result in 0 ms for the operation.
+ assert.eq(queryStatsEntry.metrics.lastExecutionMicros, 0);
+}
+
+function runTest(conn) {
+ testCollectionChangeStream(conn);
+ testDatabaseChangeStream(conn);
+ testWholeClusterChangeStream(conn);
+}
+
+{
+ // Test the non-sharded case.
+ const rst = new ReplSetTest({nodes: 2});
+ rst.startSet({setParameter: {internalQueryStatsRateLimit: -1}});
+ rst.initiate();
+ rst.getPrimary().getDB("admin").setLogLevel(3, "queryStats");
+ runTest(rst.getPrimary());
+ rst.stopSet();
+}
+
+{
+ // Test on a sharded cluster.
+ const st = new ShardingTest({
+ mongos: 1,
+ shards: 2,
+ config: 1,
+ rs: {nodes: 1, setParameter: {writePeriodicNoops: true, periodicNoopIntervalSecs: 1}},
+ mongosOptions: {
+ setParameter: {
+ internalQueryStatsRateLimit: -1,
+ }
+ },
+ });
+ runTest(st.s);
+ st.stop();
+}
diff --git a/jstests/noPassthrough/queryStats/query_stats_change_stream_evict.js b/jstests/noPassthrough/queryStats/query_stats_change_stream_evict.js
new file mode 100644
index 00000000000..c9782f4388e
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_change_stream_evict.js
@@ -0,0 +1,71 @@
+// Tests the collection of query stats for a change stream query if the entry is evicted while the
+// cursor is still active.
+// @tags: [
+// uses_change_streams,
+// requires_replication,
+// requires_sharding,
+// requires_fcv_60
+// ]
+load("jstests/libs/query_stats_utils.js"); // For getLatestQueryStatsEntry, getQueryStats,
+ // resetQueryStatsStore.
+load("jstests/libs/fixture_helpers.js"); // For FixtureHelpers.
+load("jstests/libs/collection_drop_recreate.js"); // For assertDropAndRecreateCollection.
+
+function runTest(conn) {
+ const db = conn.getDB("test");
+ assertDropAndRecreateCollection(db, "coll");
+
+ // Check creation of change stream cursor is recorded.
+ let cursor = db.coll.watch([]);
+
+ // Check that change stream entry was recorded.
+ let queryStatsEntry = getLatestQueryStatsEntry(db);
+ checkChangeStreamEntry({
+ queryStatsEntry: queryStatsEntry,
+ db: db,
+ collectionName: "coll",
+ numExecs: 1,
+ numDocsReturned: 0
+ });
+
+ // Reset the store to evict the change streams metric.
+ resetQueryStatsStore(db, "1MB");
+
+ // Insert document into a collection which should update the cursor.
+ assert.commandWorked(db.coll.insert({_id: 0, a: 1}));
+ assert.soon(() => cursor.hasNext());
+
+ // There should be nothing stored in the query stats store.
+ let queryStats = getQueryStats(db);
+ assert.eq(queryStats, []);
+
+ // Close cursor.
+ cursor.close();
+}
+
+{
+ // Test the non-sharded case.
+ const rst = new ReplSetTest({nodes: 2});
+ rst.startSet({setParameter: {internalQueryStatsRateLimit: -1}});
+ rst.initiate();
+ rst.getPrimary().getDB("admin").setLogLevel(3, "queryStats");
+ runTest(rst.getPrimary());
+ rst.stopSet();
+}
+
+{
+ // Test on a sharded cluster.
+ const st = new ShardingTest({
+ mongos: 1,
+ shards: 2,
+ config: 1,
+ rs: {nodes: 1, setParameter: {writePeriodicNoops: true, periodicNoopIntervalSecs: 1}},
+ mongosOptions: {
+ setParameter: {
+ internalQueryStatsRateLimit: -1,
+ }
+ },
+ });
+ runTest(st.s);
+ st.stop();
+} \ No newline at end of file
diff --git a/jstests/noPassthrough/queryStats/query_stats_change_stream_per_shard_cursor.js b/jstests/noPassthrough/queryStats/query_stats_change_stream_per_shard_cursor.js
new file mode 100644
index 00000000000..d2147f73eeb
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_change_stream_per_shard_cursor.js
@@ -0,0 +1,222 @@
+/**
+ * Tests the collection of query stats for a change stream query created using $_passthroughToShard.
+ * @tags: [
+ * requires_sharding,
+ * uses_change_streams,
+ * requires_fcv_60
+ * ]
+ */
+load("jstests/libs/query_stats_utils.js");
+
+const dbName = jsTestName();
+
+function testCollectionChangeStream(sdb, shardId) {
+ // Check that change stream explain command is recorded.
+ let aggregateCmd = {
+ aggregate: "coll",
+ cursor: {},
+ pipeline: [{$changeStream: {}}],
+ $_passthroughToShard: {shard: shardId},
+ };
+
+ assert.commandWorked(sdb.runCommand({explain: aggregateCmd, verbosity: "executionStats"}));
+
+ let queryStatsEntry = getLatestQueryStatsEntry(sdb);
+ checkChangeStreamEntry({
+ queryStatsEntry: queryStatsEntry,
+ db: sdb,
+ collectionName: "coll",
+ numExecs: 1,
+ numDocsReturned: 0
+ });
+
+ assert(queryStatsEntry.key.hasOwnProperty("explain"));
+ jsTestLog("passthroughToShard");
+ jsTestLog(queryStatsEntry);
+ assert(queryStatsEntry.key.hasOwnProperty("$_passthroughToShard"));
+ assert(queryStatsEntry.key.$_passthroughToShard.hasOwnProperty("shard"));
+
+ // Check creation of change stream cursor with $_passthroughToShard is recorded.
+ let resp = sdb.runCommand(aggregateCmd);
+ assert.commandWorked(resp);
+
+ let cursor = new DBCommandCursor(sdb, resp);
+
+ let numExecs = 1;
+ let numDocsReturned = 0;
+
+ queryStatsEntry = getLatestQueryStatsEntry(sdb);
+ checkChangeStreamEntry({
+ queryStatsEntry: queryStatsEntry,
+ db: sdb,
+ collectionName: "coll",
+ numExecs: numExecs,
+ numDocsReturned: numDocsReturned
+ });
+ assert(queryStatsEntry.key.hasOwnProperty("$_passthroughToShard"));
+ assert(queryStatsEntry.key.$_passthroughToShard.hasOwnProperty("shard"));
+
+ // Insert document into collection on the shard the change stream was created on (negative id
+ // value), and make sure retrieving the information updates the query stats entry.
+ assert.commandWorked(sdb.coll.insertOne({location: 1, _id: -3}));
+ numExecs += getNumberOfGetMoresUntilNextDocForChangeStream(cursor);
+ numDocsReturned++;
+
+ queryStatsEntry = getLatestQueryStatsEntry(sdb);
+ checkChangeStreamEntry({
+ queryStatsEntry: queryStatsEntry,
+ db: sdb,
+ collectionName: "coll",
+ numExecs: numExecs,
+ numDocsReturned: numDocsReturned
+ });
+ assert(queryStatsEntry.key.hasOwnProperty("$_passthroughToShard"));
+ assert(queryStatsEntry.key.$_passthroughToShard.hasOwnProperty("shard"));
+
+ // Close cursor and check that it updates query stats entry.
+ cursor.close();
+ numExecs++;
+ queryStatsEntry = getLatestQueryStatsEntry(sdb);
+ checkChangeStreamEntry({
+ queryStatsEntry: queryStatsEntry,
+ db: sdb,
+ collectionName: "coll",
+ numExecs: numExecs,
+ numDocsReturned: numDocsReturned
+ });
+ assert(queryStatsEntry.key.hasOwnProperty("$_passthroughToShard"));
+ assert(queryStatsEntry.key.$_passthroughToShard.hasOwnProperty("shard"));
+
+ // Closing the cursor should result in 0 ms for the operation.
+ assert.eq(queryStatsEntry.metrics.lastExecutionMicros, 0);
+}
+
+function testDatabaseChangeStream(sdb, shardId) {
+ // Check creation of change stream cursor with $_passthroughToShard for whole database is
+ // recorded.
+ let aggregateCmd = {
+ aggregate: 1,
+ cursor: {},
+ pipeline: [{$changeStream: {}}],
+ $_passthroughToShard: {shard: shardId}
+ };
+
+ let resp = sdb.runCommand(aggregateCmd);
+ assert.commandWorked(resp);
+
+ let cursor = new DBCommandCursor(sdb, resp);
+
+ // Check creation of change stream cursor is recorded.
+ let numExecs = 1;
+ let numDocsReturned = 0;
+
+ let queryStatsEntry = getLatestQueryStatsEntry(sdb);
+ checkChangeStreamEntry({
+ queryStatsEntry: queryStatsEntry,
+ db: sdb,
+ collectionName: "$cmd.aggregate",
+ numExecs: numExecs,
+ numDocsReturned: numDocsReturned
+ });
+
+ assert(queryStatsEntry.key.hasOwnProperty("$_passthroughToShard"));
+ assert(queryStatsEntry.key.$_passthroughToShard.hasOwnProperty("shard"));
+
+ // Insert document into collection on the shard the change stream is watching (negative id
+ // value), and make sure retrieving the information updates the query stats entry.
+ assert.commandWorked(sdb.coll.insertOne({location: 3, _id: -5}));
+ numExecs += getNumberOfGetMoresUntilNextDocForChangeStream(cursor);
+ numDocsReturned++;
+
+ queryStatsEntry = getLatestQueryStatsEntry(sdb);
+ checkChangeStreamEntry({
+ queryStatsEntry: queryStatsEntry,
+ db: sdb,
+ collectionName: "$cmd.aggregate",
+ numExecs: numExecs,
+ numDocsReturned: numDocsReturned
+ });
+
+ assert(queryStatsEntry.key.hasOwnProperty("$_passthroughToShard"));
+ assert(queryStatsEntry.key.$_passthroughToShard.hasOwnProperty("shard"));
+
+ // Insert document into different collection on the shard the change stream is watching
+ // (negative id value), and make sure retrieving the information updates the query stats entry.
+ assert.commandWorked(sdb.coll2.insertOne({location: 4, _id: -10}));
+ numExecs += getNumberOfGetMoresUntilNextDocForChangeStream(cursor);
+ numDocsReturned++;
+
+ queryStatsEntry = getLatestQueryStatsEntry(sdb);
+ checkChangeStreamEntry({
+ queryStatsEntry: queryStatsEntry,
+ db: sdb,
+ collectionName: "$cmd.aggregate",
+ numExecs: numExecs,
+ numDocsReturned: numDocsReturned
+ });
+ assert(queryStatsEntry.key.hasOwnProperty("$_passthroughToShard"));
+ assert(queryStatsEntry.key.$_passthroughToShard.hasOwnProperty("shard"));
+
+ // Close cursor and check that it increases numExecs.
+ cursor.close();
+ numExecs++;
+
+ queryStatsEntry = getLatestQueryStatsEntry(sdb);
+ checkChangeStreamEntry({
+ queryStatsEntry: queryStatsEntry,
+ db: sdb,
+ collectionName: "$cmd.aggregate",
+ numExecs: numExecs,
+ numDocsReturned: numDocsReturned
+ });
+ assert(queryStatsEntry.key.hasOwnProperty("$_passthroughToShard"));
+ assert(queryStatsEntry.key.$_passthroughToShard.hasOwnProperty("shard"));
+
+ // Closing the cursor should result in 0 ms for the operation.
+ assert.eq(queryStatsEntry.metrics.lastExecutionMicros, 0);
+}
+
+function runTest(sdb, shardId) {
+ testCollectionChangeStream(sdb, shardId);
+ testDatabaseChangeStream(sdb, shardId);
+}
+
+function setupShardedCluster() {
+ const st = new ShardingTest({
+ shards: 2,
+ mongos: 1,
+ config: 1,
+ rs: {nodes: 1, setParameter: {writePeriodicNoops: false}},
+ other: {
+ mongosOptions: {
+ setParameter: {
+ internalQueryStatsRateLimit: -1,
+ }
+ }
+ }
+ });
+
+ const sdb = st.s0.getDB(dbName);
+ assert.commandWorked(sdb.dropDatabase());
+
+ sdb.setProfilingLevel(0, -1);
+ st.shard0.getDB(dbName).setProfilingLevel(0, -1);
+
+ // Shard the relevant collections.
+ assert.commandWorked(st.s.adminCommand({enableSharding: dbName, primaryShard: st.shard0.name}));
+ // Shard the collection on {_id: 1}, split at {_id: 0} and move the empty upper chunk to
+ // shard1.
+ st.shardColl("coll", {_id: 1}, {_id: 0}, {_id: 0}, dbName);
+ st.shardColl("coll2", {_id: 1}, {_id: 0}, {_id: 0}, dbName);
+
+ // Returns shardID of shard containing the negative _id values.
+ const shardId = st.shard0.shardName;
+ return [sdb, st, shardId];
+}
+
+{
+ let [sdb, st, shardId] = setupShardedCluster();
+ st.shard0.getDB("admin").setLogLevel(3, "queryStats");
+ runTest(sdb, shardId);
+ st.stop();
+}
diff --git a/jstests/noPassthrough/queryStats/query_stats_collectionType.js b/jstests/noPassthrough/queryStats/query_stats_collectionType.js
new file mode 100644
index 00000000000..77428f9dc29
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_collectionType.js
@@ -0,0 +1,208 @@
+/**
+ * Test that collectionType is returned properly in $queryStats. Checks for collection types
+ * "collection", "view", "timeseries", "nonExistent", and "virtual". Type "changeStream" is covered
+ * in query_stats_changeStreams.js.
+ * @tags: [requires_fcv_60]
+ */
+load("jstests/libs/query_stats_utils.js");
+(function() {
+"use strict";
+
+function runTest(conn) {
+ const testDB = conn.getDB('test');
+
+ // We create one collection for each corresponding type reported by query stats.
+ assert.commandWorked(testDB.createCollection(jsTestName() + "_collection"));
+ assert.commandWorked(testDB.createView(
+ jsTestName() + "_view", jsTestName() + "_collection", [{$match: {v: {$gt: 42}}}]));
+ assert.commandWorked(
+ testDB.createCollection(jsTestName() + "_timeseries", {timeseries: {timeField: "time"}}));
+ // We create an additional view over the existing view to test full view resolution. We use
+ // the $setWindowFields stage since it desugars into multiple stages, to make sure the query
+ // shape produced is restricted to the user-provided query.
+ assert.commandWorked(testDB.createView(jsTestName() + "_viewOverView", jsTestName() + "_view", [
+ {
+ $setWindowFields: {
+ partitionBy: "$x",
+ sortBy: {v: 1},
+ output: {sum: {$sum: "$y", window: {documents: ["unbounded", "current"]}}}
+ }
+ },
+ {$project: {_id: 0, v: 1, x: 1, y: "$output.sum"}}
+ ]));
+
+ // Next we run queries over each of the collection types to generate query stats.
+
+ // Base _collection has a few simple documents.
+ var coll = testDB[jsTestName() + "_collection"];
+ coll.insert({v: 1});
+ coll.insert({v: 2});
+ coll.insert({v: 3});
+ coll.find({v: 3}).toArray();
+ coll.aggregate([]).toArray();
+
+ // View _view is over _collection.
+ coll = testDB[jsTestName() + "_view"];
+ coll.find({v: 5}).toArray();
+ coll.aggregate([{$match: {v: {$lt: 99}}}]).toArray();
+
+ // View _viewOverView is over _view.
+ coll = testDB[jsTestName() + "_viewOverView"];
+ // Run an empty find to make sure filter in query stats key is recorded as empty.
+ coll.find({}).toArray();
+ // We test with $densify since it desugars into multiple stages, again to ensure the query
+ // shape calculated is restricted to the user-provided query. (In this case, the desugared
+ // $densify is acceptable, as long as the view pipeline is ignored).
+ coll.aggregate([{$densify: {field: "y", range: {step: 10, bounds: "full"}}}]).toArray();
+
+ // Timeseries collection _timeseries.
+ coll = testDB[jsTestName() + "_timeseries"];
+ coll.insert({v: 1, time: ISODate("2021-05-18T00:00:00.000Z")});
+ coll.insert({v: 2, time: ISODate("2021-05-18T01:00:00.000Z")});
+ coll.insert({v: 3, time: ISODate("2021-05-18T02:00:00.000Z")});
+ coll.find({v: 6}).toArray();
+ // Run an empty aggregate to ensure pipeline in query stats key is recorded as empty.
+ coll.aggregate().toArray();
+
+ // QueryStats should still be collected for queries run on nonexistent collections.
+ assert.commandWorked(testDB.runCommand({find: jsTestName() + "_nonExistent", filter: {v: 6}}));
+ assert.commandWorked(
+ testDB.runCommand({aggregate: jsTestName() + "_nonExistent", pipeline: [], cursor: {}}));
+
+ // Verify that we have two query stats entries for the collection type. This assumes we have
+ // executed one find and one agg query for the given collection type.
+ function verifyQueryStatsForCollectionType(
+ collectionType, collectionName = jsTestName() + "_" + collectionType) {
+ const queryStats = getQueryStats(conn, {
+ extraMatch:
+ {"key.collectionType": collectionType, "key.queryShape.cmdNs.coll": collectionName}
+ });
+ // We should see one entry for find() and one for aggregate()
+ // for each collection type. The queries account for the fact
+ // that find() queries over views are rewritten to
+ // aggregate(). Ie, the query shapes are different because the
+ // queries are different.
+ assert.eq(2, queryStats.length, "Expected result for collection type " + collectionType);
+ }
+
+ verifyQueryStatsForCollectionType("collection");
+ verifyQueryStatsForCollectionType("view");
+ verifyQueryStatsForCollectionType("view", jsTestName() + "_viewOverView");
+ verifyQueryStatsForCollectionType("timeseries");
+ verifyQueryStatsForCollectionType("nonExistent");
+
+ // Run commands that should be tracked as "virtual" collection type.
+ assert.commandWorked(
+ testDB.adminCommand({aggregate: 1, pipeline: [{$currentOp: {}}], cursor: {}}));
+ assert.commandWorked(testDB.adminCommand(
+ {aggregate: 1, pipeline: [{$documents: [{a: 1}, {a: 4}]}], cursor: {}}));
+ assert.commandWorked(
+ testDB.adminCommand({aggregate: 1, pipeline: [{$listLocalSessions: {}}], cursor: {}}));
+
+ // Verify the queries on "virtual" collection types were tracked appropriately. This includes
+ // the 3 queries directly run above, in addition to 1 entry for the $queryStats aggregations
+ // run for the test.
+ let queryStats = getQueryStats(conn, {extraMatch: {"key.collectionType": "virtual"}});
+ assert.eq(4, queryStats.length);
+
+ // Verify that, for views, we capture the original query before it's rewritten. The view would
+ // include a $match stage with $gt predicate on 'v'. The viewOnView would include the same
+ // $match stage, the $setWindowFields stage, and the $project stage. The timeseries would
+ // include the bucket unpacking stages.
+ const findOnViewShape = getQueryStats(conn, {
+ extraMatch: {
+ "key.collectionType": "view",
+ "key.queryShape.command": "find",
+ "key.queryShape.cmdNs.coll": jsTestName() + "_view"
+ }
+ })[0]
+ .key.queryShape;
+ assert.eq(findOnViewShape.filter, {"v": {"$eq": "?number"}});
+
+ const aggOnViewShape = getQueryStats(conn, {
+ extraMatch: {
+ "key.collectionType": "view",
+ "key.queryShape.command": "aggregate",
+ "key.queryShape.cmdNs.coll": jsTestName() + "_view"
+ }
+ })[0]
+ .key.queryShape;
+ assert.eq(aggOnViewShape.pipeline, [{"$match": {"v": {"$lt": "?number"}}}]);
+
+ const findOnViewOverViewShape =
+ getQueryStats(conn, {
+ extraMatch: {
+ "key.collectionType": "view",
+ "key.queryShape.command": "find",
+ "key.queryShape.cmdNs.coll": jsTestName() + "_viewOverView"
+ }
+ })[0]
+ .key.queryShape;
+ assert.eq(findOnViewOverViewShape.filter, {});
+
+ const aggOnViewOverViewShape =
+ getQueryStats(conn, {
+ extraMatch: {
+ "key.collectionType": "view",
+ "key.queryShape.command": "aggregate",
+ "key.queryShape.cmdNs.coll": jsTestName() + "_viewOverView"
+ }
+ })[0]
+ .key.queryShape;
+ assert.eq(aggOnViewOverViewShape.pipeline, [
+ {"$sort": {"y": 1}},
+ {
+ "$_internalDensify": {
+ "field": "y",
+ "partitionByFields": [],
+ "range": {"step": "?number", "bounds": "full"}
+ }
+ }
+ ]);
+
+ const findOnTimeseriesShape = getQueryStats(conn, {
+ extraMatch: {
+ "key.collectionType": "timeseries",
+ "key.queryShape.command": "find",
+ "key.queryShape.cmdNs.coll": jsTestName() + "_timeseries"
+ }
+ })[0]
+ .key.queryShape;
+ assert.eq(findOnTimeseriesShape.filter, {"v": {"$eq": "?number"}});
+
+ const aggOnTimeseriesShape = getQueryStats(conn, {
+ extraMatch: {
+ "key.collectionType": "timeseries",
+ "key.queryShape.command": "aggregate",
+ "key.queryShape.cmdNs.coll": jsTestName() + "_timeseries"
+ }
+ })[0]
+ .key.queryShape;
+ assert.eq(aggOnTimeseriesShape.pipeline, []);
+}
+
+const conn = MongoRunner.runMongod({
+ setParameter: {
+ internalQueryStatsRateLimit: -1,
+ }
+});
+runTest(conn);
+MongoRunner.stopMongod(conn);
+
+// TODO Implement this in SERVER-76263.
+if (false) {
+ const st = new ShardingTest({
+ mongos: 1,
+ shards: 1,
+ config: 1,
+ rs: {nodes: 1},
+ mongosOptions: {
+ setParameter: {
+ internalQueryStatsSamplingRate: -1,
+ }
+ },
+ });
+ runTest(st.s);
+ st.stop();
+}
+}());
diff --git a/jstests/noPassthrough/queryStats/query_stats_disable_after_initial_request.js b/jstests/noPassthrough/queryStats/query_stats_disable_after_initial_request.js
new file mode 100644
index 00000000000..e088c045eef
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_disable_after_initial_request.js
@@ -0,0 +1,98 @@
+/**
+ * Tests that QueryStats metrics aren't collected if the feature is enabled initially but is
+ * disabled before the lifetime of the request is complete.
+ * @tags: [requires_fcv_60]
+ */
+load("jstests/libs/query_stats_utils.js"); // For getQueryStatsFindCmd.
+(function() {
+"use strict";
+
+// Test that no QueryStats entry is written when (1) dispatching an initial find query, (2)
+// disabling QueryStats, then (3) completing the command. Below, we run variations of this test
+// with combinations of different strategies to disable QueryStats and to end the command.
+function testStatsAreNotCollectedWhenDisabledBeforeCommandCompletion(
+ {conn, coll, disableQueryStatsFn, endCommandFn, enableQueryStatsFn}) {
+ // Issue a find commannd with a batchSize of 1 so that the query is not exhausted.
+ const cursor = coll.find({foo: 1}).batchSize(1);
+ // Must run .next() to make sure the initial request is executed now.
+ cursor.next();
+
+ // Disable QueryStats, then end the command,which triggers the path to writeQueryStats.
+ disableQueryStatsFn();
+ endCommandFn(cursor);
+
+ // Must re-enable QueryStats in order to check via $queryStats that nothing was recorded.
+ enableQueryStatsFn();
+ const res = getQueryStatsFindCmd(conn, {collName: coll.getName()});
+ assert.eq(res.length, 0, res);
+}
+
+// Turn on the collecting of QueryStats metrics.
+let options = {setParameter: {internalQueryStatsRateLimit: -1}};
+
+const conn = MongoRunner.runMongod(options);
+const testDB = conn.getDB('test');
+var coll = testDB[jsTestName()];
+coll.drop();
+
+const bulk = coll.initializeUnorderedBulkOp();
+const numDocs = 100;
+for (let i = 0; i < numDocs / 2; ++i) {
+ bulk.insert({foo: 0, bar: Math.floor(Math.random() * 3)});
+ bulk.insert({foo: 1, bar: Math.floor(Math.random() * -2)});
+}
+assert.commandWorked(bulk.execute());
+
+function setQueryStatsCacheSize(size) {
+ assert.commandWorked(testDB.adminCommand({setParameter: 1, internalQueryStatsCacheSize: size}));
+}
+
+function setFCV(newFCV) {
+ assert.commandWorked(testDB.adminCommand({setFeatureCompatibilityVersion: newFCV}));
+}
+
+// Tests the scenario of disabling QueryStats by setting internalQueryStatsCacheSize to
+// 0 and ending the command by running it to completion.
+testStatsAreNotCollectedWhenDisabledBeforeCommandCompletion({
+ conn: testDB,
+ coll,
+ disableQueryStatsFn: () => setQueryStatsCacheSize("0MB"),
+ endCommandFn: (cursor) => cursor.itcount(),
+ enableQueryStatsFn: () => setQueryStatsCacheSize("10MB")
+});
+
+// Tests the scenario of disabling QueryStats by setting internalQueryStatsCacheSize to
+// 0 and ending the command by killing the cursor.
+testStatsAreNotCollectedWhenDisabledBeforeCommandCompletion({
+ conn: testDB,
+ coll,
+ disableQueryStatsFn: () => setQueryStatsCacheSize("0MB"),
+ endCommandFn: (cursor) => assert.commandWorked(
+ testDB.runCommand({killCursors: coll.getName(), cursors: [cursor.getId()]})),
+ enableQueryStatsFn: () => setQueryStatsCacheSize("10MB")
+});
+
+jsTestLog(lastLTSFCV);
+// Tests the scenario of disabling query stats by downgrading the FCV and ending the command by
+// running it to completion.
+testStatsAreNotCollectedWhenDisabledBeforeCommandCompletion({
+ conn: testDB,
+ coll,
+ disableQueryStatsFn: () => setFCV(lastLTSFCV),
+ endCommandFn: (cursor) => cursor.itcount(),
+ enableQueryStatsFn: () => setFCV(binVersionToFCV("latest"))
+});
+
+// Tests the scenario of disabling query stats by downgrading the FCV and ending the command by
+// killing the cursor.
+testStatsAreNotCollectedWhenDisabledBeforeCommandCompletion({
+ conn: testDB,
+ coll,
+ disableQueryStatsFn: () => setFCV(lastLTSFCV),
+ endCommandFn: (cursor) => assert.commandWorked(
+ testDB.runCommand({killCursors: coll.getName(), cursors: [cursor.getId()]})),
+ enableQueryStatsFn: () => setFCV(binVersionToFCV("latest"))
+});
+
+MongoRunner.stopMongod(conn);
+}());
diff --git a/jstests/noPassthrough/queryStats/query_stats_explain_cmd_agg.js b/jstests/noPassthrough/queryStats/query_stats_explain_cmd_agg.js
new file mode 100644
index 00000000000..2a12b85f274
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_explain_cmd_agg.js
@@ -0,0 +1,37 @@
+/**
+ * This test confirms that the correct verbosity levels are stored in the query stats key for
+ * explain commands on an agg query.
+ * @tags: [requires_fcv_60]
+ */
+load("jstests/libs/query_stats_utils.js");
+
+const testColl = jsTestName();
+
+const testPipeline = [{"$match": {"bar": {"$gte": 1}}}, {"$count": "bars"}];
+
+function assertVerbosityField(coll, pipeline, verbosity) {
+ assert.commandWorked(coll.explain(verbosity).aggregate(pipeline));
+ const entry = getLatestQueryStatsEntry(coll.getDB().getMongo(), {collName: coll.getName()});
+ assert.eq(getValueAtPath(entry, "key.explain"), verbosity, tojson(entry));
+ assert.eq(getValueAtPath(entry, "metrics.execCount"), 1, tojson(entry));
+ // TODO SERVER-89439: Uncomment this block and perhaps add more assertions.
+ // if (!FixtureHelpers.isSharded(coll)) {
+ // TODO SERVER-89053: Remove conditional statement to assert in sharded tests.
+ // assert.gt(getValueAtPath(entry, "metrics.lastExecutionMicros"), 1, tojson(entry));
+ // }
+}
+
+withQueryStatsEnabled(testColl, (coll) => {
+ // Insert documents to ensure we raise 'execCount'.
+ const bulk = coll.initializeUnorderedBulkOp();
+ const numDocs = 100;
+ for (let i = 0; i < numDocs / 2; ++i) {
+ bulk.insert({foo: 0, bar: Math.floor(Math.random() * 3)});
+ bulk.insert({foo: 1, bar: Math.floor(Math.random() * -2)});
+ }
+ assert.commandWorked(bulk.execute());
+
+ assertVerbosityField(coll, testPipeline, 'queryPlanner');
+ assertVerbosityField(coll, testPipeline, 'allPlansExecution');
+ assertVerbosityField(coll, testPipeline, 'executionStats');
+});
diff --git a/jstests/noPassthrough/queryStats/query_stats_expressions.js b/jstests/noPassthrough/queryStats/query_stats_expressions.js
new file mode 100644
index 00000000000..133582cb715
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_expressions.js
@@ -0,0 +1,76 @@
+/**
+ * Test that queryStats works properly for a find command that uses agg expressions and produces the
+ * proper query shape without issues during re-parsing.
+ * @tags: [requires_fcv_60]
+ */
+load("jstests/libs/query_stats_utils.js"); // For getQueryStats and resetQueryStatsStore.
+
+(function() {
+"use strict";
+
+// Turn on the collecting of queryStats metrics.
+let options = {
+ setParameter: {internalQueryStatsRateLimit: -1},
+};
+
+const conn = MongoRunner.runMongod(options);
+const testDB = conn.getDB('test');
+var coll = testDB[jsTestName()];
+coll.drop();
+
+const bulk = coll.initializeUnorderedBulkOp();
+const numDocs = 100;
+for (let i = 0; i < numDocs / 2; ++i) {
+ bulk.insert({foo: i, bar: i, applyDiscount: true, word: "asdf"});
+ bulk.insert({foo: i, bar: i, applyDiscount: false, word: "ghjk"});
+}
+assert.commandWorked(bulk.execute());
+coll.createIndex({foo: 1});
+
+// Tests that $meta is re-parsed correctly by ensuring the metaDataKeyword is not serialized as
+// string literal.
+{
+ resetQueryStatsStore(conn, "1MB");
+ coll.find({$expr: {idxKey: {$meta: "indexKey"}}}).itcount();
+ let queryStats = getQueryStats(testDB);
+ assert.eq({"$expr": {"idxKey": {"$meta": "indexKey"}}}, queryStats[0].key.queryShape.filter);
+}
+
+// Tests that $regexMatch is re-parsed correctly. The parser does not check that regex is a valid
+// regex pattern, so regular serialization is okay.
+{
+ resetQueryStatsStore(conn, "1MB");
+ coll.find({$expr: {result: {$regexMatch: {input: "$word", regex: "^a"}}}}).itcount();
+ let queryStats = getQueryStats(testDB);
+ assert.eq({"$expr": {"result": {"$regexMatch": {"input": "$word", "regex": "?string"}}}},
+ queryStats[0].key.queryShape.filter);
+}
+
+// Tests that $let is re-parsed correctly, by ensuring the variables are not serialized as string
+// literals.
+{
+ resetQueryStatsStore(conn, "1MB");
+ coll.find({$expr: {$let: {
+ vars: {
+ total: { $add: [ '$foo', '$bar' ] },
+ discounted: { $cond: { if: '$applyDiscount', then: 0.9, else: 1 } }
+ },
+ in: { $multiply: [ "$$total", "$$discounted" ] }
+ }}}).itcount();
+ let queryStats = getQueryStats(testDB);
+ assert.eq({
+ "$expr": {
+ "$let": {
+ "vars": {
+ "total": {"$add": ["$foo", "$bar"]},
+ "discounted": {"$cond": ["$applyDiscount", "?number", "?number"]}
+ },
+ "in": {"$multiply": ["$$total", "$$discounted"]}
+ }
+ }
+ },
+ queryStats[0].key.queryShape.filter);
+}
+
+MongoRunner.stopMongod(conn);
+}());
diff --git a/jstests/noPassthrough/queryStats/query_stats_feature_flag.js b/jstests/noPassthrough/queryStats/query_stats_feature_flag.js
new file mode 100644
index 00000000000..5580c5ec29d
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_feature_flag.js
@@ -0,0 +1,31 @@
+/**
+ * Test that calls to read from query stats store fail when feature flag is turned off.
+ */
+load('jstests/libs/analyze_plan.js');
+load("jstests/libs/feature_flag_util.js");
+
+(function() {
+"use strict";
+
+// This test specifically tests error handling when the feature flag is not on.
+// TODO SERVER-65800 this test can be removed when the feature flag is removed.
+const conn = MongoRunner.runMongod({
+ setParameter: {featureFlagQueryStats: false},
+});
+const testDB = conn.getDB('test');
+
+// Pipeline to read queryStats store should fail without feature flag turned on.
+assert.commandFailedWithCode(
+ testDB.adminCommand({aggregate: 1, pipeline: [{$queryStats: {}}], cursor: {}}),
+ ErrorCodes.QueryFeatureNotAllowed);
+
+// Pipeline, with a filter, to read queryStats store fails without feature flag turned on.
+assert.commandFailedWithCode(testDB.adminCommand({
+ aggregate: 1,
+ pipeline: [{$queryStats: {}}, {$match: {"key.queryShape.find": {$eq: "###"}}}],
+ cursor: {}
+}),
+ ErrorCodes.QueryFeatureNotAllowed);
+
+MongoRunner.stopMongod(conn);
+}());
diff --git a/jstests/noPassthrough/queryStats/query_stats_find_cmd_collect_on_mongos.js b/jstests/noPassthrough/queryStats/query_stats_find_cmd_collect_on_mongos.js
new file mode 100644
index 00000000000..a1f3bc5d59e
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_find_cmd_collect_on_mongos.js
@@ -0,0 +1,126 @@
+/**
+ * Test that mongos is collecting query stats metrics for find queries.
+ * @tags: [requires_fcv_60]
+ */
+
+load('jstests/libs/query_stats_utils.js');
+
+(function() {
+"use strict";
+
+const st = new ShardingTest({
+ mongos: 1,
+ shards: 1,
+ config: 1,
+ rs: {nodes: 1},
+ mongosOptions: {
+ setParameter: {
+ internalQueryStatsRateLimit: -1,
+ }
+ },
+});
+const mongos = st.s;
+const db = mongos.getDB("test");
+const coll = db.coll;
+coll.insert({v: 1});
+coll.insert({v: 4});
+
+// Assert that, for find queries, no query stats results are written until a cursor has reached
+// exhaustion; ensure accurate results once they're written.
+{
+ const queryStatsKey = {
+ queryShape: {
+ cmdNs: {db: "test", coll: "coll"},
+ command: "find",
+ filter: {$and: [{v: {$gt: "?number"}}, {v: {$lt: "?number"}}]},
+ },
+ readConcern: {level: "local", provenance: "implicitDefault"},
+ batchSize: "?number",
+ client: {application: {name: "MongoDB Shell"}}
+ };
+
+ const cursor = coll.find({v: {$gt: 0, $lt: 5}}).batchSize(1); // returns 1 doc
+
+ // Since the cursor hasn't been exhausted yet, ensure no query stats results have been written
+ // yet.
+ let queryStats = getQueryStats(db);
+ assert.eq(0, queryStats.length, queryStats);
+
+ // Run a getMore to exhaust the cursor, then ensure query stats results have been written
+ // accurately. batchSize must be 2 so the cursor recognizes exhaustion.
+ assert.commandWorked(db.runCommand({
+ getMore: cursor.getId(),
+ collection: coll.getName(),
+ batchSize: 2
+ })); // returns 1 doc, exhausts the cursor
+ queryStats = getQueryStatsFindCmd(db);
+ assert.eq(1, queryStats.length, queryStats);
+ assertExpectedResults(queryStats[0],
+ queryStatsKey,
+ /* expectedExecCount */ 1,
+ /* expectedDocsReturnedSum */ 2,
+ /* expectedDocsReturnedMax */ 2,
+ /* expectedDocsReturnedMin */ 2,
+ /* expectedDocsReturnedSumOfSq */ NumberDecimal("4"),
+ /* getMores */ true);
+
+ // Run more queries (to exhaustion) with the same query shape, and ensure query stats results
+ // are accurate.
+ coll.find({v: {$gt: 2, $lt: 3}}).batchSize(10).toArray(); // returns 0 docs
+ coll.find({v: {$gt: 0, $lt: 1}}).batchSize(10).toArray(); // returns 0 docs
+ coll.find({v: {$gt: 0, $lt: 2}}).batchSize(10).toArray(); // return 1 doc
+ queryStats = getQueryStatsFindCmd(db);
+ assert.eq(1, queryStats.length, queryStats);
+ assertExpectedResults(queryStats[0],
+ queryStatsKey,
+ /* expectedExecCount */ 4,
+ /* expectedDocsReturnedSum */ 3,
+ /* expectedDocsReturnedMax */ 2,
+ /* expectedDocsReturnedMin */ 0,
+ /* expectedDocsReturnedSumOfSq */ NumberDecimal("5"),
+ /* getMores */ true);
+}
+
+// Assert on batchSize-limited find queries that killCursors will write metrics with partial results
+// to the query stats store.
+{
+ const coll2 = db.coll2;
+ coll2.insert({v: 1});
+ coll2.insert({v: 4});
+ const queryStatsKey = {
+ queryShape: {
+ cmdNs: {db: "test", coll: "coll2"},
+ command: "find",
+ filter: {$and: [{v: {$gt: "?number"}}, {v: {$lt: "?number"}}]},
+ },
+ readConcern: {level: "local", provenance: "implicitDefault"},
+ batchSize: "?number",
+ client: {application: {name: "MongoDB Shell"}}
+ };
+
+ const cursor1 = coll2.find({v: {$gt: 0, $lt: 5}}).batchSize(1); // returns 1 doc
+ const cursor2 = coll2.find({v: {$gt: 0, $lt: 2}}).batchSize(1); // returns 1 doc
+
+ assert.commandWorked(
+ db.runCommand({killCursors: coll2.getName(), cursors: [cursor1.getId(), cursor2.getId()]}));
+ const queryStats = getLatestQueryStatsEntry(db);
+ assertExpectedResults(queryStats,
+ queryStatsKey,
+ /* expectedExecCount */ 2,
+ /* expectedDocsReturnedSum */ 2,
+ /* expectedDocsReturnedMax */ 1,
+ /* expectedDocsReturnedMin */ 1,
+ /* expectedDocsReturnedSumOfSq */ NumberDecimal("2"),
+ /* getMores */ false);
+}
+
+// SERVER-83964 Test that query stats are collected if the database doesn't exist.
+{
+ const nonExistentDB = db.getSiblingDB("newDB");
+ assert.eq(null, nonExistentDB.anything.findOne());
+ const entry = getLatestQueryStatsEntry(db, {collName: "anything"});
+ assert.neq(null, entry);
+}
+
+st.stop();
+}());
diff --git a/jstests/noPassthrough/queryStats/query_stats_find_key.js b/jstests/noPassthrough/queryStats/query_stats_find_key.js
new file mode 100644
index 00000000000..2c1d65f5bb5
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_find_key.js
@@ -0,0 +1,113 @@
+/**
+ * This test confirms that query stats store key fields for a find command are properly nested and
+ * none are missing.
+ * @tags: [requires_fcv_60]
+ */
+load("jstests/libs/query_stats_utils.js"); // For runCommandAndValidateQueryStats and
+ // withQueryStatsEnabled and getLatestQueryStatsEntry
+(function() {
+"use strict";
+
+const collName = jsTestName();
+
+const findCommandObj = {
+ find: collName,
+ filter: {v: {$eq: 2}},
+ oplogReplay: true,
+ comment: "this is a test!!",
+ min: {"v": 0},
+ max: {"v": 4},
+ hint: {"v": 1},
+ sort: {a: -1},
+ returnKey: false,
+ noCursorTimeout: true,
+ showRecordId: false,
+ tailable: false,
+ awaitData: false,
+ allowPartialResults: true,
+ skip: 1,
+ limit: 2,
+ maxTimeMS: 50 * 1000,
+ collation: {locale: "en_US", strength: 2},
+ allowDiskUse: true,
+ readConcern: {level: "local"},
+ batchSize: 2,
+ singleBatch: true,
+ let : {},
+ projection: {_id: 0},
+ apiDeprecationErrors: false,
+ apiVersion: "1",
+ apiStrict: false,
+};
+
+const queryShapeFindFields = [
+ "cmdNs",
+ "command",
+ "filter",
+ "sort",
+ "projection",
+ "skip",
+ "limit",
+ "singleBatch",
+ "max",
+ "min",
+ "returnKey",
+ "showRecordId",
+ "tailable",
+ "oplogReplay",
+ "awaitData",
+ "collation",
+ "allowDiskUse",
+ "let"
+];
+
+// The outer fields not nested inside queryShape.
+const findKeyFields = [
+ "queryShape",
+ "batchSize",
+ "comment",
+ "maxTimeMS",
+ "noCursorTimeout",
+ "readConcern",
+ "allowPartialResults",
+ "apiDeprecationErrors",
+ "apiVersion",
+ "apiStrict",
+ "collectionType",
+ "client",
+ "hint"
+];
+
+/**
+ * Regression test for SERVER-85532: $hint syntax will not be validated if the collection does not
+ * exist. Make sure that query stats can still handle an invalid hint. See SERVER-85500.
+ *
+ * @param testDB
+ */
+function validateInvalidHint(testDB) {
+ const collName = "invalid_hint_coll";
+ var coll = testDB[collName];
+ coll.drop();
+ // $hint is supposed to be a string or object, but this works:
+ assert.commandWorked(testDB.runCommand({
+ find: collName,
+ hint: {$hint: -1.0},
+ }));
+ const entry = getLatestQueryStatsEntry(testDB.getMongo(), {collName: collName});
+ assert.eq(entry.key.hint, {$hint: "?number"});
+}
+
+withQueryStatsEnabled(collName, (coll) => {
+ // Have to create an index for hint not to fail.
+ assert.commandWorked(coll.createIndex({v: 1}));
+
+ runCommandAndValidateQueryStats({
+ coll: coll,
+ commandName: "find",
+ commandObj: findCommandObj,
+ shapeFields: queryShapeFindFields,
+ keyFields: findKeyFields,
+ });
+ validateInvalidHint(coll);
+});
+}());
diff --git a/jstests/noPassthrough/queryStats/query_stats_key_hash.js b/jstests/noPassthrough/queryStats/query_stats_key_hash.js
new file mode 100644
index 00000000000..0eaacf9fecf
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_key_hash.js
@@ -0,0 +1,98 @@
+/**
+ * This test confirms that the hash generated alongside query stats entries is unique and stable
+ * across restarts.
+ * @tags: [requires_fcv_60]
+ */
+(function() {
+'use strict';
+
+load("jstests/libs/query_stats_utils.js"); // For getQueryStatsFindCmd and getQueryStatsKeyHashes.
+
+const replTest = new ReplSetTest({name: 'queryStatsKeyHashTest', nodes: 2});
+
+// Turn on the collecting of query stats metrics.
+replTest.startSet({setParameter: {internalQueryStatsRateLimit: -1}});
+replTest.initiate();
+
+const conn = replTest.getPrimary();
+const collName = jsTestName();
+const coll = conn.getDB("test")[collName];
+coll.drop();
+coll.insert({x: 5});
+
+let totalShapes = 0;
+
+// Simple query, different field names.
+coll.find({x: 5}).toArray();
+++totalShapes;
+coll.find({y: 5}).toArray();
+++totalShapes;
+
+// Simple $regex query, sort, and limit.
+coll.find({x: {$regex: ".*"}}).sort({y: -1}).limit(10).toArray();
+++totalShapes;
+coll.find({x: {$regex: "."}}).sort({y: -1}).limit(10).toArray();
+// Don't increment 'totalShapes' - different $regex value still means the same shape.
+coll.find({x: {$regex: "."}}).sort({y: -1}).limit(10).toArray();
+
+// Simple query with projection and limit.
+coll.find({x: {$regex: ".*"}}, {_id: 0, x: "$$ROOT", y: {$bsonSize: ["$$ROOT"]}})
+ .limit(5)
+ .toArray();
+++totalShapes;
+coll.find({x: {$regex: ".*"}}, {_id: 0, x: "$$ROOT", y: {$bsonSize: ["$$ROOT"]}})
+ .limit(10)
+ .toArray();
+// Don't increment 'totalShapes' - different limit value still means the same shape.
+coll.find({x: {$regex: ".*"}}, {_id: false, x: "$$ROOT", y: {$bsonSize: ["$$ROOT"]}})
+ .limit(5)
+ .toArray();
+// Don't increment 'totalShapes' - 'false' projection is the same as '0'.
+coll.find({x: {$regex: ".*"}}, {_id: 0, x: "$$ROOT", y: {$bsonSize: ["$$CURRENT"]}})
+ .limit(5)
+ .toArray();
+++totalShapes; // different $bsonSize argument
+coll.find({x: {$regex: ".*"}}, {x: "$$ROOT", y: {$bsonSize: ["$$ROOT"]}, _id: true})
+ .limit(5)
+ .toArray();
+++totalShapes; // explicit '_id' inclusion projection
+coll.find({x: {$regex: ".*"}}, {x: "$$ROOT", y: {$bsonSize: ["$$ROOT"]}}).limit(5).toArray();
+// Don't increment 'totalShapes' - '_id' inclusion projection is implicit.
+
+// Different command options.
+const filter = {
+ x: 5
+};
+const maxTimeMS = 123;
+const batchSize = 10;
+const readPref = "primary";
+coll.find(filter).maxTimeMS(maxTimeMS).batchSize(batchSize).readPref(readPref).toArray();
+++totalShapes;
+// Vary values for the options specified - shape should not change for 'maxTimeMS' and
+// 'batchSize', but should for 'readPreference'.
+coll.find(filter).maxTimeMS(456).batchSize(batchSize).readPref(readPref).toArray();
+coll.find(filter).maxTimeMS(maxTimeMS).batchSize(20).readPref(readPref).toArray();
+coll.find(filter).maxTimeMS(maxTimeMS).batchSize(batchSize).readPref("nearest").toArray();
+++totalShapes;
+
+const untransformedEntries = getQueryStatsFindCmd(conn, {collName, transformIdentifiers: false});
+const untransformedKeyHashes = getQueryStatsKeyHashes(untransformedEntries);
+
+// Ensure that we got as many unique key hashes as we expect give the queries that we ran.
+assert.eq(untransformedKeyHashes.length, totalShapes, tojson(untransformedEntries));
+
+// We need to filter on the HMAC-ed collection name when we set {transformIdentifiers: true}.
+const transformedCollName = "h52faC1z+jJCQp/Hq008ffChPpnk/nhAgo70uX1FFFI=";
+const transformedEntries =
+ getQueryStatsFindCmd(conn, {collName: transformedCollName, transformIdentifiers: true});
+const transformedKeyHashes = getQueryStatsKeyHashes(transformedEntries);
+
+// We expect the hash to be derived from the untransformed shape, so the transformed $queryStats
+// call should produce the same hash values as the untransformed one.
+assert.sameMembers(untransformedKeyHashes,
+ transformedKeyHashes,
+ `untransformedEntries = ${tojson(untransformedEntries)}, transformedEntries = ${
+ tojson(transformedEntries)}`);
+
+replTest.stopSet();
+})();
diff --git a/jstests/noPassthrough/queryStats/query_stats_logging.js b/jstests/noPassthrough/queryStats/query_stats_logging.js
new file mode 100644
index 00000000000..c09f2948aa0
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_logging.js
@@ -0,0 +1,99 @@
+/**
+ * Test logging of $queryStats.
+ * @tags: [requires_fcv_60]
+ */
+
+(function() {
+"use strict";
+let options = {
+ setParameter: {internalQueryStatsRateLimit: -1},
+};
+
+function countMatching(arr, func) {
+ let count = 0;
+ let i = arr.length;
+ while (i--) {
+ if (func(arr[i])) {
+ count += 1;
+ }
+ }
+ return count;
+}
+
+function runQueryStatsAndVerifyLogs({pipeline, transformed, logLevel}) {
+ const conn = MongoRunner.runMongod(options);
+ const db = conn.getDB('test');
+ var coll = db[jsTestName()];
+ coll.drop();
+
+ // Set the logLevel.
+ assert.commandWorked(db.setLogLevel(logLevel, "queryStats"));
+
+ // Insert a document and run two find command with different shapes so that we have two entries
+ // in the queryStats store.
+ assert.commandWorked(coll.insert({foo: 1, bar: "hello"}));
+ assert.eq(coll.find({foo: 1}).itcount(), 1);
+ assert.eq(coll.find({bar: "hello"}).itcount(), 1);
+
+ // Run $queryStats with the specified pipeline.
+ let result = conn.adminCommand({aggregate: 1, pipeline: [pipeline], cursor: {}});
+ assert.commandWorked(result);
+
+ if (logLevel >= 1) {
+ // Checking that we log the invocation of $queryStats.
+ let spec = transformed
+ ? {"transformIdentifiers": {"algorithm": "hmac-sha-256", "hmacKey": "###"}}
+ : {};
+ assert(checkLog.checkContainsWithCountJson(
+ conn, 7808300, {"commandSpec": spec}, 1, null, true),
+ "failed to find log with id " + 7808300);
+ }
+
+ // We only log the output of $queryStats when invoked with transformation, and log level at
+ // least 3.
+ if (logLevel >= 3 && transformed) {
+ // Checking that we are logging both entries in the query stats store.
+ assert(checkLog.checkContainsWithCountJson(conn, 7808301, {}, 2, null, true),
+ "failed to find log with id " + 7808301);
+
+ // Checking that the output is what we expect.
+ const query = assert.commandWorked(db.adminCommand({getLog: "global"}));
+ assert(query.hasOwnProperty("log"), "no log field");
+ assert.eq(countMatching(query.log, function(v) {
+ const has = (s) => v.indexOf(s) !== -1;
+ return has("thisOutput") && has("key:") && has("queryShape") &&
+ (has("?number") || has("?string"));
+ }), 2);
+
+ // Checking that we log when we are done outputting the results of $queryStats.
+ assert(checkLog.checkContainsWithCountJson(conn, 7808302, {}, 1, null, true),
+ "failed to find log with id " + 7808302);
+ }
+
+ // At a log level of 0 we should not be seeing any of these logs.
+ if (logLevel == 0) {
+ assert(checkLog.checkContainsWithCountJson(conn, 7808300, {}, 0, null, true));
+ assert(checkLog.checkContainsWithCountJson(conn, 7808301, {}, 0, null, true));
+ assert(checkLog.checkContainsWithCountJson(conn, 7808302, {}, 0, null, true));
+ }
+
+ MongoRunner.stopMongod(conn);
+}
+
+// Testing logging with transformation.
+const hmacKey = "MjM0NTY3ODkxMDExMTIxMzE0MTUxNjE3MTgxOTIwMjE=";
+let pipeline = {
+ $queryStats: {transformIdentifiers: {algorithm: "hmac-sha-256", hmacKey: BinData(8, hmacKey)}}
+};
+runQueryStatsAndVerifyLogs({pipeline: pipeline, transformed: true, logLevel: 3});
+runQueryStatsAndVerifyLogs({pipeline: pipeline, transformed: true, logLevel: 1});
+runQueryStatsAndVerifyLogs({pipeline: pipeline, transformed: true, logLevel: 0});
+
+// Testing logging without transformation.
+pipeline = {
+ $queryStats: {}
+};
+runQueryStatsAndVerifyLogs({pipeline: pipeline, transformed: false, logLevel: 3});
+runQueryStatsAndVerifyLogs({pipeline: pipeline, transformed: false, logLevel: 1});
+runQueryStatsAndVerifyLogs({pipeline: pipeline, transformed: false, logLevel: 0});
+}());
diff --git a/jstests/noPassthrough/queryStats/query_stats_metrics_across_getMore_calls.js b/jstests/noPassthrough/queryStats/query_stats_metrics_across_getMore_calls.js
new file mode 100644
index 00000000000..1bfb1c36ae5
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_metrics_across_getMore_calls.js
@@ -0,0 +1,173 @@
+/**
+ * Test that the queryStats metrics are aggregated properly by distinct query shape over getMore
+ * calls, for agg commands.
+ * @tags: [requires_fcv_60]
+ */
+load("jstests/libs/query_stats_utils.js"); // For verifyMetrics and getQueryStatsAggCmd.
+
+(function() {
+"use strict";
+
+// Turn on the collecting of queryStats metrics.
+let options = {
+ setParameter: {internalQueryStatsRateLimit: -1},
+};
+
+const conn = MongoRunner.runMongod(options);
+const testDB = conn.getDB('test');
+var coll = testDB[jsTestName()];
+coll.drop();
+
+// Bulk insert documents to reduces roundtrips and make timeout on a slow machine less likely.
+const bulk = coll.initializeUnorderedBulkOp();
+const numDocs = 100;
+for (let i = 0; i < numDocs / 2; ++i) {
+ bulk.insert({foo: 0, bar: Math.floor(Math.random() * 3)});
+ bulk.insert({foo: 1, bar: Math.floor(Math.random() * -2)});
+}
+assert.commandWorked(bulk.execute());
+// Assert that two queries with identical structures are represented by the same key.
+{
+ // Note: toArray() is necessary for the batchSize-limited query to run to cursor exhaustion
+ // (when it writes to the queryStats store).
+ coll.aggregate([{$match: {foo: 1}}], {cursor: {batchSize: 2}}).toArray();
+ coll.aggregate([{$match: {foo: 0}}], {cursor: {batchSize: 2}}).toArray();
+
+ // This command will return all queryStats store entires.
+ const queryStatsResults = getQueryStatsAggCmd(testDB);
+ // Assert there is only one entry.
+ assert.eq(queryStatsResults.length, 1, queryStatsResults);
+ const queryStatsEntry = queryStatsResults[0];
+ assert.eq(queryStatsEntry.key.queryShape.cmdNs.db, "test");
+ assert.eq(queryStatsEntry.key.queryShape.cmdNs.coll, jsTestName());
+ assert.eq(queryStatsEntry.key.client.application.name, "MongoDB Shell");
+
+ // Assert we update execution count for identically shaped queries.
+ assert.eq(queryStatsEntry.metrics.execCount, 2);
+
+ // Assert queryStats values are accurate for the two above queries.
+ assert.eq(queryStatsEntry.metrics.docsReturned.sum, numDocs);
+ assert.eq(queryStatsEntry.metrics.docsReturned.min, numDocs / 2);
+ assert.eq(queryStatsEntry.metrics.docsReturned.max, numDocs / 2);
+
+ verifyMetrics(queryStatsResults);
+}
+
+const fooEqBatchSize = 5;
+const fooNeBatchSize = 3;
+// Assert on batchSize-limited queries that killCursors will write metrics with partial results to
+// the queryStats store.
+{
+ let cursor1 = coll.find({foo: {$eq: 0}}).batchSize(fooEqBatchSize);
+ let cursor2 = coll.find({foo: {$ne: 0}}).batchSize(fooNeBatchSize);
+ // Issue one getMore for the first query, so 2 * fooEqBatchSize documents are returned total.
+ assert.commandWorked(testDB.runCommand(
+ {getMore: cursor1.getId(), collection: coll.getName(), batchSize: fooEqBatchSize}));
+
+ // Kill both cursors so the queryStats metrics are stored.
+ assert.commandWorked(testDB.runCommand(
+ {killCursors: coll.getName(), cursors: [cursor1.getId(), cursor2.getId()]}));
+
+ // This filters queryStats entires to just the ones entered when running above find queries.
+ const queryStatsResults = testDB.getSiblingDB("admin")
+ .aggregate([
+ {$queryStats: {}},
+ {$match: {"key.queryShape.filter.foo": {$exists: true}}},
+ {$sort: {key: 1}},
+ ])
+ .toArray();
+ assert.eq(queryStatsResults.length, 2, queryStatsResults);
+ assert.eq(queryStatsResults[0].key.queryShape.cmdNs.db, "test");
+ assert.eq(queryStatsResults[0].key.queryShape.cmdNs.coll, jsTestName());
+ assert.eq(queryStatsResults[0].key.client.application.name, "MongoDB Shell");
+ assert.eq(queryStatsResults[1].key.queryShape.cmdNs.db, "test");
+ assert.eq(queryStatsResults[1].key.queryShape.cmdNs.coll, jsTestName());
+ assert.eq(queryStatsResults[1].key.client.application.name, "MongoDB Shell");
+
+ assert.eq(queryStatsResults[0].metrics.execCount, 1);
+ assert.eq(queryStatsResults[1].metrics.execCount, 1);
+ assert.eq(queryStatsResults[0].metrics.docsReturned.sum, fooEqBatchSize * 2);
+ assert.eq(queryStatsResults[1].metrics.docsReturned.sum, fooNeBatchSize);
+
+ verifyMetrics(queryStatsResults);
+
+ const distributionFields = ['sum', 'max', 'min', 'sumOfSquares'];
+ for (const field of distributionFields) {
+ // If there are getMore calls, queryExecMicros should be greater than or equal to
+ // firstResponseExecMicros.
+ assert(bsonWoCompare(queryStatsResults[0].metrics.totalExecMicros[field],
+ queryStatsResults[0].metrics.firstResponseExecMicros[field]) > 0);
+
+ // If there is no getMore calls, firstResponseExecMicros and queryExecMicros should be
+ // equal.
+ assert.eq(queryStatsResults[1].metrics.totalExecMicros[field],
+ queryStatsResults[1].metrics.firstResponseExecMicros[field]);
+ }
+}
+
+// Assert that options such as limit/sort create different keys, and that repeating a query shape
+// ({foo: {$eq}}) aggregates metrics across executions.
+{
+ const query2Limit = 50;
+ coll.find({foo: {$eq: 0}}).batchSize(2).toArray();
+ coll.find({foo: {$eq: 1}}).limit(query2Limit).batchSize(2).toArray();
+ coll.find().sort({"foo": 1}).batchSize(2).toArray();
+ // This filters queryStats entires to just the ones entered when running above find queries.
+ let queryStatsResults =
+ testDB.getSiblingDB("admin")
+ .aggregate([{$queryStats: {}}, {$match: {"key.queryShape.command": "find"}}])
+ .toArray();
+ assert.eq(queryStatsResults.length, 4, queryStatsResults);
+
+ verifyMetrics(queryStatsResults);
+
+ // This filters to just the queryStats for query coll.find().sort({"foo": 1}).batchSize(2).
+ queryStatsResults =
+ testDB.getSiblingDB("admin")
+ .aggregate([{$queryStats: {}}, {$match: {"key.queryShape.sort.foo": 1}}])
+ .toArray();
+ assert.eq(queryStatsResults.length, 1, queryStatsResults);
+ assert.eq(queryStatsResults[0].key.queryShape.cmdNs.db, "test");
+ assert.eq(queryStatsResults[0].key.queryShape.cmdNs.coll, jsTestName());
+ assert.eq(queryStatsResults[0].key.client.application.name, "MongoDB Shell");
+ assert.eq(queryStatsResults[0].metrics.execCount, 1);
+ assert.eq(queryStatsResults[0].metrics.docsReturned.sum, numDocs);
+
+ // This filters to just the queryStats for query coll.find({foo: {$eq:
+ // 1}}).limit(query2Limit).batchSize(2).
+ queryStatsResults =
+ testDB.getSiblingDB("admin")
+ .aggregate([{$queryStats: {}}, {$match: {"key.queryShape.limit": '?number'}}])
+ .toArray();
+ assert.eq(queryStatsResults.length, 1, queryStatsResults);
+ assert.eq(queryStatsResults[0].key.queryShape.cmdNs.db, "test");
+ assert.eq(queryStatsResults[0].key.queryShape.cmdNs.coll, jsTestName());
+ assert.eq(queryStatsResults[0].key.client.application.name, "MongoDB Shell");
+ assert.eq(queryStatsResults[0].metrics.execCount, 1);
+ assert.eq(queryStatsResults[0].metrics.docsReturned.sum, query2Limit);
+
+ // This filters to just the queryStats for query coll.find({foo: {$eq: 0}}).batchSize(2).
+ queryStatsResults = testDB.getSiblingDB("admin")
+ .aggregate([
+ {$queryStats: {}},
+ {
+ $match: {
+ "key.queryShape.filter.foo": {$eq: {$eq: "?number"}},
+ "key.queryShape.limit": {$exists: false},
+ "key.queryShape.sort": {$exists: false}
+ }
+ }
+ ])
+ .toArray();
+ assert.eq(queryStatsResults.length, 1, queryStatsResults);
+ assert.eq(queryStatsResults[0].key.queryShape.cmdNs.db, "test");
+ assert.eq(queryStatsResults[0].key.queryShape.cmdNs.coll, jsTestName());
+ assert.eq(queryStatsResults[0].key.client.application.name, "MongoDB Shell");
+ assert.eq(queryStatsResults[0].metrics.execCount, 2);
+ assert.eq(queryStatsResults[0].metrics.docsReturned.sum, numDocs / 2 + 2 * fooEqBatchSize);
+ assert.eq(queryStatsResults[0].metrics.docsReturned.max, numDocs / 2);
+ assert.eq(queryStatsResults[0].metrics.docsReturned.min, 2 * fooEqBatchSize);
+}
+
+MongoRunner.stopMongod(conn);
+}());
diff --git a/jstests/noPassthrough/queryStats/query_stats_regex.js b/jstests/noPassthrough/queryStats/query_stats_regex.js
new file mode 100644
index 00000000000..8b9553e267f
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_regex.js
@@ -0,0 +1,43 @@
+/**
+ * Test that queryStats works properly for a find command that uses regex.
+ * @tags: [requires_fcv_60]
+ */
+(function() {
+"use strict";
+
+load("jstests/libs/query_stats_utils.js"); // For getLatestQueryStatsEntry.
+
+// Turn on the collecting of queryStats metrics.
+let options = {
+ setParameter: {internalQueryStatsRateLimit: -1},
+};
+
+const conn = MongoRunner.runMongod(options);
+const testDB = conn.getDB('test');
+var coll = testDB[jsTestName()];
+coll.drop();
+
+const bulk = coll.initializeUnorderedBulkOp();
+const numDocs = 100;
+for (let i = 0; i < numDocs / 2; ++i) {
+ bulk.insert({foo: "ABCDE"});
+ bulk.insert({foo: "CDEFG"});
+}
+assert.commandWorked(bulk.execute());
+
+{
+ coll.find({foo: {$regex: "/^ABC/i"}}).itcount();
+ const queryStats = getLatestQueryStatsEntry(testDB);
+ assert.eq({"foo": {"$regex": "?string"}}, queryStats.key.queryShape.filter, queryStats);
+}
+
+{
+ coll.find({foo: {$regex: ".*", $options: "m"}}).itcount();
+ const queryStats = getLatestQueryStatsEntry(testDB);
+ assert.eq({"foo": {"$regex": "?string", "$options": "?string"}},
+ queryStats.key.queryShape.filter,
+ queryStats);
+}
+
+MongoRunner.stopMongod(conn);
+}());
diff --git a/jstests/noPassthrough/queryStats/query_stats_sampling_rate.js b/jstests/noPassthrough/queryStats/query_stats_sampling_rate.js
new file mode 100644
index 00000000000..b25fb3318d9
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_sampling_rate.js
@@ -0,0 +1,37 @@
+/**
+ * Test that calls to read from query stats store fail when sampling rate is not greater than 0 even
+ * if feature flag is on.
+ * @tags: [requires_fcv_60]
+ */
+load('jstests/libs/analyze_plan.js');
+load("jstests/libs/query_stats_utils.js");
+
+(function() {
+"use strict";
+
+let options = {
+ setParameter: {internalQueryStatsRateLimit: 0},
+};
+
+const conn = MongoRunner.runMongod(options);
+const testdb = conn.getDB('test');
+var coll = testdb[jsTestName()];
+coll.drop();
+for (var i = 0; i < 20; i++) {
+ coll.insert({foo: 0, bar: Math.floor(Math.random() * 3)});
+}
+
+coll.find({foo: 1}).batchSize(2).toArray();
+
+// Reading query stats store with a sampling rate of 0 should return 0 documents.
+let stats = getQueryStats(testdb);
+assert.eq(stats.length, 0);
+
+// Reading query stats store should work now with a sampling rate of greater than 0.
+assert.commandWorked(testdb.adminCommand({setParameter: 1, internalQueryStatsRateLimit: -1}));
+coll.find({foo: 1}).batchSize(2).toArray();
+stats = getQueryStats(testdb);
+assert.eq(stats.length, 1);
+
+MongoRunner.stopMongod(conn);
+}());
diff --git a/jstests/noPassthrough/queryStats/query_stats_server_status_metrics.js b/jstests/noPassthrough/queryStats/query_stats_server_status_metrics.js
new file mode 100644
index 00000000000..ee6498b45cc
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_server_status_metrics.js
@@ -0,0 +1,272 @@
+/**
+ * Test the queryStats related serverStatus metrics.
+ * @tags: [requires_fcv_60]
+ */
+(function() {
+"use strict";
+
+function runTestWithMongodOptions(mongodOptions, test, testOptions) {
+ const conn = MongoRunner.runMongod(mongodOptions);
+ const testDB = conn.getDB('test');
+ const coll = testDB[jsTestName()];
+
+ test(conn, testDB, coll, testOptions);
+
+ MongoRunner.stopMongod(conn);
+}
+
+// Helper to round up to the next highest power of 2 for our estimation.
+function align(number) {
+ return Math.pow(2, Math.ceil(Math.log2(number)));
+}
+
+function addApprox2MBOfStatsData(testDB, coll) {
+ const k2MB = 2 * 1024 * 1024;
+
+ const cmdObjTemplate = {
+ find: coll.getName(),
+ filter: {foo123: {$eq: "?"}},
+ };
+
+ const kEstimatedEntrySizeBytes = (() => {
+ // Metrics stored per shape.
+ const kNumCountersAndDates =
+ 4 /* top-level */ + (4 * 3) /* those with sum, min, max, sumOfSquares */;
+
+ // Just a sample, will change based on where the test is run - shouldn't be off by too much
+ // though.
+ const kClientMetadataEst = {
+ client: {application: {name: "MongoDB Shell"}},
+ driver: {name: "MongoDB Internal Client", version: "7.1.0-alpha"},
+ os: {type: "Linux", name: "Ubuntu", architecture: "aarch64", version: "22.04"}
+ };
+
+ const kCmdNsObj = {cmdNs: {db: testDB.getName(), coll: coll.getName()}};
+
+ // Rough estimate of space needed for just the query stats 'Key' class members assuming
+ // everything is 8 bytes.
+ const kCxxOverhead = 96;
+
+ // This is likely not to be exact - we are probably forgetting something. But we don't need
+ // to be exact, just "good enough."
+ return align(kNumCountersAndDates * 4 + Object.bsonsize(cmdObjTemplate) +
+ Object.bsonsize(kClientMetadataEst) + Object.bsonsize(kCmdNsObj) +
+ kCxxOverhead);
+ })();
+ const nIterations = k2MB / kEstimatedEntrySizeBytes;
+ for (let i = 0; i <= nIterations; i++) {
+ let newQuery = {["foo" + i]: "bar"};
+ const cmdObj = cmdObjTemplate;
+ cmdObj.filter = newQuery;
+ const cmdRes = assert.commandWorked(testDB.runCommand(cmdObj));
+ new DBCommandCursor(testDB, cmdRes).itcount();
+ }
+}
+/**
+ * Test serverStatus metric which counts the number of evicted entries.
+ *
+ * testOptions must include `resetCacheSize` bool field; e.g., { resetCacheSize : true }
+ */
+function evictionTest(conn, testDB, coll, testOptions) {
+ const evictedBefore = testDB.serverStatus().metrics.queryStats.numEvicted;
+ assert.eq(evictedBefore, 0);
+ addApprox2MBOfStatsData(testDB, coll);
+ if (!testOptions.resetCacheSize) {
+ const evictedAfter = testDB.serverStatus().metrics.queryStats.numEvicted;
+ assert.gt(evictedAfter, 0, testDB.serverStatus().metrics.queryStats);
+ return;
+ }
+ // Make sure number of evicted entries increases when the cache size is reset, which forces out
+ // least recently used entries to meet the new, smaller size requirement.
+ assert.eq(testDB.serverStatus().metrics.queryStats.numEvicted, 0);
+ assert.commandWorked(
+ testDB.adminCommand({setParameter: 1, internalQueryStatsCacheSize: "1MB"}));
+ const evictedAfter = testDB.serverStatus().metrics.queryStats.numEvicted;
+ assert.gt(evictedAfter, 0);
+}
+
+/**
+ * Test serverStatus metric which counts the number of requests for which queryStats is not
+ * collected due to rate-limiting.
+ *
+ * testOptions must include `samplingRate` and `numRequests` number fields;
+ * e.g., { samplingRate: -1, numRequests: 20 }
+ */
+function countRateLimitedRequestsTest(conn, testDB, coll, testOptions) {
+ const numRateLimitedRequestsBefore =
+ testDB.serverStatus().metrics.queryStats.numRateLimitedRequests;
+ assert.eq(numRateLimitedRequestsBefore, 0);
+
+ coll.insert({a: 0});
+
+ // Running numRequests / 2 times since we dispatch two requests per iteration
+ for (var i = 0; i < testOptions.numRequests / 2; i++) {
+ coll.find({a: 0}).toArray();
+ coll.aggregate([{$match: {a: 1}}]);
+ }
+
+ const numRateLimitedRequestsAfter =
+ testDB.serverStatus().metrics.queryStats.numRateLimitedRequests;
+
+ if (testOptions.samplingRate === 0) {
+ // queryStats should not be collected for any requests.
+ assert.eq(numRateLimitedRequestsAfter, testOptions.numRequests);
+ } else if (testOptions.samplingRate >= testOptions.numRequests) {
+ // queryStats should be collected for all requests.
+ assert.eq(numRateLimitedRequestsAfter, 0);
+ } else {
+ // queryStats should be collected for some but not all requests.
+ assert.gt(numRateLimitedRequestsAfter, 0);
+ assert.lt(numRateLimitedRequestsAfter, testOptions.numRequests);
+ }
+}
+
+function queryStatsStoreSizeEstimateTest(conn, testDB, coll, testOptions) {
+ assert.eq(testDB.serverStatus().metrics.queryStats.queryStatsStoreSizeEstimateBytes, 0);
+ let halfWayPointSize;
+ // Only using three digit numbers (eg 100, 101) means the string length will be the same for all
+ // entries and therefore the key size will be the same for all entries, which makes predicting
+ // the total size of the store clean and easy.
+ for (var i = 100; i < 200; i++) {
+ coll.aggregate([{$match: {["foo" + i]: "bar"}}]).itcount();
+ if (i == 150) {
+ halfWayPointSize =
+ testDB.serverStatus().metrics.queryStats.queryStatsStoreSizeEstimateBytes;
+ }
+ }
+ // Confirm that queryStats store has grown and size is non-zero.
+ assert.gt(halfWayPointSize, 0);
+ const fullSize = testDB.serverStatus().metrics.queryStats.queryStatsStoreSizeEstimateBytes;
+ assert.gt(fullSize, 0);
+ // Make sure the final queryStats store size is twice as much as the halfway point size (+/- 5%)
+ assert(fullSize >= halfWayPointSize * 1.95 && fullSize <= halfWayPointSize * 2.05,
+ tojson({fullSize, halfWayPointSize}));
+}
+
+function queryStatsStoreWriteErrorsTest(conn, testDB, coll, testOptions) {
+ const debugBuild = testDB.adminCommand('buildInfo').debug;
+ if (debugBuild) {
+ jsTestLog("Skipping queryStats store write errors test because debug build will tassert.");
+ return;
+ }
+
+ const errorsBefore = testDB.serverStatus().metrics.queryStats.numQueryStatsStoreWriteErrors;
+ assert.eq(errorsBefore, 0);
+ for (let i = 0; i < 5; i++) {
+ // Command should succeed and record the error.
+ let query = {};
+ query["foo" + i] = "bar";
+ coll.aggregate([{$match: query}]).itcount();
+ }
+
+ // Make sure that we recorded a write error for each run.
+ assert.eq(testDB.serverStatus().metrics.queryStats.numQueryStatsStoreWriteErrors, 5);
+}
+
+/**
+ * Test that running the $queryStats aggregation stage correctly does or does not impact
+ * serverStatus counters (whichever is applicable).
+ */
+function queryStatsAggregationStageTest(conn, testDB, coll) {
+ // First, ensure that the query stats store is empty.
+ assert.eq(testDB.serverStatus().metrics.queryStats.queryStatsStoreSizeEstimateBytes, 0);
+ assert.eq(testDB.serverStatus().metrics.queryStats.numEvicted, 0);
+
+ // Insert some query stats data and capture "before" serverStatus metrics.
+ for (let i = 100; i < 200; i++) {
+ coll.aggregate([{$match: {["foo" + i]: "bar"}}]).itcount();
+ }
+
+ let sizeBefore = testDB.serverStatus().metrics.queryStats.queryStatsStoreSizeEstimateBytes;
+ const evictedBefore = testDB.serverStatus().metrics.queryStats.numEvicted;
+
+ // Run a $queryStats pipeline. We should insert a new entry for this query.
+ assert.commandWorked(
+ testDB.adminCommand({aggregate: 1, pipeline: [{$queryStats: {}}], cursor: {}}));
+
+ assert.eq(testDB.serverStatus().metrics.queryStats.numEvicted,
+ evictedBefore,
+ "$queryStats should not have triggered evictions");
+ assert.gt(testDB.serverStatus().metrics.queryStats.queryStatsStoreSizeEstimateBytes,
+ sizeBefore,
+ "$queryStats pipeline should have been added to the query stats store");
+ sizeBefore = testDB.serverStatus().metrics.queryStats.queryStatsStoreSizeEstimateBytes;
+
+ // Now run $queryStats again. The command should be fully read-only.
+ assert.commandWorked(
+ testDB.adminCommand({aggregate: 1, pipeline: [{$queryStats: {}}], cursor: {}}));
+
+ assert.eq(testDB.serverStatus().metrics.queryStats.numEvicted,
+ evictedBefore,
+ "$queryStats should not have triggered evictions");
+ assert.eq(testDB.serverStatus().metrics.queryStats.queryStatsStoreSizeEstimateBytes,
+ sizeBefore,
+ "$queryStats pipeline should not have impacted query stats store size");
+}
+
+/**
+ * In this configuration, we insert enough entries into the queryStats store to trigger LRU
+ * eviction.
+ */
+runTestWithMongodOptions({
+ setParameter: {internalQueryStatsCacheSize: "1MB", internalQueryStatsRateLimit: -1},
+},
+ evictionTest,
+ {resetCacheSize: false});
+/**
+ * In this configuration, eviction is triggered only when the queryStats store size is reset.
+ *
+ * Use an 8MB upper limit since our estimated size of the query stats entry is pretty rough and
+ * meant to give us some wiggle room so we don't have to keep adjusting this test as we tweak it.
+ */
+runTestWithMongodOptions({
+ setParameter: {internalQueryStatsCacheSize: "8MB", internalQueryStatsRateLimit: -1},
+},
+ evictionTest,
+ {resetCacheSize: true});
+
+/**
+ * In this configuration, every query is sampled, so no requests should be rate-limited.
+ */
+runTestWithMongodOptions({
+ setParameter: {internalQueryStatsRateLimit: -1},
+},
+ countRateLimitedRequestsTest,
+ {samplingRate: 2147483647, numRequests: 20});
+
+/**
+ * In this configuration, the sampling rate is set so that some but not all requests are
+ * rate-limited.
+ */
+runTestWithMongodOptions({
+ setParameter: {internalQueryStatsRateLimit: 10},
+},
+ countRateLimitedRequestsTest,
+ {samplingRate: 10, numRequests: 20});
+
+/**
+ * Sample all queries and assert that the size of queryStats store is equal to num entries * entry
+ * size
+ */
+runTestWithMongodOptions({
+ setParameter: {internalQueryStatsRateLimit: -1},
+},
+ queryStatsStoreSizeEstimateTest);
+
+/**
+ * Use a very small queryStats store size and assert that errors in writing to the queryStats store
+ * are tracked.
+ */
+runTestWithMongodOptions({
+ setParameter: {internalQueryStatsCacheSize: "0.00001MB", internalQueryStatsRateLimit: -1},
+},
+ queryStatsStoreWriteErrorsTest);
+
+/**
+ * Tests that $queryStats has expected effects (or no effect) on counters.
+ */
+runTestWithMongodOptions({
+ setParameter: {internalQueryStatsCacheSize: "2MB", internalQueryStatsRateLimit: -1},
+},
+ queryStatsAggregationStageTest);
+}());
diff --git a/jstests/noPassthrough/queryStats/query_stats_sub_pipelines.js b/jstests/noPassthrough/queryStats/query_stats_sub_pipelines.js
new file mode 100644
index 00000000000..7e74d66f20c
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_sub_pipelines.js
@@ -0,0 +1,184 @@
+/**
+ * Test that shapification for queries with sub-pipelines happens before view resolution and
+ * pipeline optimization.
+ * @tags: [requires_fcv_60]
+ */
+load("jstests/libs/query_stats_utils.js"); // For getLatestQueryStatsEntry
+
+const conn = MongoRunner.runMongod({
+ setParameter: {
+ internalQueryStatsRateLimit: -1,
+ }
+});
+
+const dbName = jsTestName();
+const db = conn.getDB(dbName);
+
+const collName = "base";
+const coll = db[collName];
+coll.drop();
+assert.commandWorked(coll.insert({x: 10, y: 20}));
+
+const viewName = "projection_view";
+assert.commandWorked(
+ db.runCommand({create: viewName, viewOn: collName, pipeline: [{$project: {_id: 1, x: 1}}]}));
+const view = db[viewName];
+
+// Tests a basic query on a view as a sanity check.
+(function testViewQuery() {
+ view.aggregate([{$sort: {x: 1}}]).toArray();
+
+ const stats = getLatestQueryStatsEntry(db);
+ const key = stats.key;
+
+ // The view should not be resolved in the key.
+ assert.eq({"db": `${dbName}`, "coll": `${viewName}`}, key.queryShape.cmdNs, tojson(key));
+ assert.eq(
+ [
+ {"$sort": {"x": 1}},
+ ],
+ key.queryShape.pipeline,
+ tojson(key));
+})();
+
+// Tests a query where a view reference is in a $lookup pipeline.
+(function testViewInLookupPipeline() {
+ coll.aggregate([{$lookup: {from: viewName, pipeline: [{$match: {x: 10}}], as: "lookup"}}])
+ .toArray();
+
+ const stats = getLatestQueryStatsEntry(db);
+ const key = stats.key;
+
+ // The view should not be resolved in the key.
+ assert.eq({"db": `${dbName}`, "coll": `${collName}`}, key.queryShape.cmdNs, tojson(key));
+ assert.eq(
+ [
+ {$lookup:
+ {
+ from: viewName,
+ as: "lookup",
+ let: {},
+ pipeline: [{$match: {x: {$eq: "?number"}}}],
+ }
+ }
+ ],
+ key.queryShape.pipeline, tojson(key));
+})();
+
+// Tests that the $lookup x $match optimization is applied after shapification.
+(function testLookupMatchOptimization() {
+ coll.aggregate([
+ {$lookup: {from: viewName, pipeline: [{$match: {x: {$gt: 5}}}], as: "lookup"}},
+ {$unwind: {path: "$lookup"}},
+ {$match: {"lookup.x": 10}}
+ ])
+ .toArray();
+
+ const stats = getLatestQueryStatsEntry(db);
+ const key = stats.key;
+
+ // The view should not be resolved in the key.
+ assert.eq({"db": `${dbName}`, "coll": `${collName}`}, key.queryShape.cmdNs, tojson(key));
+ assert.eq(
+ [
+ {$lookup:
+ {
+ from: viewName,
+ as: "lookup",
+ let: {},
+ pipeline: [{$match: {x: {$gt: "?number"}}}],
+ }
+ },
+ {$unwind: {
+ path: "$lookup"
+ }},
+ {$match: {
+ "lookup.x": {
+ $eq: "?number"
+ }
+ }}
+ ],
+ key.queryShape.pipeline, tojson(key));
+})();
+
+// Tests that the $lookup x $unwind optimization is applied after shapification.
+(function testLookupUnwindOptimization() {
+ coll.aggregate([
+ {$lookup: {from: viewName, pipeline: [{$match: {x: 10}}], as: "lookup"}},
+ {$unwind: {path: "$lookup"}}
+ ])
+ .toArray();
+
+ const stats = getLatestQueryStatsEntry(db);
+ const key = stats.key;
+
+ // The view should not be resolved in the key.
+ assert.eq({"db": `${dbName}`, "coll": `${collName}`}, key.queryShape.cmdNs, tojson(key));
+ assert.eq(
+ [
+ {$lookup:
+ {
+ from: viewName,
+ as: "lookup",
+ let: {},
+ pipeline: [{$match: {x: {$eq: "?number"}}}],
+ }
+ },
+ {$unwind: {
+ path: "$lookup"
+ }}
+ ],
+ key.queryShape.pipeline, tojson(key));
+})();
+
+// Tests a query where a view reference is in a $graphLookup pipeline.
+(function testViewInGraphLookupPipeline() {
+ coll.aggregate([{$graphLookup: {from: viewName, startWith: "$x", connectFromField: "x", connectToField: "x", as: "lookup"}}]).toArray();
+
+ const stats = getLatestQueryStatsEntry(db);
+ const key = stats.key;
+
+ // The view should not be resolved in the key.
+ assert.eq({"db": `${dbName}`, "coll": `${collName}`}, key.queryShape.cmdNs, tojson(key));
+ assert.eq(
+ [
+ {$graphLookup:
+ {
+ from: viewName,
+ as: "lookup",
+ connectToField: "x",
+ connectFromField: "x",
+ startWith: "$x"
+ }
+ }
+ ],
+ key.queryShape.pipeline, tojson(key));
+})();
+
+// Tests a query where a view reference is in a $unionWith.
+(function testViewInUnionWith() {
+ coll.aggregate([{$unionWith: viewName}]).toArray();
+
+ const stats = getLatestQueryStatsEntry(db);
+ const key = stats.key;
+
+ // The view should not be resolved in the key.
+ assert.eq({"db": `${dbName}`, "coll": `${collName}`}, key.queryShape.cmdNs, tojson(key));
+ assert.eq([{$unionWith: {coll: viewName, pipeline: []}}], key.queryShape.pipeline, tojson(key));
+})();
+
+// Tests a query where a view reference is in a $unionWith with a sub-pipeline.
+(function testViewInUnionWithPipeline() {
+ coll.aggregate([{$unionWith: {coll: viewName, pipeline: [{$sort: {x: 1}}]}}]).toArray();
+
+ const stats = getLatestQueryStatsEntry(db);
+ const key = stats.key;
+
+ // The view should not be resolved in the key.
+ assert.eq({"db": `${dbName}`, "coll": `${collName}`}, key.queryShape.cmdNs, tojson(key));
+ assert.eq([{$unionWith: {coll: viewName, pipeline: [{$sort: {x: 1}}]}}],
+ key.queryShape.pipeline,
+ tojson(key));
+})();
+
+MongoRunner.stopMongod(conn);
diff --git a/jstests/noPassthrough/queryStats/query_stats_upgrade.js b/jstests/noPassthrough/queryStats/query_stats_upgrade.js
new file mode 100644
index 00000000000..de23b157e99
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/query_stats_upgrade.js
@@ -0,0 +1,45 @@
+/**
+ * Test that query stats doesn't work on a lower FCV version but works after an FCV upgrade.
+ * @tags: [
+ * requires_fcv_60,
+ * # Re-uses FCV state in the dbpath.
+ * requires_persistence
+ * ]
+ */
+load('jstests/libs/analyze_plan.js');
+load("jstests/libs/feature_flag_util.js");
+
+(function() {
+"use strict";
+
+const dbpath = MongoRunner.dataPath + jsTestName();
+let conn = MongoRunner.runMongod({dbpath: dbpath});
+let testDB = conn.getDB(jsTestName());
+
+function testLower(restart = false) {
+ let adminDB = conn.getDB("admin");
+ assert.commandWorked(
+ adminDB.runCommand({setFeatureCompatibilityVersion: binVersionToFCV("last-lts")}));
+ if (restart) {
+ MongoRunner.stopMongod(conn);
+ conn = MongoRunner.runMongod({dbpath: dbpath, noCleanData: true});
+ testDB = conn.getDB(jsTestName());
+ adminDB = conn.getDB("admin");
+ }
+
+ assert.commandFailedWithCode(
+ testDB.adminCommand({aggregate: 1, pipeline: [{$queryStats: {}}], cursor: {}}),
+ ErrorCodes.QueryFeatureNotAllowed);
+
+ // Upgrade FCV.
+ assert.commandWorked(
+ adminDB.runCommand({setFeatureCompatibilityVersion: binVersionToFCV("latest")}));
+
+ // We should be able to run a query stats pipeline now that the FCV is correct.
+ assert.commandWorked(
+ testDB.adminCommand({aggregate: 1, pipeline: [{$queryStats: {}}], cursor: {}}));
+}
+testLower(true);
+testLower(false);
+MongoRunner.stopMongod(conn);
+})(); \ No newline at end of file
diff --git a/jstests/noPassthrough/queryStats/redact_queries_with_nonobject_fields.js b/jstests/noPassthrough/queryStats/redact_queries_with_nonobject_fields.js
new file mode 100644
index 00000000000..7bc0737f699
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/redact_queries_with_nonobject_fields.js
@@ -0,0 +1,76 @@
+/**
+ * Test that query stats key generation works for queries with non-object fields.
+ * @tags: [requires_fcv_60]
+ */
+load('jstests/libs/analyze_plan.js');
+
+(function() {
+"use strict";
+
+// Turn on the collecting of query stats metrics.
+let options = {
+ setParameter: {internalQueryStatsRateLimit: -1},
+};
+
+const conn = MongoRunner.runMongod(options);
+const testDB = conn.getDB('test');
+var collA = testDB[jsTestName()];
+var collB = testDB[jsTestName() + 'Two'];
+collA.drop();
+collB.drop();
+
+for (var i = 0; i < 200; i++) {
+ collA.insert({foo: 0, bar: Math.floor(Math.random() * 3)});
+ collA.insert({foo: 1, bar: Math.floor(Math.random() * -2)});
+ collB.insert({foo: Math.floor(Math.random() * 2), bar: Math.floor(Math.random() * 2)});
+}
+
+function confirmAggSuccess(collName, pipeline) {
+ const command = {aggregate: collName, cursor: {}};
+ command.pipeline = pipeline;
+ assert.commandWorked(testDB.runCommand(command));
+}
+// Test with non-object fields $limit and $skip.
+confirmAggSuccess(collA.getName(), [{$sort: {bar: -1}}, {$limit: 2}, {$match: {foo: {$lte: 2}}}]);
+confirmAggSuccess(collA.getName(), [{$sort: {bar: -1}}, {$skip: 50}, {$match: {foo: {$lte: 2}}}]);
+confirmAggSuccess(collA.getName(),
+ [{$sort: {bar: -1}}, {$limit: 2}, {$skip: 50}, {$match: {foo: 0}}]);
+
+// Test non-object field, $unionWith.
+confirmAggSuccess(collA.getName(), [{$unionWith: collB.getName()}]);
+
+// Test $limit in $setWindowFields for good measure.
+confirmAggSuccess(collA.getName(), [
+ {$_internalInhibitOptimization: {}},
+ {
+ $setWindowFields: {
+ sortBy: {foo: 1},
+ output: {sum: {$sum: "$bar", window: {documents: ["unbounded", "current"]}}}
+ }
+ },
+ {$sort: {foo: 1}},
+ {$limit: 5}
+]);
+// Test find commands containing non-object fields
+assert.commandWorked(testDB.runCommand({find: collA.getName(), limit: 20}));
+assert.commandWorked(testDB.runCommand({find: collA.getName(), skip: 199}));
+collA.find().skip(100);
+
+// findOne has a nonobject field, $limit.
+collB.findOne();
+collB.findOne({foo: 1});
+
+// Test non-object field $unwind
+confirmAggSuccess(
+ collA.getName(), [{
+ "$facet": {
+ "productOfJoin": [
+ {"$lookup": {"from": collB.getName(), "pipeline": [{"$match": {}}], "as": "join"}},
+ {"$unwind": "$join"},
+ {"$project": {"str": 1}}
+ ]
+ }
+ }]);
+
+MongoRunner.stopMongod(conn);
+}());
diff --git a/jstests/noPassthrough/queryStats/redact_sensitive_fields_in_log.js b/jstests/noPassthrough/queryStats/redact_sensitive_fields_in_log.js
new file mode 100644
index 00000000000..498603ba5da
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/redact_sensitive_fields_in_log.js
@@ -0,0 +1,60 @@
+/**
+ * Test that the queryStats HMAC key is not logged.
+ * @tags: [requires_fcv_60]
+ */
+
+(function() {
+'use strict';
+
+load('jstests/libs/query_stats_utils.js'); // For getQueryStatsFindCmd
+
+const checkLogForHmacKey = function(conn) {
+ const coll = conn.getCollection("test.foo");
+ assert.commandWorked(coll.insert({_id: 1}));
+ assert.neq(coll.findOne({_id: 1}), null);
+
+ assert.neq(getQueryStatsFindCmd(conn, {
+ transformIdentifiers: true,
+ hmacKey: BinData(8, "YW4gYXJiaXRyYXJ5IEhNQUNrZXkgZm9yIHRlc3Rpbmc=")
+ }),
+ null);
+
+ print(`Checking ${conn.fullOptions.logFile} for query stats message`);
+ const log = cat(conn.fullOptions.logFile);
+
+ // Make sure there is no unredacted HMAC key
+ const predicate = /"hmacKey":"[^#"]+"/;
+ assert(!predicate.test(log),
+ "Found an unredacted HMAC key in log file!\n" +
+ "Log file contents: " + conn.fullOptions.logFile +
+ "\n************************************************************\n" + log +
+ "\n************************************************************");
+};
+
+// Test MongoD
+const testMongoD = function() {
+ const conn =
+ MongoRunner.runMongod({setParameter: {internalQueryStatsRateLimit: -1}, useLogFiles: true});
+ assert.neq(null, conn, 'mongod was unable to start up');
+
+ checkLogForHmacKey(conn);
+
+ MongoRunner.stopMongod(conn);
+};
+
+// Test MongoS
+const testMongoS = function() {
+ const options = {
+ mongosOptions: {setParameter: {internalQueryStatsRateLimit: -1}, useLogFiles: true},
+ };
+
+ const st = new ShardingTest({shards: 1, mongos: 1, other: options});
+
+ checkLogForHmacKey(st.s0);
+
+ st.stop();
+};
+
+testMongoD();
+testMongoS();
+})();
diff --git a/jstests/noPassthrough/queryStats/redact_sensitive_fields_in_profile.js b/jstests/noPassthrough/queryStats/redact_sensitive_fields_in_profile.js
new file mode 100644
index 00000000000..1b37a0ad94a
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/redact_sensitive_fields_in_profile.js
@@ -0,0 +1,63 @@
+/**
+ * Test that the queryStats HMAC key is not leaked during profiling.
+ * @tags: [requires_fcv_60]
+ */
+(function() {
+"use strict";
+
+load("jstests/libs/profiler.js"); // For getLatestProfilerEntry.
+load("jstests/libs/query_stats_utils.js"); // For getQueryStatsFindCmd
+
+const conn = MongoRunner.runMongod({setParameter: {internalQueryStatsRateLimit: -1}, profile: 2});
+const adminDB = conn.getDB("admin");
+const testDB = conn.getDB("test");
+const coll = testDB[jsTestName()];
+
+// Prepopulate
+coll.drop();
+assert.commandWorked(coll.insert([{foo: 0}, {foo: 1}]));
+
+const nsProfilerFilter = {
+ ns: coll.getFullName()
+};
+
+// Run a few find commands
+for (const index of Array(10).keys()) {
+ if (index < 2) {
+ assert.neq(coll.findOne({foo: index}), null, `{foo: ${index}} should be extant`);
+ } else {
+ assert.isnull(coll.findOne({foo: index}), `{foo: ${index}} should be null`);
+ }
+}
+
+// This returns `null` when there are no entries, as opposed to erroring when getLatestProfilerEntry
+// encounters an empty profile.
+const getLastAdminEntry = () => {
+ const cursor =
+ adminDB.system.profile.find({ns: "admin.$cmd.aggregate"}).sort({$natural: -1}).limit(1);
+ return [...cursor.toArray(), null][0];
+};
+
+const lastTestEntry = getLatestProfilerEntry(testDB, nsProfilerFilter);
+const lastAdminEntry = getLastAdminEntry();
+const hmacKey = BinData(8, "YW4gYXJiaXRyYXJ5IEhNQUNrZXkgZm9yIHRlc3Rpbmc=");
+
+getQueryStatsFindCmd(conn, {transformIdentifiers: true, hmacKey: hmacKey});
+
+// Check that the queryStats command is not profiled.
+assert.eq(getLatestProfilerEntry(testDB, nsProfilerFilter), lastTestEntry);
+
+// Check that the queryStats command is profiled in the admin log either.
+const adminEntry = getLastAdminEntry();
+assert.neq(adminEntry, lastAdminEntry);
+
+// Check that the HMAC key is redacted.
+const loggedHmacKey = adminEntry.command.pipeline[0].$queryStats.transformIdentifiers.hmacKey;
+assert.neq(loggedHmacKey, hmacKey);
+
+// This is somewhat implementation dependent. If the redaction string ever changes, this will need
+// to be updated as well.
+assert.eq(loggedHmacKey, "###");
+
+MongoRunner.stopMongod(conn);
+}());
diff --git a/jstests/noPassthrough/queryStats/repl_set_query_stats_key.js b/jstests/noPassthrough/queryStats/repl_set_query_stats_key.js
new file mode 100644
index 00000000000..309e0b9ff75
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/repl_set_query_stats_key.js
@@ -0,0 +1,108 @@
+/**
+ * This test confirms that queryStats store key fields specific to replica sets (readConcern and
+ * readPreference) are included and correctly shapified. General command fields related to api
+ * versioning are included for good measure.
+ * @tags: [requires_fcv_60]
+ */
+load("jstests/libs/query_stats_utils.js"); // For getLatestQueryStatsEntry
+(function() {
+"use strict";
+
+const replTest = new ReplSetTest({
+ name: 'queryStatsTest',
+ nodes: [
+ {rsConfig: {tags: {dc: "east"}}},
+ {rsConfig: {tags: {dc: "west"}}},
+ ]
+});
+
+// Turn on the collecting of query stats metrics.
+replTest.startSet({setParameter: {internalQueryStatsRateLimit: -1}});
+replTest.initiate();
+
+const primary = replTest.getPrimary();
+
+const dbName = jsTestName();
+const collName = "foobar";
+const primaryDB = primary.getDB(dbName);
+const primaryColl = primaryDB.getCollection(collName);
+
+primaryColl.drop();
+
+const clusterTime =
+ assert.commandWorked(primaryDB.runCommand({insert: collName, documents: [{a: 1000}]}))
+ .operationTime;
+
+replTest.awaitReplication();
+
+function confirmCommandFieldsPresent(queryStatsKey, commandObj) {
+ for (const field in queryStatsKey) {
+ if (field == "queryShape" || field == "client" || field == "command") {
+ continue;
+ }
+ assert(commandObj.hasOwnProperty(field),
+ `${field} is present in the query stats key but not present in command obj: ${
+ tojson(queryStatsKey)}, ${tojson(commandObj)}`);
+ }
+ assert.eq(Object.keys(queryStatsKey).length, Object.keys(commandObj).length, queryStatsKey);
+}
+
+let commandObj = {
+ find: collName,
+ filter: {v: {$eq: 2}},
+ readConcern: {level: "local", afterClusterTime: new Timestamp(0, 1)},
+ $readPreference: {mode: "nearest", tags: [{some: "tag"}, {dc: "north pole"}, {dc: "east"}]},
+ apiDeprecationErrors: false,
+ apiVersion: "1",
+ apiStrict: false,
+};
+const replSetConn = new Mongo(replTest.getURL());
+assert.commandWorked(replSetConn.getDB(dbName).runCommand(commandObj));
+let stats = getLatestQueryStatsEntry(replSetConn, {collName: collName});
+delete stats.key["collectionType"];
+confirmCommandFieldsPresent(stats.key, commandObj);
+// Check that readConcern afterClusterTime is normalized.
+assert.eq(stats.key.readConcern.afterClusterTime, "?timestamp", tojson(stats.key.readConcern));
+
+// Check that $readPreference.tags are sorted.
+assert.eq(stats.key.$readPreference.tags,
+ [{dc: "east"}, {dc: "north pole"}, {some: "tag"}],
+ tojson(stats.key.$readPreference));
+
+// Check that readConcern just has an afterClusterTime field.
+commandObj["readConcern"] = {
+ afterClusterTime: new Timestamp(1, 0)
+};
+delete commandObj["$readPreference"];
+assert.commandWorked(replSetConn.getDB(dbName).runCommand(commandObj));
+stats = getLatestQueryStatsEntry(replSetConn, {collName});
+// We're not concerned with this field here.
+delete stats.key["collectionType"];
+confirmCommandFieldsPresent(stats.key, commandObj);
+assert.eq(stats.key["readConcern"], {"afterClusterTime": "?timestamp"});
+
+// Check that readConcern has no afterClusterTime and fields related to api usage are not present.
+commandObj["readConcern"] = {
+ level: "local"
+};
+delete commandObj["apiDeprecationErrors"];
+delete commandObj["apiVersion"];
+delete commandObj["apiStrict"];
+assert.commandWorked(replSetConn.getDB(dbName).runCommand(commandObj));
+stats = getLatestQueryStatsEntry(replSetConn, {collName: collName});
+assert.eq(stats.key["readConcern"], {level: "local"});
+// We're not concerned with this field here.
+delete stats.key["collectionType"];
+confirmCommandFieldsPresent(stats.key, commandObj);
+
+// Check that the 'atClusterTime' parameter is shapified correctly.
+commandObj.readConcern = {
+ level: "snapshot",
+ atClusterTime: clusterTime
+};
+assert.commandWorked(replSetConn.getDB(dbName).runCommand(commandObj));
+stats = getLatestQueryStatsEntry(replSetConn, {collName: collName});
+assert.eq(stats.key["readConcern"], {level: "snapshot", atClusterTime: "?timestamp"});
+
+replTest.stopSet();
+})();
diff --git a/jstests/noPassthrough/queryStats/single_batch_on_mongod_agg_cmd.js b/jstests/noPassthrough/queryStats/single_batch_on_mongod_agg_cmd.js
new file mode 100644
index 00000000000..d3c605c61d8
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/single_batch_on_mongod_agg_cmd.js
@@ -0,0 +1,61 @@
+/**
+ * Test that the queryStats metrics are aggregated properly for queries run on a mongod where the
+ * results fit into a single batch (and thus don't require a cursor), for agg commands.
+ * @tags: [requires_fcv_60]
+ */
+load("jstests/libs/query_stats_utils.js"); // For verifyMetrics and getQueryStatsAggCmd.
+
+(function() {
+"use strict";
+
+// Turn on the collecting of queryStats metrics.
+let options = {
+ setParameter: {internalQueryStatsRateLimit: -1},
+};
+
+const conn = MongoRunner.runMongod(options);
+const testDB = conn.getDB('test');
+var coll = testDB[jsTestName()];
+coll.drop();
+
+// Bulk insert documents to reduces roundtrips and make timeout on a slow machine less likely.
+const bulk = coll.initializeUnorderedBulkOp();
+const numDocs = 100;
+for (let i = 0; i < numDocs / 2; ++i) {
+ bulk.insert({foo: 0, bar: Math.floor(Math.random() * 3)});
+ bulk.insert({foo: 1, bar: Math.floor(Math.random() * -2)});
+}
+assert.commandWorked(bulk.execute());
+
+// Assert that two agg queries with identical structures are represented by the same key.
+
+// Note that toArray is necessary to guarantee the query finishes executing on the server (at
+// which point an entry is finally written to the queryStats store).
+coll.aggregate([{$match: {foo: 1}}]).toArray();
+coll.aggregate([{$match: {foo: 0}}]).toArray();
+
+// This command will return all queryStats store entires.
+const queryStatsResults = getQueryStatsAggCmd(testDB);
+// Assert there is only one entry.
+assert.eq(queryStatsResults.length, 1, queryStatsResults);
+const queryStatsEntry = queryStatsResults[0];
+assert.eq(queryStatsEntry.key.queryShape.cmdNs.db, "test");
+assert.eq(queryStatsEntry.key.queryShape.cmdNs.coll, jsTestName());
+assert.eq(queryStatsEntry.key.client.application.name, "MongoDB Shell");
+
+// Assert we update execution count for identically shaped queries.
+assert.eq(queryStatsEntry.metrics.execCount, 2);
+
+// Assert queryStats values are accurate for the two above queries.
+assert.eq(queryStatsEntry.metrics.docsReturned.sum, numDocs);
+assert.eq(queryStatsEntry.metrics.docsReturned.min, numDocs / 2);
+assert.eq(queryStatsEntry.metrics.docsReturned.max, numDocs / 2);
+
+// The total size of documents in the collection should ensure that the queries in this test can
+// be executed without requiring multiple batches, but we verify that by looking at the
+// timestamps.
+assert.eq(queryStatsEntry.metrics.firstResponseExecMicros, queryStatsEntry.metrics.totalExecMicros);
+
+verifyMetrics(queryStatsResults);
+MongoRunner.stopMongod(conn);
+}());
diff --git a/jstests/noPassthrough/queryStats/single_batch_on_mongod_find_cmd.js b/jstests/noPassthrough/queryStats/single_batch_on_mongod_find_cmd.js
new file mode 100644
index 00000000000..84c13b942e3
--- /dev/null
+++ b/jstests/noPassthrough/queryStats/single_batch_on_mongod_find_cmd.js
@@ -0,0 +1,59 @@
+/**
+ * Test that the queryStats metrics are aggregated properly for queries run on a mongod where the
+ * results fit into a single batch (and thus don't require a cursor), for find commands.
+ * @tags: [requires_fcv_60]
+ */
+load("jstests/libs/query_stats_utils.js"); // For verifyMetrics and getQueryStatsAggCmd.
+
+(function() {
+"use strict";
+
+// Turn on the collecting of queryStats metrics.
+let options = {
+ setParameter: {internalQueryStatsRateLimit: -1},
+};
+
+const conn = MongoRunner.runMongod(options);
+const testDB = conn.getDB('test');
+var coll = testDB[jsTestName()];
+coll.drop();
+
+// Bulk insert documents to reduces roundtrips and make timeout on a slow machine less likely.
+const bulk = coll.initializeUnorderedBulkOp();
+const numDocs = 100;
+for (let i = 0; i < numDocs / 2; ++i) {
+ bulk.insert({foo: 0, bar: Math.floor(Math.random() * 3)});
+ bulk.insert({foo: 1, bar: Math.floor(Math.random() * -2)});
+}
+assert.commandWorked(bulk.execute());
+
+// Note that toArray is necessary to guarantee the query finishes executing on the server (at
+// which point an entry is finally written to the queryStats store).
+coll.find({foo: {$eq: 0}}).toArray();
+coll.find({foo: {$eq: 1}}).toArray();
+
+// This command will return all queryStats store entires.
+const queryStatsResults = getQueryStatsFindCmd(testDB);
+// Assert there is only one entry.
+assert.eq(queryStatsResults.length, 1, queryStatsResults);
+const queryStatsEntry = queryStatsResults[0];
+assert.eq(queryStatsEntry.key.queryShape.cmdNs.db, "test");
+assert.eq(queryStatsEntry.key.queryShape.cmdNs.coll, jsTestName());
+assert.eq(queryStatsEntry.key.client.application.name, "MongoDB Shell");
+
+// Assert we update execution count for identically shaped queries.
+assert.eq(queryStatsEntry.metrics.execCount, 2);
+
+// Assert queryStats values are accurate for the two above queries.
+assert.eq(queryStatsEntry.metrics.docsReturned.sum, numDocs);
+assert.eq(queryStatsEntry.metrics.docsReturned.min, numDocs / 2);
+assert.eq(queryStatsEntry.metrics.docsReturned.max, numDocs / 2);
+
+// The total size of documents in the collection should ensure that the queries in this test can
+// be executed without requiring multiple batches, but we verify that by looking at the
+// timestamps.
+assert.eq(queryStatsEntry.metrics.firstResponseExecMicros, queryStatsEntry.metrics.totalExecMicros);
+verifyMetrics(queryStatsResults);
+
+MongoRunner.stopMongod(conn);
+}());
diff --git a/jstests/noPassthrough/readConcern_atClusterTime_noop_write.js b/jstests/noPassthrough/readConcern_atClusterTime_noop_write.js
index 081b6c9a5cf..ddc5c191bea 100644
--- a/jstests/noPassthrough/readConcern_atClusterTime_noop_write.js
+++ b/jstests/noPassthrough/readConcern_atClusterTime_noop_write.js
@@ -56,24 +56,46 @@ const st = new ShardingTest({
}
});
-// Create database "test0" on shard 0.
-const testDB0 = st.s.getDB("test0");
-assert.commandWorked(testDB0.adminCommand({enableSharding: testDB0.getName()}));
-st.ensurePrimaryShard(testDB0.getName(), st.shard0.shardName);
-assert.commandWorked(testDB0.createCollection("coll0"));
+/*
+ * Create one unsharded collection per shard
+ * SHARD0 : "test0.coll0"
+ * SHARD1 : "test1.coll1"
+ */
+var collectionMap = {};
+collectionMap[st.shard0.shardName] = {
+ rs: st.rs0,
+ dbName: "test0",
+ collName: "coll0"
+};
+collectionMap[st.shard1.shardName] = {
+ rs: st.rs1,
+ dbName: "test1",
+ collName: "coll1"
+};
-// Create a database "test1" on shard 1.
-const testDB1 = st.s.getDB("test1");
-assert.commandWorked(testDB1.adminCommand({enableSharding: testDB1.getName()}));
-st.ensurePrimaryShard(testDB1.getName(), st.shard1.shardName);
-assert.commandWorked(testDB1.createCollection("coll1"));
+// Create an unsharded collection per shard.
+function createCollectionOnShard(shard) {
+ var dbName = collectionMap[shard.shardName].dbName;
+ var collName = collectionMap[shard.shardName].collName;
+
+ assert.commandWorked(
+ st.s.getDB(dbName).adminCommand({enableSharding: dbName, primaryShard: shard.shardName}));
+ assert.commandWorked(st.s.getDB(dbName).createCollection(collName));
+}
-const PropagationPreferenceOptions = Object.freeze({kShard: 0, kConfig: 1});
+createCollectionOnShard(st.shard0);
+createCollectionOnShard(st.shard1);
-let testNoopWrite = (fromDbName, fromColl, toRS, toDbName, toColl, propagationPreference) => {
- const fromDBFromMongos = st.s.getDB(fromDbName);
- const toDBFromMongos = st.s.getDB(toDbName);
- const configFromMongos = st.s.getDB("config");
+let testNoopWrite = (sourceShardName, destinationShardName) => {
+ var fromDbName = collectionMap[sourceShardName].dbName;
+ var fromCollName = collectionMap[sourceShardName].collName;
+
+ var toDbName = collectionMap[destinationShardName].dbName;
+ var toCollName = collectionMap[destinationShardName].collName;
+ var toRS = collectionMap[destinationShardName].rs;
+
+ jsTest.log(
+ `Testing source shard ${sourceShardName}, destination shard ${destinationShardName}`);
const oplog = toRS.getPrimary().getCollection("local.oplog.rs");
let findRes = oplog.findOne({o: {$eq: {"noop write for afterClusterTime read concern": 1}}});
@@ -81,57 +103,57 @@ let testNoopWrite = (fromDbName, fromColl, toRS, toDbName, toColl, propagationPr
// Perform a write on the fromDB and get its op time.
let res = assert.commandWorked(
- fromDBFromMongos.runCommand({insert: fromColl, documents: [{_id: 0}]}));
+ st.s.getDB(fromDbName).runCommand({insert: fromCollName, documents: [{_id: 0}]}));
assert(res.hasOwnProperty("operationTime"), tojson(res));
- let clusterTime = res.operationTime;
-
- // Propagate 'clusterTime' to toRS or the config server. This ensures that its next
- // write will be at time >= 'clusterTime'. We cannot use toDBFromMongos to propagate
- // 'clusterTime' to the config server, because mongos only routes to the config server
- // for the 'config' and 'admin' databases.
- if (propagationPreference == PropagationPreferenceOptions.kConfig) {
- configFromMongos.coll1.find().itcount();
- } else {
- toDBFromMongos.coll1.find().itcount();
+ let fromRSOpTime = res.operationTime;
+
+ let toRSOpTime = getLastOpTime(toRS.getPrimary()).ts;
+ // In case 'to' shard has a clock already ahead of the 'from' shard, the entire test can be
+ // skipped as the no-op write won't be executed.
+ if (timestampCmp(toRSOpTime, fromRSOpTime) >= 0) {
+ jsTest.log(`Skipping check for source shard ${sourceShardName}, destination shard ${
+ destinationShardName}. Destination shard's clock ${
+ tojson(toRSOpTime)} >= Source shard's clock ${tojson(fromRSOpTime)}`);
+ return;
}
- // Attempt a snapshot read at 'clusterTime' on toRS. Test that it performs a noop write
- // to advance its lastApplied optime past 'clusterTime'. The snapshot read itself may
- // fail if the noop write advances the node's majority commit point past 'clusterTime'
+ // Propagate 'fromRSOpTime' to toRS. This ensures that its next write will be at time >=
+ // 'clusterTime'.
+ st.s.getDB(toDbName).getCollection(toCollName).find().itcount();
+
+ // Attempt a snapshot read at 'fromRSOpTime' on toRS. Test that it performs a noop write
+ // to advance its lastApplied optime past 'fromRSOpTime'. The snapshot read itself may
+ // fail if the noop write advances the node's majority commit point past 'fromRSOpTime'
// and it releases that snapshot.
const toRSSession =
- toRS.getPrimary().getDB(toDBFromMongos).getMongo().startSession({causalConsistency: false});
+ toRS.getPrimary().getDB(toDbName).getMongo().startSession({causalConsistency: false});
- toRSSession.startTransaction({readConcern: {level: "snapshot", atClusterTime: clusterTime}});
- res = toRSSession.getDatabase(toDBFromMongos).runCommand({find: toColl});
+ jsTest.log(`Running transaction with snapshot read concern ${tojson(fromRSOpTime)}`);
+
+ // In case the shard does not advance its lastOpTime, the transaction would hang indefinitely.
+ toRSSession.startTransaction({readConcern: {level: "snapshot", atClusterTime: fromRSOpTime}});
+ res = toRSSession.getDatabase(toDbName).runCommand({find: toCollName, maxTimeMS: 60 * 1000});
+ assert.neq(res.code,
+ ErrorCodes.MaxTimeMSExpired,
+ `Transaction with read concern snapshot at clusterTime ${tojson(fromRSOpTime)} did not complete on time. The shard might not have advanced its lastOpTime before executing.`);
if (res.ok === 0) {
assert.commandFailedWithCode(res, ErrorCodes.SnapshotTooOld);
assert.commandFailedWithCode(toRSSession.abortTransaction_forTesting(),
ErrorCodes.NoSuchTransaction);
- } else {
- assert.commandWorked(toRSSession.commitTransaction_forTesting());
+ return;
}
- const toRSOpTime = getLastOpTime(toRS.getPrimary()).ts;
-
- assert.gte(toRSOpTime, clusterTime);
-
- findRes = oplog.findOne({o: {$eq: {"noop write for afterClusterTime read concern": 1}}});
- assert(findRes);
+ assert.commandWorked(toRSSession.commitTransaction_forTesting());
+ // Check the lastOpTime advanced. This should happen either because of another operation, or
+ // because of a no-op in the oplog performed by the transaction itself.
+ toRSOpTime = getLastOpTime(toRS.getPrimary()).ts;
+ assert.gte(toRSOpTime, fromRSOpTime);
};
-//
-// Test noop write. Read from the destination shard.
-//
-
-testNoopWrite("test0", "coll0", st.rs1, "test1", "coll1", PropagationPreferenceOptions.kShard);
-
-//
-// Test noop write. Read from the config server's primary.
-//
-
-testNoopWrite(
- "test0", "coll2", st.configRS, "test1", "coll3", PropagationPreferenceOptions.kConfig);
+// The test requires the "to" shard to have its clock ahead the "from" shard, otherwise it early
+// exits. Run the test both sides to make sure to execute the test at least once.
+testNoopWrite(st.shard0.shardName, st.shard1.shardName);
+testNoopWrite(st.shard1.shardName, st.shard0.shardName);
st.stop();
}());
diff --git a/jstests/noPassthrough/read_preference_metrics.js b/jstests/noPassthrough/read_preference_metrics.js
index b6290a23f47..2f47a0c4797 100644
--- a/jstests/noPassthrough/read_preference_metrics.js
+++ b/jstests/noPassthrough/read_preference_metrics.js
@@ -33,9 +33,24 @@ function verifyMetricIncrement(conn, readPref, executedOn, tagged) {
const expectedCount = preMetrics[executedOn][readPref].external + 1;
const count = postMetrics[executedOn][readPref].external;
- assert(expectedCount == count,
- `Actual count ${count} did not equal expected count ${
- expectedCount} for readPreference ${readPref}.`);
+ // Replica set nodes run a periodic job to refresh keys for HMAC computation. Although this
+ // job is internal, it is classified as "external" because it uses a client flagged as such.
+ // The job performs two find operations on system collections using read preference 'nearest',
+ // which asynchronously increments the external 'nearest' read preference counter twice. This
+ // can race with retrieving the pre- and post-metrics, and so we must include a special case.
+ // The incorrect external classification is fixed in future versions.
+ if (readPref === "nearest") {
+ // Ensure the actual count is greater than or equal to the expected count. In the case
+ // we've hit the race condition, ensure the count is no greater than two more increments
+ // beyond the expected count.
+ assert(count >= expectedCount && count <= expectedCount + 2,
+ `Actual count ${count} is not greater than or equal to expected count ${
+ expectedCount} for readPreference ${readPref}.`);
+ } else {
+ assert(expectedCount == count,
+ `Actual count ${count} did not equal expected count ${
+ expectedCount} for readPreference ${readPref}.`);
+ }
if (tagged) {
const expectedTaggedCount = preMetrics[executedOn].tagged.external + 1;
@@ -78,38 +93,22 @@ let serverStatus = assert.commandWorked(standalone.getDB("admin").runCommand({se
assert(!serverStatus.hasOwnProperty("readPreferenceCounters"), tojson(serverStatus));
MongoRunner.stopMongod(standalone);
-// Test that replica set nodes tracks metrics around read preference. The assert.soon() that
-// checks for a periodic job to complete below assumes the replica set will have two nodes, so
-// we should keep that consistent.
+// Test that replica set nodes tracks metrics around read preference.
const rst = new ReplSetTest({nodes: 2});
rst.startSet();
rst.initiateWithHighElectionTimeout();
-// On startup, the replica set nodes will run a periodic job to refresh keys for HMAC computation.
-// This job will perform two find operations on system collections, and this will increment the
-// external 'nearest' read preference counter twice. We should wait for this periodic job to
-// complete on both nodes, so the counters aren't incremented during the test.
-assert.soon(() => {
- return getReadPreferenceMetrics(rst.getPrimary()).executedOnPrimary.nearest.external >= 2 &&
- getReadPreferenceMetrics(rst.getSecondary()).executedOnSecondary.nearest.external >= 2;
-});
jsTestLog("Testing against replica set");
runTest(rst);
rst.stopSet();
// Test that mongos omits metrics around read preference, and shard servers include them.
-// The assert.soon() below assumes two shard server nodes, similar to the replica set case above.
const st = new ShardingTest({shards: 1, rs: {nodes: 2}});
serverStatus = assert.commandWorked(st.s.getDB("admin").runCommand({serverStatus: 1}));
assert(serverStatus.process.startsWith("mongos"), tojson(serverStatus));
assert(!serverStatus.hasOwnProperty("readPreferenceCounters"), tojson(serverStatus));
-// The newly started shard servers will also run the same periodic job mentioned above.
-assert.soon(() => {
- return getReadPreferenceMetrics(st.rs0.getPrimary()).executedOnPrimary.nearest.external >= 2 &&
- getReadPreferenceMetrics(st.rs0.getSecondary()).executedOnSecondary.nearest.external >= 2;
-});
jsTestLog("Testing against sharded cluster");
runTest(st.rs0);
diff --git a/jstests/noPassthrough/read_ticket_exhaustion_with_stepdown.js b/jstests/noPassthrough/read_ticket_exhaustion_with_stepdown.js
deleted file mode 100644
index fa59e94c3dd..00000000000
--- a/jstests/noPassthrough/read_ticket_exhaustion_with_stepdown.js
+++ /dev/null
@@ -1,239 +0,0 @@
-/**
- * Tests exhaustion of read tickets, trying to force a deadlock reproduction
- * after yield restores lock state. See SERVER-75205 for more information.
- *
- * Deadlock:
- * The deadlock in question involves readers acquiring the RSTL lock, which no longer
- * happens in 5.0+ due to lock-free reads. Therefore, this test doesn't exercise the
- * deadlock behavior on 5.0+. 4.4 is the primary target of this test, but there isn't
- * much test coverage of ticket exhaustion, so this test may provide other benefits on
- * 5.0+.
- *
- * Parallel Shell Coordination:
- * The 'jsTestName().timing_coordination' collection is used to coordinate timing
- * between the main thread of the test and all the readers via writes to specific
- * documents. One side will wait until the document appears.
- *
- * Test Steps:
- * 0) Start ReplSet with special params:
- * - lower read ticket concurrency
- * - increase yielding
- * 1) Insert kNumDocs documents.
- * 2) Kick off many parallel readers that perform long collection scans that are subject to yields.
- * 3) Wait for many parallel read shells to run.
- * 4) Hold tickets before they're given back to the pool. This is what ensures that we're holding
- * all of the read tickets before the stepdown so that one of the readers has to yield.
- * 5) Wait for many parallel readers to run.
- * 6) Ensure that there are no available read tickets.
- * 7) Hold stepDown so that we know that upon release, it will need a read ticket ~immediately.
- * 8) Initiate stepDown.
- * 9) Hold tickets again, verify state, unlock, and proceed with stepDown.
- * <<Should deadlock here for this scenario>>
- * 10) Stop readers and clean up.
- *
- * @tags: [
- * multiversion_incompatible,
- * requires_replication,
- * requires_wiredtiger,
- * ]
- */
-
-(function() {
-"use strict";
-
-load("jstests/libs/parallel_shell_helpers.js");
-
-const kNumDocs = 1000;
-const kNumReadTickets = 5;
-const replTest = new ReplSetTest({
- name: jsTestName(),
- nodes: 1,
- nodeOptions: {
- setParameter: {
- // This test seeks the minimum amount of concurrency to force ticket exhaustion.
- storageEngineConcurrentReadTransactions: kNumReadTickets,
- // Make yielding more common.
- internalQueryExecYieldPeriodMS: 1,
- internalQueryExecYieldIterations: 1
- }
- }
-});
-
-const dbName = jsTestName();
-const collName = "testcoll";
-let nQueuedReaders = 20;
-// Ensure that when read tickets are released, we have enough reads queued right behind to take the
-// tickets again, ensuring that stepDown competes with reads and a read must yield.
-assert.gte(nQueuedReaders, kNumReadTickets * 2);
-TestData.dbName = dbName;
-TestData.collName = collName;
-
-// Issues long read commands until told to stop.
-// Should be run in a parallel shell via startParallelShell() with a unique id.
-function queuedLongReadsFunc(id) {
- jsTestLog("Starting queued reader [" + id + "]");
- db.getMongo().setSecondaryOk();
- db.getSiblingDB(TestData.dbName)
- .timing_coordination.insert({_id: id, msg: "queued reader started"});
- try {
- for (let i = 0;
- db.getSiblingDB(TestData.dbName).timing_coordination.findOne({_id: "stop reading"}) ==
- null;
- i++) {
- try {
- db.getSiblingDB(TestData.dbName)[TestData.collName].aggregate([{"$count": "x"}]);
- } catch (e) {
- jsTestLog("Ignoring failed read that may be due to stepdown [" + id + "]", e);
- }
- }
- } catch (e) {
- jsTestLog("Exiting reader [" + id + "] early due to:" + e);
- }
- jsTestLog("Queued Reader complete [" + id + "]");
-}
-
-/****************************************************/
-
-// 0) Start ReplSet with special params:
-// - lower read ticket concurrency
-// - increase yielding
-replTest.startSet();
-replTest.initiate();
-let primary = replTest.getPrimary();
-let db = primary.getDB(dbName);
-let primaryAdmin = primary.getDB("admin");
-let primaryColl = db[collName];
-let queuedReaders = [];
-
-// 1) Insert kNumDocs documents.
-jsTestLog("Fill collection [" + dbName + "." + collName + "] with " + kNumDocs + " docs");
-for (let i = 0; i < kNumDocs; i++) {
- assert.commandWorked(primaryColl.insert({"x": i}));
-}
-jsTestLog(kNumDocs + " inserts done");
-
-// 2) Kick off many parallel readers that perform long collection scans that are subject to yields.
-for (let i = 0; i < nQueuedReaders; i++) {
- queuedReaders.push(startParallelShell(funWithArgs(queuedLongReadsFunc, i), primary.port));
- jsTestLog("queued reader " + queuedReaders.length + " initiated");
-}
-
-// 3) Wait for many parallel read shells to run.
-jsTestLog("Wait for many parallel reader shells to run");
-assert.soon(() => db.getSiblingDB(TestData.dbName).timing_coordination.count({
- msg: "queued reader started"
-}) >= nQueuedReaders,
- "Expected at least " + nQueuedReaders + " queued readers to start.");
-
-// 4) Hold tickets before they're given back to the pool. This is what ensures that we're holding
-// all of the read tickets before the stepdown so that one of the readers has to yield.
-jsTestLog("Hold tickets");
-assert.commandWorked(db.adminCommand({configureFailPoint: 'hangTicketRelease', mode: 'alwaysOn'}));
-
-// 5) Wait for many parallel readers to run.
-jsTestLog("Wait for many parallel readers to run");
-assert.soon(
- () => db.getSiblingDB("admin")
- .aggregate([{$currentOp: {}}, {$match: {"command.aggregate": TestData.collName}}])
- .toArray()
- .length >= kNumReadTickets,
- "Expected at least as many operations as queued readers.");
-
-// 6) Ensure that there are no available read tickets.
-jsTestLog("Wait for no available read tickets");
-assert.soon(() => {
- let stats = db.runCommand({serverStatus: 1});
- jsTestLog(stats.wiredTiger.concurrentTransactions);
- return stats.wiredTiger.concurrentTransactions.read.available == 0;
-}, "Expected to have no available read tickets.");
-
-// 7) Hold stepDown so that we know that upon release, it will need a read ticket ~immediately.
-let stats = assert.commandWorked(db.runCommand({serverStatus: 1}));
-jsTestLog(stats.locks);
-jsTestLog(stats.wiredTiger.concurrentTransactions);
-
-stats = db.adminCommand({
- configureFailPoint: 'stepdownHangBeforeRSTLEnqueue',
- mode: 'off' /* Don't change the value; just get the counts. */
-});
-assert.eq(1, stats.ok);
-assert.eq(0, stats.count); // No process has entered this block yet.
-
-jsTestLog("Hold stepDown");
-assert.commandWorked(
- db.adminCommand({configureFailPoint: 'stepdownHangBeforeRSTLEnqueue', mode: 'alwaysOn'}));
-
-// 8) Initiate stepDown.
-jsTestLog("Make primary step down");
-const stepDownSecs = 10;
-const stepDownShell = startParallelShell(
- funWithArgs(function(stepDownSecs) {
- jsTestLog("Run replSetStepDown");
- assert.commandWorked(
- db.getSiblingDB(TestData.dbName).timing_coordination.createIndex({a: 1}));
-
- assert.commandWorked(
- db.getSiblingDB("admin").runCommand({"replSetStepDown": stepDownSecs, "force": true}));
- }, stepDownSecs), primary.port);
-
-// Ensure that the parallel shell is up so that we know that the stepDown has begun. Since we
-// can't share state between the main thread and the parallel shell, the "right" way to do this
-// is to write something from within the parallel shell and check it here. However, even if we
-// wrote something, we wouldn't be able to read it back because we locked reads! Therefore,
-// we'll create an index. We can count the indexes via serverStatus without doing a "read," so
-// it's observable. The index doesn't affect the correctness of this test.
-assert.soon(() => {
- let stats = db.runCommand({serverStatus: 1});
- return stats.metrics.commands.createIndexes.total > 0;
-}, "Expected stepDown shell to be ready.");
-
-jsTestLog("Allow tickets to be released so that we can get stuck at stepdownHangBeforeRSTLEnqueue");
-assert.commandWorked(db.adminCommand({configureFailPoint: 'hangTicketRelease', mode: 'off'}));
-
-jsTestLog("Verify that we're stuck at stepdownHangBeforeRSTLEnqueue");
-assert.commandWorked(db.adminCommand({
- waitForFailPoint: 'stepdownHangBeforeRSTLEnqueue',
- timesEntered: 1,
- maxTimeMS: 10 * 1000,
-}));
-
-// 9) Hold tickets again, verify state, unlock, and proceed with stepDown.
-jsTestLog("Hold tickets again so that we can verify that there are competing readers");
-assert.commandWorked(db.adminCommand({configureFailPoint: 'hangTicketRelease', mode: 'alwaysOn'}));
-assert.soon(() => {
- let stats = db.runCommand({serverStatus: 1});
- jsTestLog(stats.wiredTiger.concurrentTransactions);
- return stats.wiredTiger.concurrentTransactions.read.available == 0;
-}, "Expected to have no available read tickets.");
-
-jsTestLog("Allow stepDown to proceed");
-assert.commandWorked(
- db.adminCommand({configureFailPoint: 'stepdownHangBeforeRSTLEnqueue', mode: 'off'}));
-
-jsTestLog("Allow tickets to be released");
-assert.commandWorked(db.adminCommand({configureFailPoint: 'hangTicketRelease', mode: 'off'}));
-
-jsTestLog("Wait for SECONDARY state");
-replTest.waitForState(primary, ReplSetTest.State.SECONDARY);
-
-// Enforce the replSetStepDown timer.
-sleep(stepDownSecs * 1000);
-
-jsTestLog("Wait for PRIMARY state");
-replTest.waitForState(primary, ReplSetTest.State.PRIMARY);
-replTest.getPrimary();
-
-// 10) Stop readers and clean up.
-jsTestLog("Stop readers");
-assert.commandWorked(db.getSiblingDB(dbName).timing_coordination.insertOne({_id: "stop reading"}));
-
-for (let i = 0; i < queuedReaders.length; i++) {
- const awaitQueuedReader = queuedReaders[i];
- awaitQueuedReader();
- jsTestLog("Queued reader [" + i + "] done");
-}
-
-stepDownShell();
-
-replTest.stopSet();
-})();
diff --git a/jstests/noPassthrough/sbe_plan_cache_with_const_let_var.js b/jstests/noPassthrough/sbe_plan_cache_with_const_let_var.js
new file mode 100644
index 00000000000..88b27eb58f3
--- /dev/null
+++ b/jstests/noPassthrough/sbe_plan_cache_with_const_let_var.js
@@ -0,0 +1,57 @@
+/**
+ * Test that the const user-defined variable will not be const-folded. The SBE plan cache should
+ * keep track of the let variable and refresh the let variable when the plan is recovered.
+ *
+ * The test ensures that two queries with only difference in the const let variable have the same
+ * 'planCacheKey' and return correct results.
+ *
+ * Please see SERVER-81807 for details.
+ *
+ * @tags: [
+ * featureFlagSbeFull
+ * ]
+ */
+
+import {getPlanCacheKeyFromExplain} from "jstests/libs/analyze_plan.js";
+
+const conn = MongoRunner.runMongod();
+const db = conn.getDB("test");
+const coll = db.sbe_plan_cache_with_const_let_var;
+coll.drop();
+
+assert.commandWorked(coll.insert({}));
+
+let result;
+const findWithConstLet5 = {
+ find: coll.getName(),
+ filter: {},
+ projection: {_id: "$$a"},
+ limit: 1,
+ let : {a: {$add: [2, 3]}},
+};
+const findWithConstLet500 = {
+ find: coll.getName(),
+ filter: {},
+ projection: {_id: "$$a"},
+ limit: 1,
+ let : {a: {$add: [200, 300]}},
+};
+
+result = assert.commandWorked(db.runCommand(findWithConstLet5)).cursor.firstBatch;
+// Test that right result is returned.
+assert.eq(result, [{_id: 5}]);
+assert.gt(coll.getPlanCache().list().length, 0, coll.getPlanCache().list());
+
+let exp = assert.commandWorked(db.runCommand({explain: findWithConstLet5}));
+let planCacheKey = getPlanCacheKeyFromExplain(exp, db);
+
+result = assert.commandWorked(db.runCommand(findWithConstLet500)).cursor.firstBatch;
+exp = assert.commandWorked(db.runCommand({explain: findWithConstLet500}));
+
+// Test that two queries with different consts have the same planCacheKey and the returned results
+// are correct and different. Otherwise, the const let value may be incorrectly baked into SBE plan
+// and then the 2nd query would return the same document as the first query.
+assert.eq(result, [{_id: 500}]);
+assert.eq(planCacheKey, getPlanCacheKeyFromExplain(exp, db), coll.getPlanCache().list());
+
+MongoRunner.stopMongod(conn);
diff --git a/jstests/noPassthrough/server_status_metrics_retryable_writes.js b/jstests/noPassthrough/server_status_metrics_retryable_writes.js
new file mode 100644
index 00000000000..fd320dc4c61
--- /dev/null
+++ b/jstests/noPassthrough/server_status_metrics_retryable_writes.js
@@ -0,0 +1,155 @@
+/**
+ * Tests the retryable write counts in mongos and mongod serverStatus output
+ * for a replica set and a sharded cluster.
+ */
+
+function assertServerStatus(expectedServerStatusMetrics, externalConn, internalConn) {
+ const externalServerStatus = assert.commandWorked(externalConn.adminCommand({serverStatus: 1}));
+ assert.eq(expectedServerStatusMetrics['external']['internalRetryableWriteCount'],
+ externalServerStatus.metrics.query.internalRetryableWriteCount);
+ assert.eq(expectedServerStatusMetrics['external']['externalRetryableWriteCount'],
+ externalServerStatus.metrics.query.externalRetryableWriteCount);
+ assert.eq(expectedServerStatusMetrics['external']['retryableInternalTransactionCount'],
+ externalServerStatus.metrics.query.retryableInternalTransactionCount);
+ if (internalConn) {
+ const internalServerStatus =
+ assert.commandWorked(internalConn.adminCommand({serverStatus: 1}));
+ assert.eq(expectedServerStatusMetrics['internal']['internalRetryableWriteCount'],
+ internalServerStatus.metrics.query.internalRetryableWriteCount);
+ assert.eq(expectedServerStatusMetrics['internal']['externalRetryableWriteCount'],
+ internalServerStatus.metrics.query.externalRetryableWriteCount);
+ assert.eq(expectedServerStatusMetrics['internal']['retryableInternalTransactionCount'],
+ internalServerStatus.metrics.query.retryableInternalTransactionCount);
+ }
+}
+
+function runTest(externalConn, internalConn = undefined) {
+ // Setting up
+ const dbName = "test";
+ const testDB = externalConn.getDB(dbName);
+ const coll = testDB.coll;
+
+ assert.commandWorked(coll.insert({x: -1, _id: -1}));
+ assert.commandWorked(coll.insert({x: 1, _id: 1}));
+
+ let txnNumber = NumberLong(1);
+ const lsid = {id: UUID()};
+ const lsidWithUUID = {id: UUID(), txnUUID: UUID()};
+ const lsidWithUUIDAndTxnNum = {
+ id: UUID(),
+ txnUUID: UUID(),
+ txnNumber: NumberLong(2),
+ };
+ const update = {q: {_id: 2}, u: {$inc: {counter: 1}}};
+
+ // Check initial metrics.
+ let expectedServerStatusMetrics = {};
+ expectedServerStatusMetrics['external'] = {
+ 'internalRetryableWriteCount': 0,
+ 'externalRetryableWriteCount': 0,
+ 'retryableInternalTransactionCount': 0
+ };
+ if (internalConn) {
+ const internalServerStatus =
+ assert.commandWorked(internalConn.adminCommand({serverStatus: 1}));
+ expectedServerStatusMetrics['internal'] = {
+ 'internalRetryableWriteCount': 0,
+ 'externalRetryableWriteCount': 0,
+ 'retryableInternalTransactionCount':
+ internalServerStatus.metrics.query.retryableInternalTransactionCount
+ };
+ }
+
+ assertServerStatus(expectedServerStatusMetrics, externalConn, internalConn);
+
+ // Ordinary write without session
+ assert.commandWorked(testDB.runCommand({update: coll.getName(), updates: [update]}));
+
+ assertServerStatus(expectedServerStatusMetrics, externalConn, internalConn);
+
+ // Non-retryable write with session
+ assert.commandWorked(
+ testDB.runCommand({update: coll.getName(), updates: [update], lsid: lsid}));
+
+ assertServerStatus(expectedServerStatusMetrics, externalConn, internalConn);
+
+ // Retryable write with session
+ assert.commandWorked(testDB.runCommand({
+ update: coll.getName(),
+ updates: [update],
+ lsid: lsid,
+ txnNumber: NumberLong(txnNumber++)
+ }));
+
+ expectedServerStatusMetrics['external']['externalRetryableWriteCount'] += 1;
+ if (internalConn) {
+ expectedServerStatusMetrics['internal']['internalRetryableWriteCount'] += 1;
+ }
+
+ assertServerStatus(expectedServerStatusMetrics, externalConn, internalConn);
+
+ // Write with session and in transaction, lsid with id.
+ assert.commandWorked(testDB.runCommand({
+ update: coll.getName(),
+ updates: [update],
+ lsid: lsid,
+ txnNumber: NumberLong(txnNumber++),
+ startTransaction: true,
+ autocommit: false
+ }));
+
+ assertServerStatus(expectedServerStatusMetrics, externalConn, internalConn);
+
+ // Write with session and in transaction, lsid with id and txnUUID.
+ assert.commandWorked(testDB.runCommand({
+ update: coll.getName(),
+ updates: [update],
+ lsid: lsidWithUUID,
+ txnNumber: NumberLong(txnNumber++),
+ startTransaction: true,
+ autocommit: false
+ }));
+
+ assertServerStatus(expectedServerStatusMetrics, externalConn, internalConn);
+
+ // Write with session and in transaction, lsid with id, txnUUID and txnNumber.
+ assert.commandWorked(testDB.runCommand({
+ update: coll.getName(),
+ updates: [update],
+ lsid: lsidWithUUIDAndTxnNum,
+ txnNumber: NumberLong(txnNumber++),
+ startTransaction: true,
+ autocommit: false
+ }));
+
+ expectedServerStatusMetrics['external']['retryableInternalTransactionCount'] += 1;
+ if (internalConn) {
+ expectedServerStatusMetrics['internal']['retryableInternalTransactionCount'] += 1;
+ }
+
+ assertServerStatus(expectedServerStatusMetrics, externalConn, internalConn);
+}
+
+jsTest.log(
+ "Tests the retryable write counts in mongos and mongod serverStatus output for a sharded cluster.");
+{
+ const st = new ShardingTest({shards: 1, mongos: 1});
+ const mongos = st.s0;
+ const shard0Primary = st.rs0.getPrimary();
+
+ runTest(mongos, shard0Primary);
+
+ st.stop();
+}
+
+jsTest.log("Tests the retryable write counts in mongod serverStatus output for a replica set.");
+{
+ const rt = new ReplSetTest({name: "server_status_repl", nodes: 1});
+ rt.startSet();
+ rt.initiate();
+ const primary = rt.getPrimary();
+
+ runTest(primary);
+
+ rt.stopSet();
+}
diff --git a/jstests/noPassthrough/serverstatus_index_stats.js b/jstests/noPassthrough/serverstatus_index_stats.js
index 300b71c6194..6f73afb1cb5 100644
--- a/jstests/noPassthrough/serverstatus_index_stats.js
+++ b/jstests/noPassthrough/serverstatus_index_stats.js
@@ -31,6 +31,7 @@ const knownFeatures = [
"id",
"normal",
"partial",
+ "prepareUnique",
"single",
"sparse",
"text",
diff --git a/jstests/noPassthrough/shell_assertions.js b/jstests/noPassthrough/shell_assertions.js
index 066ee04a2c7..d09b2b0a6fc 100644
--- a/jstests/noPassthrough/shell_assertions.js
+++ b/jstests/noPassthrough/shell_assertions.js
@@ -61,6 +61,29 @@
'doAssert should throw passed object as exception');
});
+ tests.push(function callingDoAssertCorrectlyAttachesWriteErrors() {
+ const errorMessage = "Operation was interrupted";
+ const bulkResult = {
+ nModified: 0,
+ n: 0,
+ writeErrors: [{"index": 0, "code": 11601, "errmsg": errorMessage}],
+ upserted: [],
+ ok: 1
+ };
+
+ let error = assert.throws(() => doassert(errorMessage, new BulkWriteError(bulkResult)));
+ assert.eq(error.writeErrors[0].code, bulkResult.writeErrors[0].code);
+
+ error = assert.throws(() => doassert(errorMessage, new BulkWriteResult(bulkResult)));
+ assert.eq(error.writeErrors[0].code, bulkResult.writeErrors[0].code);
+
+ error = assert.throws(() => doassert(errorMessage, new WriteResult(bulkResult)));
+ assert.eq(error.writeErrors[0].code, bulkResult.writeErrors[0].code);
+
+ error = assert.throws(() => doassert(errorMessage, bulkResult));
+ assert.eq(error.writeErrors[0].code, bulkResult.writeErrors[0].code);
+ });
+
/* assert tests */
tests.push(function assertShouldFailForMoreThan2Args() {
diff --git a/jstests/noPassthrough/standalone_replication_recovery.js b/jstests/noPassthrough/standalone_replication_recovery.js
index f0de7b23710..b916795bc80 100644
--- a/jstests/noPassthrough/standalone_replication_recovery.js
+++ b/jstests/noPassthrough/standalone_replication_recovery.js
@@ -8,6 +8,7 @@
* requires_persistence,
* requires_replication,
* requires_wiredtiger,
+ * incompatible_with_windows_tls,
* ]
*/
@@ -168,4 +169,4 @@ restartServerReplication(secondary);
// Skip checking db hashes since we do a write as a standalone.
TestData.skipCheckDBHashes = true;
rst.stopSet();
-})(); \ No newline at end of file
+})();
diff --git a/jstests/noPassthrough/timeseries_validate_mixed_schema_bucket.js b/jstests/noPassthrough/timeseries_validate_mixed_schema_bucket.js
new file mode 100644
index 00000000000..545314f56df
--- /dev/null
+++ b/jstests/noPassthrough/timeseries_validate_mixed_schema_bucket.js
@@ -0,0 +1,94 @@
+/**
+ * Tests validating a time-series collection with mixed schema buckets.
+ */
+(function() {
+"use strict";
+
+load("jstests/core/timeseries/libs/timeseries.js"); // For 'TimeseriesTest'.
+
+const conn = MongoRunner.runMongod();
+const testDB = conn.getDB(jsTestName());
+
+const collName = "ts";
+
+testDB.createCollection(collName, {timeseries: {timeField: "timestamp", metaField: "metadata"}});
+
+assert.commandWorked(testDB.runCommand({drop: collName}));
+assert.commandWorked(
+ testDB.createCollection(collName, {timeseries: {timeField: "t", metaField: "m"}}));
+const coll = testDB[collName];
+const bucketsColl = testDB["system.buckets." + collName];
+
+const bucket = {
+ _id: ObjectId("65a6eb806ffc9fa4280ecac4"),
+ control: {
+ version: NumberInt(1),
+ min: {
+ _id: ObjectId("65a6eba7e6d2e848e08c3750"),
+ t: ISODate("2024-01-16T20:48:00Z"),
+ a: 1,
+ },
+ max: {
+ _id: ObjectId("65a6eba7e6d2e848e08c3751"),
+ t: ISODate("2024-01-16T20:48:39.448Z"),
+ a: "a",
+ },
+ },
+ meta: 0,
+ data: {
+ _id: {
+ 0: ObjectId("65a6eba7e6d2e848e08c3750"),
+ 1: ObjectId("65a6eba7e6d2e848e08c3751"),
+ },
+ t: {
+ 0: ISODate("2024-01-16T20:48:39.448Z"),
+ 1: ISODate("2024-01-16T20:48:39.448Z"),
+ },
+ a: {
+ 0: "a",
+ 1: 1,
+ },
+ },
+};
+
+assert.commandWorked(
+ testDB.runCommand({collMod: collName, timeseriesBucketsMayHaveMixedSchemaData: true}));
+assert.eq(TimeseriesTest.bucketsMayHaveMixedSchemaData(bucketsColl), true);
+
+// There should be no reason to have validation errors in the empty collection.
+let res = assert.commandWorked(coll.validate());
+assert(res.valid);
+assert.eq(res.errors.length, 0, "Validation errors detected when there should be none.");
+
+// Insert normal bucket——we expect no errors nor warnings.
+assert.commandWorked(coll.insert({t: ISODate()}));
+res = assert.commandWorked(coll.validate());
+assert(res.valid);
+assert.eq(res.errors.length, 0, "Validation errors detected when there should be none.");
+assert.eq(res.warnings.length, 0, "Validation warnings detected when there should be none.");
+
+assert.commandWorked(bucketsColl.insert(bucket));
+// Even though a mixed schema bucket has been inserted, since the mixed schema data is allowed there
+// should be no errors.
+res = assert.commandWorked(coll.validate());
+assert(res.valid);
+assert.eq(res.errors.length, 0, "Validation errors detected when there should be none.");
+// There should be one warning, though, indicating the mixed schema data.
+assert.eq(res.warnings.length, 1);
+assert.containsPrefix("Detected a time-series bucket with mixed schema data", res.warnings);
+
+assert.commandWorked(
+ testDB.runCommand({collMod: collName, timeseriesBucketsMayHaveMixedSchemaData: false}));
+
+// Now that the allow mixed schema flag is false, an error should be returned after validating.
+res = assert.commandWorked(coll.validate());
+assert(!res.valid);
+assert.eq(res.warnings.length, 0);
+assert.gt(res.errors.length, 0, "Validation should return at least one error.");
+assert.containsPrefix(
+ "Detected a time-series bucket with mixed schema data",
+ res.errors,
+ "Validation of mixed schema buckets when they are not allowed should return an error stating such");
+
+MongoRunner.stopMongod(conn, null, {skipValidation: true});
+})();
diff --git a/jstests/noPassthrough/unfinished_index_builds_restart_using_same_ident.js b/jstests/noPassthrough/unfinished_index_builds_restart_using_same_ident.js
new file mode 100644
index 00000000000..919504b0600
--- /dev/null
+++ b/jstests/noPassthrough/unfinished_index_builds_restart_using_same_ident.js
@@ -0,0 +1,80 @@
+/**
+ * Tests that during startup recovery unfinished index builds that are not resumable will drop and
+ * recreate the index table using the same ident to avoid doing untimestamped writes to the catalog.
+ *
+ * @tags: [
+ * requires_persistence,
+ * requires_replication,
+ * requires_wiredtiger,
+ * ]
+ */
+(function() {
+"use strict";
+
+load("jstests/libs/fail_point_util.js");
+load('jstests/noPassthrough/libs/index_build.js');
+
+const replSet = new ReplSetTest({nodes: 1});
+replSet.startSet();
+replSet.initiate();
+
+const dbName = "test";
+const collName = jsTestName();
+
+let primary = replSet.getPrimary();
+let primaryDB = primary.getDB(dbName);
+let primaryColl = primaryDB[collName];
+
+assert.commandWorked(primaryDB.createCollection(collName));
+assert.commandWorked(primaryColl.insert({x: 1}));
+assert.commandWorked(primaryColl.insert({x: 2}));
+assert.commandWorked(primaryColl.insert({x: 3}));
+
+const failPoint = configureFailPoint(primaryDB, "hangIndexBuildBeforeCommit");
+const indexBuild = IndexBuildTest.startIndexBuild(primaryDB.getMongo(),
+ primaryColl.getFullName(),
+ {x: 1},
+ {},
+ [ErrorCodes.InterruptedAtShutdown]);
+failPoint.wait();
+
+// Get the index ident.
+const ident = assert.commandWorked(primaryDB.runCommand({collStats: collName}))
+ .indexDetails.x_1.uri.substring('statistics:table:'.length);
+jsTestLog("Ident: " + ident);
+
+// Take a checkpoint so that the unfinished index is present in the catalog during the next startup.
+assert.commandWorked(primary.adminCommand({fsync: 1}));
+
+// Crash and restart the node.
+replSet.stop(primary, 9, {allowedExitCode: MongoRunner.EXIT_SIGKILL});
+indexBuild({checkExitSuccess: false});
+replSet.start(primary, {noCleanData: true, setParameter: {logLevel: 1}});
+
+primary = replSet.getPrimary();
+primaryDB = primary.getDB(dbName);
+primaryColl = primaryDB[collName];
+
+// Resetting unfinished index.
+checkLog.containsJson(
+ primary, 6987700, {namespace: primaryColl.getFullName(), index: "x_1", ident: ident});
+
+// WT drop.
+checkLog.containsJson(primary, 22338, {uri: "table:" + ident});
+
+// Create uri.
+checkLog.containsJson(primary, 51780, {uri: "table:" + ident});
+
+// Index build starting.
+checkLog.containsJson(primary, 20384, {ident: ident});
+
+IndexBuildTest.waitForIndexBuildToStop(primaryDB);
+IndexBuildTest.assertIndexes(primaryColl, 2, ["_id_", "x_1"]);
+
+assert.commandWorked(primaryColl.insert({x: 4}));
+assert.commandWorked(primaryColl.insert({x: 5}));
+
+assert.eq(5, primaryColl.find().hint("x_1").count());
+
+replSet.stopSet();
+}());
diff --git a/jstests/noPassthrough/unindex_detects_data_corruption.js b/jstests/noPassthrough/unindex_detects_data_corruption.js
new file mode 100644
index 00000000000..a475b928463
--- /dev/null
+++ b/jstests/noPassthrough/unindex_detects_data_corruption.js
@@ -0,0 +1,38 @@
+/**
+ * This tests that errors are logged when unindexing _id finds evidence of corruption, the server
+ * does not crash, and the appropriate error is returned.
+ */
+(function() {
+
+const replSet = new ReplSetTest({nodes: 1});
+replSet.startSet();
+replSet.initiate();
+
+const primary = replSet.getPrimary();
+
+const db = primary.getDB('test');
+const collName = 'coll';
+const coll = db[collName];
+
+assert.commandWorked(coll.insert({a: "first"}));
+
+assert.commandWorked(primary.adminCommand(
+ {configureFailPoint: "WTIndexUassertDuplicateRecordForKeyOnIdUnindex", mode: "alwaysOn"}));
+
+assert.commandFailedWithCode(coll.remove({a: "first"}), ErrorCodes.DataCorruptionDetected);
+
+assert.commandWorked(primary.adminCommand(
+ {configureFailPoint: "WTIndexUassertDuplicateRecordForKeyOnIdUnindex", mode: "off"}));
+
+assert.soonNoExcept(() => {
+ // The health log entry is written asynchronously by a background worker, expect it to be
+ // eventually found.
+ let entry = primary.getDB('local').system.healthlog.findOne({severity: 'error'});
+ assert(entry, "No healthlog entry found on " + tojson(primary));
+ assert.eq("Un-index seeing multiple records for key", entry.msg, tojson(entry));
+ assert.eq(1, primary.getDB('local').system.healthlog.count({severity: 'error'}));
+ return true;
+});
+
+replSet.stopSet();
+})();
diff --git a/jstests/noPassthrough/update_now_clustertime_replset.js b/jstests/noPassthrough/update_now_clustertime_replset.js
index ca530b8ecdc..46d87ab07d7 100644
--- a/jstests/noPassthrough/update_now_clustertime_replset.js
+++ b/jstests/noPassthrough/update_now_clustertime_replset.js
@@ -214,8 +214,10 @@ returnedDoc = coll.findAndModify({
nowFAMUpsert: {$exists: true},
ctimeFAMUpsert: {$exists: true},
$expr: {
- $and:
- [{$lt: ["$nowFAMUpsert", "$$NOW"]}, {$gt: ["$$CLUSTER_TIME", "$ctimeFAMUpsert"]}]
+ $and: [
+ {$lte: ["$nowFAMUpsert", {$max: [returnedDoc.nowFAMUpsert, "$$NOW"]}]},
+ {$gte: ["$$CLUSTER_TIME", "$ctimeFAMUpsert"]}
+ ]
}
},
sort: {_id: 1},
diff --git a/jstests/noPassthrough/validate_detects_invalid_index_options.js b/jstests/noPassthrough/validate_detects_invalid_index_options.js
index 4d841cc4152..32fb1a3d03e 100644
--- a/jstests/noPassthrough/validate_detects_invalid_index_options.js
+++ b/jstests/noPassthrough/validate_detects_invalid_index_options.js
@@ -25,22 +25,26 @@ assert.commandWorked(coll.createIndex({x: 1}, {safe: true, sparse: true, force:
fp.off();
-// Foreground and background validations can detect invalid index options.
-let validateRes = assert.commandWorked(db.runCommand({validate: collName}));
-assert(!validateRes.valid);
+const checkValidateWarns = function(options = {}) {
+ const res = assert.commandWorked(db.runCommand(Object.assign({validate: collName}, options)));
+ assert(res.valid, res);
+ assert.eq(res.errors.length, 0, res);
+ assert.eq(res.warnings.length, 1, res);
+ assert(res.warnings[0].includes("contains invalid fields"));
+};
-// Ensure that $collStats info gets logged when validation fails.
-checkLog.containsJson(conn, 7463200);
+// Foreground and background validations can detect invalid index options.
+checkValidateWarns();
-validateRes = assert.commandWorked(db.runCommand({validate: collName, background: true}));
-assert(!validateRes.valid);
+// Forces a checkpoint to make the background validation see the data.
+assert.commandWorked(db.adminCommand({fsync: 1}));
+checkValidateWarns({background: true});
// Validating only the metadata can detect invalid index options.
-validateRes = assert.commandWorked(db.runCommand({validate: collName, metadata: true}));
-assert(!validateRes.valid);
+checkValidateWarns({metadata: true});
-// Validation of metadata complete for collection. Problems detected.
-checkLog.containsJson(conn, 5980501);
+// Validation of metadata complete for collection. No problems detected.
+checkLog.containsJson(conn, 5980500);
// Cannot use { metadata: true } with any other options. Background validation is converted into a
// foreground validation on the ephemeralForTest storage engine, making it incompatible with this
@@ -58,7 +62,7 @@ assert.commandFailedWithCode(
// Drop the index with the invalid index options and validate only the metadata.
assert.commandWorked(coll.dropIndex({x: 1}));
-validateRes = assert.commandWorked(db.runCommand({validate: collName, metadata: true}));
+let validateRes = assert.commandWorked(db.runCommand({validate: collName, metadata: true}));
assert(validateRes.valid);
// Validation of metadata complete for collection. No problems detected.
diff --git a/jstests/noPassthrough/validate_doc_schema.js b/jstests/noPassthrough/validate_doc_schema.js
index 8834ed5073f..6215ebdcea3 100644
--- a/jstests/noPassthrough/validate_doc_schema.js
+++ b/jstests/noPassthrough/validate_doc_schema.js
@@ -4,11 +4,6 @@
(function() {
"use strict";
-// TODO SERVER-65078: remove this block.
-// Disable the testing proctor. When the testing proctor is enabled, 'validate' will only warn about
-// non-compliant documents, even when the validation action is 'error'.
-TestData.testingDiagnosticsEnabled = false;
-
const conn = MongoRunner.runMongod();
const dbName = "test";
@@ -29,18 +24,12 @@ function testSchemaValidation(validationAction) {
jsTestLog(res);
// Even though there are two documents violating the collection schema rules, the message about
- // non-compliant documents should only be shown once.
- if (validationAction == "warn") {
- assert(res.valid);
- assert.eq(res.warnings.length, 1);
- assert.eq(res.errors.length, 0);
- assert.eq(res.nNonCompliantDocuments, 2);
- } else if (validationAction == "error") {
- assert(!res.valid);
- assert.eq(res.warnings.length, 0);
- assert.eq(res.errors.length, 1);
- assert.eq(res.nNonCompliantDocuments, 2);
- }
+ // non-compliant documents should only be shown once. Regardless of the validation level, it
+ // should be reported as a warning.
+ assert(res.valid);
+ assert.eq(res.errors.length, 0);
+ assert.eq(res.warnings.length, 1);
+ assert.eq(res.nNonCompliantDocuments, 2);
checkLog.containsJson(conn, 5363500, {recordId: "2"});
checkLog.containsJson(conn, 5363500, {recordId: "3"});
diff --git a/jstests/noPassthrough/validate_out_of_order.js b/jstests/noPassthrough/validate_out_of_order.js
index 27142a71c5f..c8c9eaeecbd 100644
--- a/jstests/noPassthrough/validate_out_of_order.js
+++ b/jstests/noPassthrough/validate_out_of_order.js
@@ -19,11 +19,11 @@ for (let i = 0; i < 5; i++) {
// Test record store out-of-order detection.
assert.commandWorked(
- primary.adminCommand({configureFailPoint: "WTRecordStoreUassertOutOfOrder", mode: "alwaysOn"}));
+ primary.adminCommand({configureFailPoint: "failRecordStoreTraversal", mode: "alwaysOn"}));
let res = assert.commandWorked(coll.validate());
assert(!res.valid);
assert.commandWorked(
- primary.adminCommand({configureFailPoint: "WTRecordStoreUassertOutOfOrder", mode: "off"}));
+ primary.adminCommand({configureFailPoint: "failRecordStoreTraversal", mode: "off"}));
// Test index entry out-of-order detection.
assert.commandWorked(
diff --git a/jstests/noPassthroughWithMongod/command_let_variables_merge_only.js b/jstests/noPassthroughWithMongod/command_let_variables_merge_only.js
index e16f686f57c..7f631864bbb 100644
--- a/jstests/noPassthroughWithMongod/command_let_variables_merge_only.js
+++ b/jstests/noPassthroughWithMongod/command_let_variables_merge_only.js
@@ -1,7 +1,7 @@
// Tests that the aggregate command can use command-level let variables with $merge. Note $merge
// tests must be run in a noPassthrough suite so the other operators are exercised in
// jstests/core/command_let_variables.js.
-
+// @tags: [references_foreign_collection]
(function() {
"use strict";
diff --git a/jstests/noPassthroughWithMongod/cursor_server_status_metrics_lifespan_histogram.js b/jstests/noPassthroughWithMongod/cursor_server_status_metrics_lifespan_histogram.js
index b80ce4dcc0f..ce6988a7489 100644
--- a/jstests/noPassthroughWithMongod/cursor_server_status_metrics_lifespan_histogram.js
+++ b/jstests/noPassthroughWithMongod/cursor_server_status_metrics_lifespan_histogram.js
@@ -22,14 +22,6 @@ function getNumCursorsLessThan30Seconds() {
return db.serverStatus().metrics.cursor.lifespan.lessThan30Seconds;
}
-function getNumCursorsLessThan1Minute() {
- return db.serverStatus().metrics.cursor.lifespan.lessThan1Minute;
-}
-
-function getNumCursorsLessThan10Minutes() {
- return db.serverStatus().metrics.cursor.lifespan.lessThan10Minutes;
-}
-
for (let i = 0; i < 40; i++) {
coll.insert({a: i, b: "field b"});
}
@@ -38,8 +30,6 @@ const initialNumCursorsLt1s = getNumCursorsLessThan1Second();
const initialNumCursorsLt5s = getNumCursorsLessThan5Seconds();
const initialNumCursorsLt15s = getNumCursorsLessThan15Seconds();
const initialNumCursorsLt30s = getNumCursorsLessThan30Seconds();
-const initialNumCursorsLt1m = getNumCursorsLessThan1Minute();
-const initialNumCursorsLt10m = getNumCursorsLessThan10Minutes();
// Since we aren't guaranteed perfect timings, the checks in this test have been relaxed to window
// sizes of 30s. For example, a cursor that is expected to die in under 5s may actually take longer
@@ -65,21 +55,4 @@ for (let i = 0; i < 3; i++) {
}
assert.eq(cursorsDeadSinceStartLt30Seconds(), 4);
-
-const cursorLt1Minute = coll.find().batchSize(2);
-const cursorLt10Minutes = coll.aggregate([], {cursor: {batchSize: 2}});
-cursorLt1Minute.next();
-cursorLt10Minutes.next();
-
-sleep(31000); // Sleep for 31 s.
-while (cursorLt1Minute.hasNext()) {
- cursorLt1Minute.next();
-}
-assert.eq(getNumCursorsLessThan1Minute() - initialNumCursorsLt1m, 1);
-
-sleep(30000); // Sleep another 30s, so the total should be greater than 1m and less than 10m.
-while (cursorLt10Minutes.hasNext()) {
- cursorLt10Minutes.next();
-}
-assert.eq(getNumCursorsLessThan10Minutes() - initialNumCursorsLt10m, 1);
}()); \ No newline at end of file
diff --git a/jstests/noPassthroughWithMongod/projection_optimizations.js b/jstests/noPassthroughWithMongod/projection_optimizations.js
index 8658d6f2260..2b9418cdd6e 100644
--- a/jstests/noPassthroughWithMongod/projection_optimizations.js
+++ b/jstests/noPassthroughWithMongod/projection_optimizations.js
@@ -25,7 +25,8 @@ let result = runFindWithProjection({
expected: [{a: 1, b: false}]
});
// Query should be optimized and covered.
-assert(isIndexOnly(db, getWinningPlan(result.explain().queryPlanner)));
+const winningPlan = getWinningPlan(result.explain().queryPlanner);
+assert(isIndexOnly(db, winningPlan), winningPlan);
result = runFindWithProjection(
{projection: {a: {$and: ['$a', true, 1]}}, expected: [{_id: 0, a: true}]});
diff --git a/jstests/noPassthroughWithMongod/query_stats_configuration.js b/jstests/noPassthroughWithMongod/query_stats_configuration.js
new file mode 100644
index 00000000000..b8094de7d67
--- /dev/null
+++ b/jstests/noPassthroughWithMongod/query_stats_configuration.js
@@ -0,0 +1,35 @@
+/**
+ * Tests that the query stats store can be resized if it is configured, and cannot be resized if it
+ * is disabled.
+ */
+(function() {
+"use strict";
+
+load("jstests/libs/feature_flag_util.js");
+
+if (FeatureFlagUtil.isEnabled(db, "QueryStats")) {
+ function testQueryStatsSetting(paramName, paramValue) {
+ // The feature flag is enabled - make sure the queryStats store can be configured.
+ const original = assert.commandWorked(db.adminCommand({getParameter: 1, [paramName]: 1}));
+ assert(original.hasOwnProperty(paramName), original);
+ const originalValue = original[paramName];
+ try {
+ assert.doesNotThrow(() => db.adminCommand({setParameter: 1, [paramName]: paramValue}));
+ // Other tests verify that changing the parameter actually affects the behavior.
+ } finally {
+ assert.doesNotThrow(() =>
+ db.adminCommand({setParameter: 1, [paramName]: originalValue}));
+ }
+ }
+ testQueryStatsSetting("internalQueryStatsCacheSize", "2MB");
+ testQueryStatsSetting("internalQueryStatsRateLimit", 2147483647);
+} else {
+ // The feature flag is disabled - make sure the query stats store *cannot* be configured.
+ assert.commandFailedWithCode(
+ db.adminCommand({setParameter: 1, internalQueryStatsCacheSize: '2MB'}),
+ ErrorCodes.QueryFeatureNotAllowed);
+ assert.commandFailedWithCode(
+ db.adminCommand({setParameter: 1, internalQueryStatsRateLimit: 2147483647}),
+ ErrorCodes.QueryFeatureNotAllowed);
+}
+}());
diff --git a/jstests/noPassthroughWithMongod/validate_timeseries.js b/jstests/noPassthroughWithMongod/validate_timeseries.js
new file mode 100644
index 00000000000..bf13fb131fd
--- /dev/null
+++ b/jstests/noPassthroughWithMongod/validate_timeseries.js
@@ -0,0 +1,64 @@
+/*
+ * Tests that calling the validate command on a time-series collection is allowed, while ensuring
+ * that calling validate on non-time-series views is still prohibited, even if a collection with the
+ * bucket namespace of that view exists.
+ */
+
+(function() {
+"use strict";
+
+db.validate_timeseries.drop();
+db.system.buckets.validate_timeseries.drop();
+db.viewSource.drop();
+db.view.drop();
+db.system.buckets.view.drop();
+
+assert.commandWorked(db.createCollection(
+ "validate_timeseries",
+ {timeseries: {timeField: "timestamp", metaField: "metadata", granularity: "hours"}}));
+
+const coll = db.validate_timeseries;
+const bucketColl = db.system.buckets.validate_timeseries;
+const weather_data = [
+ {
+ "metadata": {"sensorId": 5578, "type": "temperature"},
+ "timestamp": ISODate("2021-05-18T00:00:00.000Z"),
+ "temp": 12
+ },
+ {
+ "metadata": {"sensorId": 5578, "type": "temperature"},
+ "timestamp": ISODate("2021-05-18T04:00:00.000Z"),
+ "temp": 11
+ },
+];
+
+assert.commandWorked(coll.insertMany(weather_data));
+
+// Tests that the validate command can be run on a time-series collection.
+
+let res = assert.commandWorked(coll.validate());
+assert(res.valid, tojson(res));
+
+res = assert.commandWorked(bucketColl.validate());
+assert(res.valid, tojson(res));
+
+// Tests that the validate command doesn't run on a view without a bucket collection.
+assert.commandWorked(db.createCollection("viewSource"));
+
+assert.commandWorked(db.createView("view", "viewSource", [{$project: {"Name": "$temp"}}]));
+
+const viewSource = db.viewSource;
+const view = db.view;
+
+res = assert.commandWorked(viewSource.validate());
+assert(res.valid, tojson(res));
+
+assert.commandFailedWithCode(view.validate(), ErrorCodes.CommandNotSupportedOnView);
+
+// Tests that the validate command doesn't run on a view with a non-time-series bucket collection.
+assert.commandWorked(db.createCollection("system.buckets.view"));
+
+assert.commandFailedWithCode(view.validate(), ErrorCodes.CommandNotSupportedOnView);
+
+//
+})();
diff --git a/jstests/noPassthroughWithMongod/validate_timeseries_minmax.js b/jstests/noPassthroughWithMongod/validate_timeseries_minmax.js
new file mode 100644
index 00000000000..2bf3a4886fa
--- /dev/null
+++ b/jstests/noPassthroughWithMongod/validate_timeseries_minmax.js
@@ -0,0 +1,246 @@
+/**
+ * Tests that the validate command now checks that 'control.min' and 'control.max' fields in a
+ * time-series bucket agree with those in 'data', and that it adds a warning and
+ * increments the number of noncompliant documents if they don't.
+ */
+
+(function() {
+"use strict";
+
+const collPrefix = "validate_timeseries_minmax";
+const bucketPrefix = "system.buckets.validate_timeseries_minmax";
+let collName = "validate_timeseries_minmax";
+let bucketName = "system.buckets.validate_timeseries_minmax";
+let testCount = 0;
+
+const weatherData = [
+ {
+ "metadata": {"sensorId": 5578, "type": "temperature"},
+ "timestamp": ISODate("2021-05-18T12:00:00.000Z"),
+ "temp": 12
+ },
+ {
+ "metadata": {"sensorId": 5578, "type": "temperature"},
+ "timestamp": ISODate("2021-05-18T16:00:00.000Z"),
+ "temp": 16
+ },
+ {
+ "metadata": {"sensorId": 5578, "type": "temperature"},
+ "timestamp": ISODate("2021-05-18T20:00:00.000Z"),
+ "temp": 15
+ },
+];
+
+const weatherDataWithGap = [
+ {
+ "metadata": {"sensorId": 5578, "type": "temperature"},
+ "timestamp": ISODate("2021-05-18T12:00:00.000Z"),
+ "temp": 12
+ },
+ {
+ "metadata": {"sensorId": 5578, "type": "temperature"},
+ "timestamp": ISODate("2021-05-18T16:00:00.000Z"),
+ },
+ {
+ "metadata": {"sensorId": 5578, "type": "temperature"},
+ "timestamp": ISODate("2021-05-18T20:00:00.000Z"),
+ "temp": 15
+ },
+];
+
+const stringData = [
+ {
+ "metadata": {"sensorId": 5578, "type": "temperature"},
+ "timestamp": ISODate("2021-05-18T12:00:00.000Z"),
+ "temp": 12,
+ "str": "a"
+ },
+ {
+ "metadata": {"sensorId": 5578, "type": "temperature"},
+ "timestamp": ISODate("2021-05-18T16:00:00.000Z"),
+ "temp": 16,
+ "str": "11"
+ },
+ {
+ "metadata": {"sensorId": 5578, "type": "temperature"},
+ "timestamp": ISODate("2021-05-18T20:00:00.000Z"),
+ "temp": 16,
+ "str": "18"
+ },
+];
+
+const arrayData = [
+ {
+ "metadata": {"sensorId": 5578, "type": "temperature"},
+ "timestamp": ISODate("2021-05-18T12:00:00.000Z"),
+ "arr": ["a", {"field": 1}, 1]
+ },
+ {
+ "metadata": {"sensorId": 5578, "type": "temperature"},
+ "timestamp": ISODate("2021-05-18T16:00:00.000Z"),
+ "arr": ["1", {"field": 2}, 100]
+ },
+ {
+ "metadata": {"sensorId": 5578, "type": "temperature"},
+ "timestamp": ISODate("2021-05-18T20:00:00.000Z"),
+ "arr": ["z", {"field": -2}, 30]
+ },
+];
+
+const objectData = [
+ {
+ "metadata": {"sensorId": 5578, "type": "temperature"},
+ "timestamp": ISODate("2021-05-18T12:00:00.000Z"),
+ "obj": {"nestedObj": {"field": 0}},
+ },
+ {
+ "metadata": {"sensorId": 5578, "type": "temperature"},
+ "timestamp": ISODate("2021-05-18T16:00:00.000Z"),
+ "obj": {"nestedObj": {"field": 10}},
+ },
+ {
+ "metadata": {"sensorId": 5578, "type": "temperature"},
+ "timestamp": ISODate("2021-05-18T20:00:00.000Z"),
+ "obj": {"nestedObj": {"field": 2}},
+ },
+];
+
+// Drops collection and creates it again with new data, checking that collection is valid before
+// faulty data is inserted.
+function setUpCollection(data) {
+ testCount += 1;
+ collName = collPrefix + testCount;
+ bucketName = bucketPrefix + testCount;
+ db.getCollection(collName).drop();
+ assert.commandWorked(db.createCollection(
+ collName,
+ {timeseries: {timeField: "timestamp", metaField: "metadata", granularity: "hours"}}));
+ let collection = db.getCollection(collName);
+ assert.commandWorked(collection.insertMany(data));
+ let result = assert.commandWorked(collection.validate());
+ assert(result.valid, tojson(result));
+ assert(result.warnings.length == 0, tojson(result));
+ assert(result.nNonCompliantDocuments == 0, tojson(result));
+}
+
+// Updates 'control' min temperature with corresponding update in recorded temperature, testing
+// that valid updates do not return warnings.
+setUpCollection(weatherData);
+jsTestLog("Running validate on bucket with correct 'max' temperature, using collection " +
+ collName + ".");
+let coll = db.getCollection(collName);
+let bucket = db.getCollection(bucketName);
+assert.commandWorked(bucket.update({}, {"$set": {"control.max.temp": 17}}));
+assert.commandWorked(bucket.update({}, {"$set": {"data.temp.1": 17}}));
+let res = assert.commandWorked(coll.validate());
+assert(res.valid, tojson(res));
+assert(res.warnings.length == 0, tojson(res));
+assert(res.nNonCompliantDocuments == 0, tojson(res));
+
+// Updates the 'control' min and max temperature without an update in recorded temperature.
+setUpCollection(weatherData);
+jsTestLog(
+ "Running validate on bucket with incorrect 'min' and 'max' temperature, using collection " +
+ collName + ".");
+coll = db.getCollection(collName);
+bucket = db.getCollection(bucketName);
+assert.commandWorked(bucket.update({}, {"$set": {"control.min.temp": -200}}));
+assert.commandWorked(bucket.update({}, {"$set": {"control.max.temp": 500}}));
+res = assert.commandWorked(coll.validate());
+assert(res.valid, tojson(res));
+assert(res.warnings.length == 1, tojson(res));
+assert(res.nNonCompliantDocuments == 1, tojson(res));
+
+// Updates the 'control' min and max temperature without an update in recorded temperature, when
+// there is also a gap in observed temperature (i.e, one or more of the data entries does not have a
+// 'temp' field).
+setUpCollection(weatherDataWithGap);
+jsTestLog(
+ "Running validate on bucket with incorrect 'min' and 'max' temperature with gaps in temperature data, using collection " +
+ collName + ".");
+coll = db.getCollection(collName);
+bucket = db.getCollection(bucketName);
+assert.commandWorked(bucket.update({}, {"$set": {"control.min.temp": -200}}));
+assert.commandWorked(bucket.update({}, {"$set": {"control.max.temp": 500}}));
+res = assert.commandWorked(coll.validate());
+assert(res.valid, tojson(res));
+assert(res.warnings.length == 1, tojson(res));
+assert(res.nNonCompliantDocuments == 1, tojson(res));
+
+// Updates the 'control' max _id without an update in recorded temperature.
+setUpCollection(weatherData);
+jsTestLog("Running validate on bucket with incorrect 'max' '_id', using collection " + collName +
+ ".");
+coll = db.getCollection(collName);
+bucket = db.getCollection(bucketName);
+assert.commandWorked(
+ bucket.update({}, {"$set": {"control.max._id": ObjectId("62bcc728f3c51f43297eea43")}}));
+res = assert.commandWorked(coll.validate());
+assert(res.valid, tojson(res));
+assert(res.warnings.length == 1, tojson(res));
+assert(res.nNonCompliantDocuments == 1, tojson(res));
+
+// Updates the 'control' min timestamp without an update in recorded temperature.
+setUpCollection(weatherData);
+jsTestLog("Running validate on bucket with incorrect 'min' timestamp, using collection " +
+ collName + ".");
+coll = db.getCollection(collName);
+bucket = db.getCollection(bucketName);
+assert.commandWorked(
+ bucket.update({}, {"$set": {"control.min.timestamp": ISODate("2021-05-19T13:00:00.000Z")}}));
+res = assert.commandWorked(coll.validate());
+assert(res.valid, tojson(res));
+assert(res.warnings.length == 1, tojson(res));
+assert(res.nNonCompliantDocuments == 1, tojson(res));
+
+// Adds an extra field to the 'control' min object.
+setUpCollection(weatherData);
+jsTestLog("Running validate on bucket with extra control field, using collection " + collName +
+ ".");
+coll = db.getCollection(collName);
+bucket = db.getCollection(bucketName);
+assert.commandWorked(bucket.update({}, {"$set": {"control.min.extra": 10}}));
+res = assert.commandWorked(coll.validate());
+assert(res.valid, tojson(res));
+assert(res.warnings.length == 1, tojson(res));
+assert(res.nNonCompliantDocuments == 1, tojson(res));
+
+// Tests whether discrepancies with string min/max values are caught.
+setUpCollection(stringData);
+jsTestLog(
+ "Running validate on bucket with incorrect 'min' and 'max' string field, using collection " +
+ collName + ".");
+coll = db.getCollection(collName);
+bucket = db.getCollection(bucketName);
+assert.commandWorked(bucket.update({}, {"$set": {"control.min.str": "-200"}}));
+assert.commandWorked(bucket.update({}, {"$set": {"control.max.str": "zzz"}}));
+res = assert.commandWorked(coll.validate());
+assert(res.valid, tojson(res));
+assert(res.warnings.length == 1, tojson(res));
+assert(res.nNonCompliantDocuments == 1, tojson(res));
+
+// Tests whether discrepancies with array values are caught.
+setUpCollection(arrayData);
+jsTestLog("Running validate on bucket with incorrect 'max' array field, using collection " +
+ collName + ".");
+coll = db.getCollection(collName);
+bucket = db.getCollection(bucketName);
+assert.commandWorked(
+ bucket.update({}, {"$set": {"control.max.arr": ["zzzzz", {"field": -2}, 30]}}));
+res = assert.commandWorked(coll.validate());
+assert(res.valid, tojson(res));
+assert(res.warnings.length == 1, tojson(res));
+assert(res.nNonCompliantDocuments == 1, tojson(res));
+
+// Tests whether discrepancies with nested objects are caught.
+setUpCollection(objectData);
+jsTestLog("Running validate on bucket with incorrect 'max' object field, using collection " +
+ collName + ".");
+coll = db.getCollection(collName);
+bucket = db.getCollection(bucketName);
+assert.commandWorked(bucket.update({}, {"$set": {"control.max.obj": {"nestedObj": {"field": 2}}}}));
+res = assert.commandWorked(coll.validate());
+assert(res.valid, tojson(res));
+assert(res.warnings.length == 1, tojson(res));
+assert(res.nNonCompliantDocuments == 1, tojson(res));
+})(); \ No newline at end of file
diff --git a/jstests/noPassthroughWithMongod/validate_timeseries_version.js b/jstests/noPassthroughWithMongod/validate_timeseries_version.js
new file mode 100644
index 00000000000..55aabe6b859
--- /dev/null
+++ b/jstests/noPassthroughWithMongod/validate_timeseries_version.js
@@ -0,0 +1,106 @@
+/**
+ * Tests that the validate command checks data consistencies of the version field in time-series
+ * bucket collections and return warnings properly.
+ */
+
+(function() {
+"use strict";
+let testCount = 0;
+const collNamePrefix = "validate_timeseries_version";
+const bucketNamePrefix = "system.buckets.validate_timeseries_version";
+let collName = collNamePrefix + testCount;
+let bucketName = bucketNamePrefix + testCount;
+let coll = null;
+let bucket = null;
+
+jsTestLog("Running the validate command to check time-series bucket versions");
+testCount += 1;
+collName = collNamePrefix + testCount;
+bucketName = bucketNamePrefix + testCount;
+db.getCollection(collName).drop();
+assert.commandWorked(db.createCollection(
+ collName, {timeseries: {timeField: "timestamp", metaField: "metadata", granularity: "hours"}}));
+coll = db.getCollection(collName);
+bucket = db.getCollection(bucketName);
+
+// Inserts documents into a bucket. Checks no issues are found.
+jsTestLog("Inserting documents into a bucket and checking that no issues are found.");
+coll.insertMany([...Array(10).keys()].map(
+ i =>
+ ({"metadata": {"sensorId": 1, "type": "temperature"}, "timestamp": ISODate(), "temp": i})));
+let res = bucket.validate();
+assert(res.valid, tojson(res));
+assert.eq(res.nNonCompliantDocuments, 0);
+assert.eq(res.warnings.length, 0);
+
+// Inserts documents into another bucket but manually changes the version to 2. Expects warnings
+// from validation.
+jsTestLog(
+ "Manually changing 'control.version' from 1 to 2 and checking for warnings from validation.");
+testCount += 1;
+collName = collNamePrefix + testCount;
+bucketName = bucketNamePrefix + testCount;
+db.getCollection(collName).drop();
+assert.commandWorked(db.createCollection(
+ collName, {timeseries: {timeField: "timestamp", metaField: "metadata", granularity: "hours"}}));
+coll = db.getCollection(collName);
+bucket = db.getCollection(bucketName);
+coll.insertMany([...Array(10).keys()].map(
+ i =>
+ ({"metadata": {"sensorId": 2, "type": "temperature"}, "timestamp": ISODate(), "temp": i})));
+bucket.updateOne({"meta.sensorId": 2}, {"$set": {"control.version": 2}});
+res = bucket.validate();
+assert(res.valid, tojson(res));
+assert.eq(res.nNonCompliantDocuments, 1);
+assert.eq(res.warnings.length, 1);
+
+// Inserts enough documents to close a bucket and then manually changes the version to 1.
+// Expects warnings from validation.
+jsTestLog(
+ "Changing the 'control.version' of a closed bucket from 2 to 1, and checking for warnings from validation.");
+testCount += 1;
+collName = collNamePrefix + testCount;
+bucketName = bucketNamePrefix + testCount;
+db.getCollection(collName).drop();
+assert.commandWorked(db.createCollection(
+ collName, {timeseries: {timeField: "timestamp", metaField: "metadata", granularity: "hours"}}));
+coll = db.getCollection(collName);
+bucket = db.getCollection(bucketName);
+coll.insertMany([...Array(1200).keys()].map(
+ i =>
+ ({"metadata": {"sensorId": 3, "type": "temperature"}, "timestamp": ISODate(), "temp": i})));
+bucket.updateOne({"meta.sensorId": 3, "control.version": 2}, {"$set": {"control.version": 1}});
+res = bucket.validate();
+assert(res.valid, tojson(res));
+assert.eq(res.nNonCompliantDocuments, 1);
+assert.eq(res.warnings.length, 1);
+
+// Returns warnings on a bucket with an unsupported version.
+jsTestLog("Changing 'control.version' to an unsupported version and checking for warnings.");
+testCount += 1;
+collName = collNamePrefix + testCount;
+bucketName = bucketNamePrefix + testCount;
+db.getCollection(collName).drop();
+assert.commandWorked(db.createCollection(
+ collName, {timeseries: {timeField: "timestamp", metaField: "metadata", granularity: "hours"}}));
+coll = db.getCollection(collName);
+bucket = db.getCollection(bucketName);
+coll.insertMany([...Array(1100).keys()].map(
+ i =>
+ ({"metadata": {"sensorId": 4, "type": "temperature"}, "timestamp": ISODate(), "temp": i})));
+bucket.updateOne({"meta.sensorId": 4, "control.version": 2}, {"$set": {"control.version": 500}});
+res = bucket.validate();
+assert(res.valid, tojson(res));
+assert.eq(res.nNonCompliantDocuments, 1);
+assert.eq(res.warnings.length, 1);
+
+// Creates a type-version mismatch in the previous bucket and checks that multiple warnings are
+// reported from a single collection with multiple inconsistent documents.
+jsTestLog(
+ "Making a type-version mismatch in the same bucket as the previous test and checking for warnings.");
+bucket.updateOne({"meta.sensorId": 4, "control.version": 1}, {"$set": {"control.version": 2}});
+res = bucket.validate();
+assert(res.valid, tojson(res));
+assert.eq(res.nNonCompliantDocuments, 2);
+assert.eq(res.warnings.length, 1);
+})(); \ No newline at end of file
diff --git a/jstests/parallel/basic.js b/jstests/parallel/basic.js
index 6ac6361991d..e69de29bb2d 100644
--- a/jstests/parallel/basic.js
+++ b/jstests/parallel/basic.js
@@ -1,22 +0,0 @@
-// perform basic js tests in parallel
-
-load('jstests/libs/parallelTester.js');
-
-Random.setRandomSeed();
-
-var params = ParallelTester.createJstestsLists(4);
-var t = new ParallelTester();
-for (i in params) {
- t.add(ParallelTester.fileTester, params[i]);
-}
-
-try {
- t.run("one or more tests failed");
-} finally {
- print(
- "If the failure here is due to a test unexpected being run, " +
- "it may be due to the parallel suite not honoring feature flag tags. " +
- "If you want to skip such tests in parallel suite, " +
- "please add them to the exclusion list at " +
- "https://github.com/mongodb/mongo/blob/eb75b6ccc62f7c8ea26a57c1b5eb96a41809396a/jstests/libs/parallelTester.js#L149.");
-}
diff --git a/jstests/parallel/basicPlus.js b/jstests/parallel/basicPlus.js
index bd5e4f4c085..e69de29bb2d 100644
--- a/jstests/parallel/basicPlus.js
+++ b/jstests/parallel/basicPlus.js
@@ -1,39 +0,0 @@
-// perform basic js tests in parallel & some other tasks as well
-load('jstests/libs/parallelTester.js');
-
-var c = db.jstests_parallel_basicPlus;
-c.drop();
-
-Random.setRandomSeed();
-
-var params = ParallelTester.createJstestsLists(4);
-var t = new ParallelTester();
-for (i in params) {
- t.add(ParallelTester.fileTester, params[i]);
-}
-
-for (var i = 4; i < 8; ++i) {
- var g = new EventGenerator(i, "jstests_parallel_basicPlus", Random.randInt(20));
- for (var j = (i - 4) * 3000; j < (i - 3) * 3000; ++j) {
- var expected = j - ((i - 4) * 3000);
- g.addCheckCount(expected,
- {_id: {$gte: ((i - 4) * 3000), $lt: ((i - 3) * 3000)}},
- expected % 1000 == 0,
- expected % 500 == 0);
- g.addInsert({_id: j});
- // Add currentOp commands running in parallel. Historically there have been many race
- // conditions between various commands and the currentOp command.
- g.addCurrentOp();
- }
- t.add(EventGenerator.dispatch, g.getEvents());
-}
-try {
- t.run("one or more tests failed");
-} finally {
- print(
- "If the failure here is due to a test unexpected being run, " +
- "it may be due to the parallel suite not honoring feature flag tags. " +
- "If you want to skip such tests in parallel suite, " +
- "please add them to the exclusion list at " +
- "https://github.com/mongodb/mongo/blob/eb75b6ccc62f7c8ea26a57c1b5eb96a41809396a/jstests/libs/parallelTester.js#L149.");
-}
diff --git a/jstests/replsets/backwards_compatible_timeseries_catalog_options.js b/jstests/replsets/backwards_compatible_timeseries_catalog_options.js
new file mode 100644
index 00000000000..af65d49ae8a
--- /dev/null
+++ b/jstests/replsets/backwards_compatible_timeseries_catalog_options.js
@@ -0,0 +1,72 @@
+/*
+ * Test that timeseriesBucketsMayHaveMixedSchemaData and timeseriesBucketingParametersHaveChanged
+ * collection options are correctly applied by secondaries and cloned on initial sync according to
+ * the format introduced under SERVER-91195 (relying on storageEngine.wiredTiger.configString).
+ *
+ * @tags: [multiversion_incompatible]
+ */
+load("jstests/libs/feature_flag_util.js"); // For "FeatureFlagUtil"
+
+const dbName = "testdb";
+const collName = "testcoll";
+const bucketCollName = 'system.buckets.' + collName;
+const bucketNs = dbName + '.' + bucketCollName;
+
+const rst = new ReplSetTest({name: 'rs', nodes: 2});
+rst.startSet();
+rst.initiateWithHighElectionTimeout();
+
+// Create collection on the primary node
+const primary = rst.getPrimary();
+const primaryDb = primary.getDB(dbName);
+const primaryColl = primaryDb.getCollection(collName);
+
+assert.commandWorked(primaryDb.createCollection(collName, {timeseries: {timeField: "t"}}));
+
+// Execute collMod to change the timeseries catalog options under testing
+assert.commandWorked(primaryDb.runCommand({
+ collMod: collName,
+ timeseriesBucketsMayHaveMixedSchemaData: true,
+}));
+
+// Double check that the option has been correctly applied on the primary node
+const expectedAppMetadata = "app_metadata=(timeseriesBucketsMayHaveMixedSchemaData=true)";
+
+const configStringAfterCollMod =
+ primaryDb.runCommand({listCollections: 1, filter: {name: bucketCollName}})
+ .cursor.firstBatch[0]
+ .options.storageEngine.wiredTiger.configString;
+
+assert.eq(configStringAfterCollMod, expectedAppMetadata);
+
+// Add a new node and wait for it to complete initial sync
+rst.add({rsConfig: {priority: 0}});
+
+rst.reInitiate();
+rst.awaitSecondaryNodes();
+rst.awaitReplication();
+
+function assertSameOutputFromDifferentNodes(func) {
+ let outputs = [];
+ rst.nodes.forEach(function(node) {
+ outputs.push(func(node));
+ });
+ assert.eq(outputs[0], outputs[1]);
+ assert.eq(outputs[1], outputs[2]);
+}
+
+// Assert that collection options for the view and for the buckets namespace
+// are the same on primary, secondary and initial-synced secondary.
+assertSameOutputFromDifferentNodes(node => {
+ return node.getDB(dbName)
+ .runCommand({listCollections: 1, filter: {name: collName}})
+ .cursor.firstBatch[0];
+});
+
+assertSameOutputFromDifferentNodes(node => {
+ return node.getDB(dbName)
+ .runCommand({listCollections: 1, filter: {name: bucketCollName}})
+ .cursor.firstBatch[0];
+});
+
+rst.stopSet();
diff --git a/jstests/replsets/catchup_ignores_old_heartbeats.js b/jstests/replsets/catchup_ignores_old_heartbeats.js
new file mode 100644
index 00000000000..9f72adbc86a
--- /dev/null
+++ b/jstests/replsets/catchup_ignores_old_heartbeats.js
@@ -0,0 +1,70 @@
+// Makes sure an old heartbeat that is being processed when primary catchup starts does not cause
+// primary catchup to think we're already caught up.
+
+(function() {
+
+load('jstests/libs/fail_point_util.js');
+load('jstests/replsets/rslib.js');
+
+var name = TestData.testName;
+var rst = new ReplSetTest({
+ name: name,
+ nodes: 3,
+ // We're not testing catchup takeover in this test, and in the case where primary catchup fails,
+ // catchup takeover may cause an additional election and muddle the results. Setting
+ // catchUpTakeoverDelayMillis to -1 disables catchup takeover.
+ settings: {chainingAllowed: true, catchUpTakeoverDelayMillis: -1},
+ nodeOptions: {
+ "setParameter": {
+ "logComponentVerbosity": tojsononeline({"replication": {"verbosity": 2}}),
+ },
+ },
+ useBridge: true,
+ waitForKeys: true
+});
+
+rst.startSet();
+rst.initiate();
+rst.awaitSecondaryNodes();
+
+var primary = rst.getPrimary();
+var primaryColl = primary.getDB("test").coll;
+
+// The default WC is majority and this test can't test catchup properly if it used majority writes.
+assert.commandWorked(primary.adminCommand(
+ {setDefaultRWConcern: 1, defaultWriteConcern: {w: 1}, writeConcern: {w: "majority"}}));
+
+assert(primary.host == rst.nodes[0].host);
+// Make us chain node 1 (the node which will become the new primary) from node 2. Don't allow
+// node 1 to switch back.
+const forceSyncSource = configureFailPoint(
+ rst.nodes[1], "forceSyncSourceCandidate", {"hostAndPort": rst.nodes[2].host});
+syncFrom(rst.nodes[2], rst.nodes[0], rst);
+syncFrom(rst.nodes[1], rst.nodes[2], rst);
+const RBIDBeforeStepUp = assert.commandWorked(primary.adminCommand({replSetGetRBID: 1}));
+
+// Disconnect the primary from the node syncing from it.
+primary.disconnect(rst.nodes[2]);
+// Get a heartbeat from the original primary "stuck" in the new primary.
+const newPrimary = rst.nodes[1];
+let hbfp =
+ configureFailPoint(newPrimary, "pauseInHandleHeartbeatResponse", {"target": primary.host});
+hbfp.wait();
+// Put the original primary ahead of the secondaries.
+assert.commandWorked(primaryColl.insert({_id: 1}));
+jsTestLog("Stepping up new primary");
+assert.commandWorked(newPrimary.adminCommand({replSetStepUp: 1}));
+// Allow the "stuck" heartbeat to proceed.
+hbfp.off();
+// The step-up command waits for the election to complete, but not catch-up. Reconnect the old
+// primary to the new primary's sync source to allow replication.
+primary.reconnect(rst.nodes[2]);
+rst.awaitReplication();
+// The new primary should still be primary.
+assert.eq(newPrimary.host, rst.getPrimary().host);
+// No rollbacks should have happened.
+const RBIDAfterStepUp = assert.commandWorked(primary.adminCommand({replSetGetRBID: 1}));
+assert.eq(RBIDBeforeStepUp.rbid, RBIDAfterStepUp.rbid);
+forceSyncSource.off();
+rst.stopSet();
+})();
diff --git a/jstests/replsets/change_stream_pit_pre_image_deletion_asymmetric.js b/jstests/replsets/change_stream_pit_pre_image_deletion_asymmetric.js
index 014dd8fe568..b0e1f887b60 100644
--- a/jstests/replsets/change_stream_pit_pre_image_deletion_asymmetric.js
+++ b/jstests/replsets/change_stream_pit_pre_image_deletion_asymmetric.js
@@ -47,7 +47,8 @@ assert.commandWorked(coll.insert({_id: 1, v: 1}, {writeConcern: {w: 2}}));
// data situation during oplog application.
const initialSyncNode = replTest.add({
rsConfig: {priority: 0},
- setParameter: {'failpoint.initialSyncHangBeforeCopyingDatabases': tojson({mode: 'alwaysOn'})}
+ setParameter: {'failpoint.initialSyncHangBeforeCopyingDatabases': tojson({mode: 'alwaysOn'})},
+ oplogSize: oplogSizeMB
});
// Wait until the new node starts and pauses on the fail point.
@@ -90,6 +91,10 @@ function oplogIsRolledOver() {
}
while (!oplogIsRolledOver()) {
+ // Reducing the number of documents inserted to prevent using too much memory.
+ // The oplog rollover depends on timestamp, sleeping between inserts can significantly reduce
+ // the total number of documents.
+ sleep(20);
// Insert a large document with a write concern that ensures that before proceeding the
// operation gets replicated to all 3 nodes in the replica set, since, otherwise, the node that
// is being initial synced may not be able to catchup due to a small size of the oplog.
diff --git a/jstests/replsets/dbcheck_fails_on_write_concern_error.js b/jstests/replsets/dbcheck_fails_on_write_concern_error.js
new file mode 100644
index 00000000000..4e76e9ef1c6
--- /dev/null
+++ b/jstests/replsets/dbcheck_fails_on_write_concern_error.js
@@ -0,0 +1,103 @@
+/**
+ * Tests dbCheck fails on write concern error.
+ *
+ */
+load("jstests/libs/fail_point_util.js");
+load("jstests/libs/write_concern_util.js");
+load("jstests/replsets/libs/dbcheck_utils.js");
+
+const dbName = jsTestName();
+const collName = jsTestName();
+
+// There should be multiple batches in the dbcheck run, but dbcheck should stop after the first
+// batch fails when waiting for write concern.
+const nDocs = 100;
+const batchSize = 10;
+
+function runTest(validateMode, writeConcern) {
+ const rst = new ReplSetTest({
+ name: jsTestName(),
+ nodes: 2,
+ nodeOptions: {
+ setParameter:
+ {logComponentVerbosity: tojson({command: 3}), dbCheckHealthLogEveryNBatches: 1},
+ }
+ });
+ rst.startSet();
+ rst.initiateWithHighElectionTimeout();
+ const primary = rst.getPrimary();
+ const secondary = rst.getSecondary();
+ const primaryHealthLog = primary.getDB("local").system.healthlog;
+ const secondaryHealthLog = secondary.getDB("local").system.healthlog;
+ const primaryDB = primary.getDB(dbName);
+ const secondaryDB = secondary.getDB(dbName);
+
+ resetAndInsert(rst, primaryDB, collName, nDocs);
+ assert.commandWorked(primaryDB.runCommand({
+ createIndexes: collName,
+ indexes: [{key: {a: 1}, name: 'a_1'}],
+ }));
+ rst.awaitReplication();
+
+ assert.eq(primaryDB.getCollection(collName).find({}).count(), nDocs);
+ assert.eq(secondaryDB.getCollection(collName).find({}).count(), nDocs);
+ clearHealthLog(rst);
+
+ const hangBeforeProcessingDbCheckRunFp =
+ configureFailPoint(primary, "hangBeforeProcessingDbCheckRun");
+
+ const hangBeforeAddingDBCheckBatchToOplogFp =
+ configureFailPoint(primary, "hangBeforeAddingDBCheckBatchToOplog");
+
+ if (validateMode == "dataConsistencyAndMissingIndexKeysCheck") {
+ jsTestLog("Running dbCheck dataConsistencyAndMissingIndexKeysCheck");
+ runDbCheck(rst, primary.getDB(dbName), collName, {
+ // validateMode: "dataConsistencyAndMissingIndexKeysCheck",
+ maxDocsPerBatch: batchSize,
+ batchWriteConcern: writeConcern,
+ });
+ }
+
+ // TODO SERVER-89817: uncomment when write concern erroring is backported for extra index keys
+ // check. else if (validateMode == "extraIndexKeysCheck") {
+ // jsTestLog("Running dbCheck extraIndexKeysCheck");
+ // runDbCheck(rst, primary.getDB(dbName), collName, {
+ // validateMode: "extraIndexKeysCheck",
+ // secondaryIndex: "a_1",
+ // maxDocsPerBatch: batchSize,
+ // batchWriteConcern: writeConcern,
+ // });
+ // }
+
+ hangBeforeProcessingDbCheckRunFp.wait();
+ stopReplicationOnSecondaries(rst);
+
+ hangBeforeProcessingDbCheckRunFp.off();
+ hangBeforeAddingDBCheckBatchToOplogFp.wait();
+ hangBeforeAddingDBCheckBatchToOplogFp.off();
+
+ // Verify that dbCheck stopped after write concern error.
+ checkHealthLog(primaryHealthLog, logQueries.writeConcernErrorQuery, 1);
+ checkHealthLog(primaryHealthLog, logQueries.startStopQuery, 2);
+ // 1 for start, 1 for the batch, 1 for write concern error, 1 for stop
+ checkHealthLog(primaryHealthLog, {}, 4);
+ checkHealthLog(secondaryHealthLog, logQueries.startStopQuery, 1);
+ checkHealthLog(secondaryHealthLog, {}, 1);
+
+ restartReplicationOnSecondaries(rst);
+ rst.stopSet();
+}
+
+["dataConsistencyAndMissingIndexKeysCheck",
+ // TODO SERVER-89817: uncomment when write concern erroring is backported for extra index keys
+ // check. "extraIndexKeysCheck"
+].forEach((failpointName) => {
+ runTest(failpointName, {
+ w: 'majority',
+ wtimeout: 100,
+ });
+ runTest(failpointName, {
+ w: 3,
+ wtimeout: 100,
+ });
+});
diff --git a/jstests/replsets/dbcheck_skip_applying_batch_on_secondary_parameter.js b/jstests/replsets/dbcheck_skip_applying_batch_on_secondary_parameter.js
new file mode 100644
index 00000000000..e74611ffd1e
--- /dev/null
+++ b/jstests/replsets/dbcheck_skip_applying_batch_on_secondary_parameter.js
@@ -0,0 +1,91 @@
+/**
+ * Tests the skipApplyingDbCheckBatchOnSecondary parameter.
+ */
+load("jstests/libs/feature_flag_util.js");
+load("jstests/replsets/libs/dbcheck_utils.js");
+
+const dbName = jsTestName();
+const collName = jsTestName();
+
+const nDocs = 20;
+const batchSize = 4;
+
+function runTest(validateMode) {
+ const rst = new ReplSetTest({
+ name: jsTestName(),
+ nodes: 2,
+ nodeOptions: {
+ setParameter:
+ {logComponentVerbosity: tojson({command: 3}), dbCheckHealthLogEveryNBatches: 1},
+ }
+ });
+ rst.startSet();
+ rst.initiateWithHighElectionTimeout();
+ const primary = rst.getPrimary();
+
+ if (validateMode == "extraIndexKeysCheck" &&
+ !FeatureFlagUtil.isEnabled(primary.getDB("admin"), "SecondaryIndexChecksInDbCheck")) {
+ rst.stopSet();
+ return;
+ }
+ const secondary = rst.getSecondary();
+ const primaryHealthLog = primary.getDB("local").system.healthlog;
+ const secondaryHealthLog = secondary.getDB("local").system.healthlog;
+ const primaryDB = primary.getDB(dbName);
+ const secondaryDB = secondary.getDB(dbName);
+
+ assert.commandWorked(
+ secondary.adminCommand({"setParameter": 1, "skipApplyingDbCheckBatchOnSecondary": true}));
+ const writeConcern = {w: 'majority'};
+
+ resetAndInsert(rst, primaryDB, collName, nDocs);
+ assert.commandWorked(primaryDB.runCommand({
+ createIndexes: collName,
+ indexes: [{key: {a: 1}, name: 'a_1'}],
+ }));
+ rst.awaitReplication();
+
+ assert.eq(primaryDB.getCollection(collName).find({}).count(), nDocs);
+ assert.eq(secondaryDB.getCollection(collName).find({}).count(), nDocs);
+ clearHealthLog(rst);
+
+ if (validateMode == "dataConsistencyCheck") {
+ jsTestLog("Running dbCheck dataConsistencyCheck");
+ runDbCheck(rst,
+ primary.getDB(dbName),
+ collName,
+ {
+ maxDocsPerBatch: batchSize,
+ batchWriteConcern: writeConcern,
+ },
+ true /*awaitCompletion*/);
+ } else if (validateMode == "extraIndexKeysCheck") {
+ jsTestLog("Running dbCheck extraIndexKeysCheck");
+ runDbCheck(rst,
+ primary.getDB(dbName),
+ collName,
+ {
+ validateMode: "extraIndexKeysCheck",
+ secondaryIndex: "a_1",
+ maxDocsPerBatch: batchSize,
+ batchWriteConcern: writeConcern,
+ },
+ true /*awaitCompletion*/);
+ }
+
+ checkHealthLog(primaryHealthLog, logQueries.allErrorsOrWarningsQuery, 0);
+ checkHealthLog(primaryHealthLog, logQueries.infoBatchQuery, nDocs / batchSize);
+
+ checkHealthLog(secondaryHealthLog, logQueries.startStopQuery, 2);
+ checkHealthLog(
+ secondaryHealthLog, logQueries.skipApplyingBatchOnSecondaryQuery, nDocs / batchSize);
+ checkHealthLog(secondaryHealthLog, logQueries.allErrorsOrWarningsQuery, nDocs / batchSize);
+ checkHealthLog(secondaryHealthLog, logQueries.infoBatchQuery, 0);
+ rst.stopSet();
+}
+
+["extraIndexKeysCheck",
+ "dataConsistencyCheck",
+].forEach((validateMode) => {
+ runTest(validateMode);
+});
diff --git a/jstests/replsets/dbcheck_write_concern.js b/jstests/replsets/dbcheck_write_concern.js
index 4e2a233a2b3..6e102d7bd17 100644
--- a/jstests/replsets/dbcheck_write_concern.js
+++ b/jstests/replsets/dbcheck_write_concern.js
@@ -99,87 +99,5 @@ const healthlog = db.getSiblingDB('local').system.healthlog;
assert.eq(healthlog.find({operation: "dbCheckBatch", severity: "error"}).itcount(), 0);
})();
-// Validate that dbCheck completes with w:majority even when the secondary is down and a wtimeout is
-// specified.
-(function testWMajorityUnavailable() {
- clearLog();
- coll.drop();
-
- // Insert 1000 docs and run a few small batches to ensure we wait for write concern between
- // each one.
- const nDocs = 1000;
- const maxDocsPerBatch = 100;
- assert.commandWorked(coll.insertMany([...Array(nDocs).keys()].map(x => ({a: x}))));
- replSet.awaitReplication();
-
- // Stop the secondary and expect that the dbCheck batches still complete on the primary.
- const secondaryConn = replSet.getSecondary();
- const secondaryNodeId = replSet.getNodeId(secondaryConn);
- replSet.stop(secondaryNodeId, {forRestart: true /* preserve dbPath */});
-
- assert.commandWorked(db.runCommand({
- dbCheck: coll.getName(),
- maxDocsPerBatch: maxDocsPerBatch,
- batchWriteConcern: {w: 'majority', wtimeout: 10},
- }));
-
- // Confirm dbCheck logs the expected number of batches.
- assert.soon(function() {
- return (healthlog.find({operation: "dbCheckBatch", severity: "info"}).itcount() ==
- nDocs / maxDocsPerBatch);
- }, "dbCheck doesn't seem to complete", 60 * 1000);
-
- // Confirm dbCheck logs a warning for every batch.
- assert.soon(function() {
- return (healthlog.find({operation: "dbCheckBatch", severity: "warning"}).itcount() ==
- nDocs / maxDocsPerBatch);
- }, "dbCheck did not log writeConcern warnings", 60 * 1000);
- // There should be no errors.
- assert.eq(healthlog.find({operation: "dbCheckBatch", severity: "error"}).itcount(), 0);
-
- replSet.start(secondaryNodeId, {}, true /*restart*/);
- replSet.awaitNodesAgreeOnPrimaryNoAuth();
- replSet.awaitReplication();
-})();
-
-// Validate that an invalid 'w' setting still allows dbCheck to succeed when presented with a
-// wtimeout.
-(function testW3Unavailable() {
- clearLog();
- coll.drop();
-
- // Insert 1000 docs and run a few small batches to ensure we wait for write concern between
- // each one.
- const nDocs = 1000;
- const maxDocsPerBatch = 100;
- assert.commandWorked(coll.insertMany([...Array(nDocs).keys()].map(x => ({a: x}))));
- replSet.awaitReplication();
-
- // Stop the secondary and expect that the dbCheck batches still complete on the primary.
- const secondaryConn = replSet.getSecondary();
- const secondaryNodeId = replSet.getNodeId(secondaryConn);
- replSet.stop(secondaryNodeId, {forRestart: true /* preserve dbPath */});
-
- assert.commandWorked(db.runCommand({
- dbCheck: coll.getName(),
- maxDocsPerBatch: maxDocsPerBatch,
- batchWriteConcern: {w: 3, wtimeout: 10},
- }));
-
- // Confirm dbCheck logs the expected number of batches.
- assert.soon(function() {
- return (healthlog.find({operation: "dbCheckBatch", severity: "info"}).itcount() ==
- nDocs / maxDocsPerBatch);
- }, "dbCheck doesn't seem to complete", 60 * 1000);
-
- // Confirm dbCheck logs a warning for every batch.
- assert.soon(function() {
- return (healthlog.find({operation: "dbCheckBatch", severity: "warning"}).itcount() ==
- nDocs / maxDocsPerBatch);
- }, "dbCheck did not log writeConcern warnings", 60 * 1000);
- // There should be no errors.
- assert.eq(healthlog.find({operation: "dbCheckBatch", severity: "error"}).itcount(), 0);
-})();
-
replSet.stopSet();
})();
diff --git a/jstests/replsets/empty_ts_repl.js b/jstests/replsets/empty_ts_repl.js
new file mode 100644
index 00000000000..3a2052beb45
--- /dev/null
+++ b/jstests/replsets/empty_ts_repl.js
@@ -0,0 +1,159 @@
+/**
+ * Tests how replication handles inserts and updates with "Timestamp(0,0)" values.
+ *
+ * @tags: [
+ * multiversion_incompatible,
+ * ]
+ */
+(function() {
+"use strict";
+
+const dbName = "test";
+const collName = "empty_ts_repl";
+
+const rst = new ReplSetTest({
+ name: jsTestName(),
+ nodes: 2,
+});
+rst.startSet();
+rst.initiate();
+
+const primaryColl = rst.getPrimary().getDB(dbName).getCollection(collName);
+const secondaryColl = rst.getSecondary().getDB(dbName).getCollection(collName);
+const emptyTs = Timestamp(0, 0);
+
+// Insert several documents. For the first document inserted (_id=101), the empty timestamp value
+// in field "a" should get replaced with the current timestamp.
+assert.commandWorked(primaryColl.insert({_id: 101, a: emptyTs}));
+assert.commandWorked(primaryColl.insert({_id: 102, a: 1}));
+assert.commandWorked(primaryColl.insert({_id: 103, a: 2}));
+assert.commandWorked(primaryColl.insert({_id: 106, a: 3}));
+assert.commandWorked(primaryColl.insert({_id: 107, a: 4}));
+assert.commandWorked(primaryColl.insert({_id: 108, a: 5}));
+assert.commandWorked(primaryColl.insert({_id: 109, a: 6}));
+assert.commandWorked(primaryColl.insert({_id: 110, a: 7}));
+assert.commandWorked(primaryColl.insert({_id: 111, a: 8}));
+
+// Wait for all the inserted documents to replicate to the secondaries.
+rst.awaitReplication();
+
+// Use a replacement-style update to update _id=102. This should result in field "a" being set to
+// the current timestamp.
+assert.commandWorked(primaryColl.update({_id: 102}, {a: emptyTs}));
+
+// Use a replacement-style findAndModify to update _id=103. This should result in field "a" being
+// set to the current timestamp.
+let findAndModifyResult = primaryColl.findAndModify({query: {_id: 103}, update: {a: emptyTs}});
+assert.eq(findAndModifyResult, {_id: 103, a: 2});
+
+// Do a replacement-style update to add a new document with _id=104. This should result in field "a"
+// being set to the current timestamp.
+assert.commandWorked(primaryColl.update({_id: 104}, {a: emptyTs}, {upsert: true}));
+
+// Do a replacement-style findAndModify to add a new document with _id=105. This should result in
+// field "a" being set to the current timestamp.
+findAndModifyResult =
+ primaryColl.findAndModify({query: {_id: 105}, update: {a: emptyTs}, upsert: true});
+assert.eq(findAndModifyResult, null);
+
+// For the rest of the commands below, the empty timestamp values stored in field "a" should be
+// preserved as-is.
+
+// Do an update-operator-style update to update _id=106.
+assert.commandWorked(primaryColl.update({_id: 106}, {$set: {a: emptyTs}}));
+
+// Do an update-operator-style findAndModify to update _id=107.
+findAndModifyResult = primaryColl.findAndModify({query: {_id: 107}, update: {$set: {a: emptyTs}}});
+assert.eq(findAndModifyResult, {_id: 107, a: 4});
+
+// Do a pipeline-style update to update _id=108.
+assert.commandWorked(primaryColl.update({_id: 108}, [{$addFields: {a: emptyTs}}]));
+
+// Do a pipeline-style findAndModify to update _id=109.
+findAndModifyResult =
+ primaryColl.findAndModify({query: {_id: 109}, update: [{$addFields: {a: emptyTs}}]});
+assert.eq(findAndModifyResult, {_id: 109, a: 6});
+
+// Do a pipeline-style update with $internalApplyOplogUpdate to update _id=110.
+assert.commandWorked(primaryColl.update(
+ {_id: 110}, [{$_internalApplyOplogUpdate: {oplogUpdate: {$v: 2, diff: {i: {a: emptyTs}}}}}]));
+
+// Do a pipeline-style findAndModify with $internalApplyOplogUpdate to update _id=111.
+findAndModifyResult = primaryColl.findAndModify({
+ query: {_id: 111},
+ update: [{$_internalApplyOplogUpdate: {oplogUpdate: {$v: 2, diff: {i: {a: emptyTs}}}}}]
+});
+assert.eq(findAndModifyResult, {_id: 111, a: 8});
+
+// Do an update-operator-style update to add a new document with _id=112.
+assert.commandWorked(primaryColl.update({_id: 112}, {$set: {a: emptyTs}}, {upsert: true}));
+
+// Do an update-operator-style findAndModify to add a new document with _id=113.
+findAndModifyResult =
+ primaryColl.findAndModify({query: {_id: 113}, update: {$set: {a: emptyTs}}, upsert: true});
+assert.eq(findAndModifyResult, null);
+
+// Do a pipeline-style update to add a new document with _id=114.
+assert.commandWorked(primaryColl.update({_id: 114}, [{$addFields: {a: emptyTs}}], {upsert: true}));
+
+// Do a pipeline-style findAndModify to add a new document with _id=115.
+findAndModifyResult = primaryColl.findAndModify(
+ {query: {_id: 115}, update: [{$addFields: {a: emptyTs}}], upsert: true});
+assert.eq(findAndModifyResult, null);
+
+// Do a pipeline-style update with $internalApplyOplogUpdate to add a new document _id=116.
+assert.commandWorked(primaryColl.update(
+ {_id: 116},
+ [{$_internalApplyOplogUpdate: {oplogUpdate: {$v: 2, diff: {i: {a: emptyTs}}}}}],
+ {upsert: true}));
+
+// Do a pipeline-style findAndModify with $internalApplyOplogUpdate to add a new document _id=117.
+findAndModifyResult = primaryColl.findAndModify({
+ query: {_id: 117},
+ update: [{$_internalApplyOplogUpdate: {oplogUpdate: {$v: 2, diff: {i: {a: emptyTs}}}}}],
+ upsert: true
+});
+assert.eq(findAndModifyResult, null);
+
+rst.awaitReplication();
+
+// Verify that all the insert, update, and findAndModify commands behaved the way we expect and that
+// they all were replicated correctly to the secondaries.
+for (let i = 101; i <= 117; ++i) {
+ let result = primaryColl.findOne({_id: i});
+ let secondaryResult = secondaryColl.findOne({_id: i});
+
+ assert.eq(tojson(result), tojson(secondaryResult), "_id=" + i);
+
+ if (i >= 106) {
+ assert.eq(tojson(result.a), tojson(emptyTs), "_id=" + i);
+ } else {
+ assert.neq(tojson(result.a), tojson(emptyTs), "_id=" + i);
+ }
+}
+
+// Insert a document with _id=Timestamp(0,0).
+assert.commandWorked(primaryColl.insert({_id: emptyTs, a: 9}));
+
+// Verify the document we just inserted can be retrieved using the filter "{_id: Timestamp(0,0)}".
+let result = primaryColl.findOne({_id: emptyTs});
+assert.eq(tojson(result._id), tojson(emptyTs), "_id=" + tojson(emptyTs));
+assert.eq(tojson(result.a), tojson(9), "_id=" + tojson(emptyTs));
+
+// Do a replacement-style update on the document.
+assert.commandWorked(primaryColl.update({_id: emptyTs}, {_id: emptyTs, a: emptyTs}));
+
+// Verify the document we just updated can still be retrieved using "{_id: Timestamp(0,0)}" and
+// verify that field "a" was set to the current timestamp.
+result = primaryColl.findOne({_id: emptyTs});
+assert.eq(tojson(result._id), tojson(emptyTs), "_id=" + tojson(emptyTs));
+assert.neq(tojson(result.a), tojson(emptyTs), "_id=" + tojson(emptyTs));
+
+rst.awaitReplication();
+
+// Verify that the document was replicated correctly to the secondaries.
+let secondaryResult = secondaryColl.findOne({_id: emptyTs});
+assert.eq(tojson(result), tojson(secondaryResult), "_id=" + tojson(emptyTs));
+
+rst.stopSet();
+}());
diff --git a/jstests/replsets/ignore_dbcheck_in_initial_sync.js b/jstests/replsets/ignore_dbcheck_in_initial_sync.js
index 4f1557e4d85..8efc8dcabf4 100644
--- a/jstests/replsets/ignore_dbcheck_in_initial_sync.js
+++ b/jstests/replsets/ignore_dbcheck_in_initial_sync.js
@@ -57,6 +57,7 @@ replSet.reInitiate();
initialSyncHangBeforeSplittingControlFlowFailPoint.wait();
+// TODO SERVER-89921: Uncomment validateMode once the relevant tickets are backported.
runDbCheck(replSet,
primaryDb,
collName,
@@ -65,11 +66,17 @@ runDbCheck(replSet,
maxDocsPerBatch //, validateMode: "dataConsistencyAndMissingIndexKeysCheck"
});
+// Wait until the primary finished dbcheck before turning off the initial sync failpoint so that the
+// initial sync node would need to apply (ignore) dbCheckStop in initial sync.
+checkHealthLog(primaryHealthlog, {"operation": "dbCheckStop"}, 1);
+
assert.commandWorked(initialSyncNode.adminCommand(
{configureFailPoint: 'initialSyncHangBeforeSplittingControlFlow', mode: 'off'}));
replSet.waitForState(initialSyncNode, ReplSetTest.State.SECONDARY);
+// TODO SERVER-89921: Uncomment all of the following checkHealthLog once the relevant tickets are
+// backported.
// Check that the primary logged an error health log entry for each document with missing index key.
// checkHealthLog(primaryHealthlog, logQueries.missingIndexKeysQuery, nDocs);
// Check that the primary does not have other error/warning entries.
diff --git a/jstests/replsets/ignore_dbcheck_in_rollback.js b/jstests/replsets/ignore_dbcheck_in_rollback.js
new file mode 100644
index 00000000000..239bf0bfc94
--- /dev/null
+++ b/jstests/replsets/ignore_dbcheck_in_rollback.js
@@ -0,0 +1,104 @@
+/*
+ * This test makes sure the 'dbcheck' command is ignored during rollback and a warning health log
+ * entry is logged.
+ * @tags: [
+ * featureFlagSecondaryIndexChecksInDbCheck
+ * ]
+ */
+
+load("jstests/libs/fail_point_util.js");
+load("jstests/replsets/libs/rollback_test.js");
+load("jstests/replsets/libs/dbcheck_utils.js");
+
+// This test injects inconsistencies between replica set members; do not fail because of expected
+// dbHash differences.
+TestData.skipCollectionAndIndexValidation = true;
+TestData.skipCheckDBHashes = true;
+
+const dbName = "ignore_dbcheck_in_rollback";
+const collName = "ignore_dbcheck_in_rollback-collection";
+
+const replSet = new ReplSetTest({
+ name: jsTestName(),
+ nodes: [{}, {}, {rsConfig: {priority: 0}}],
+ useBridge: true,
+ settings: {chainingAllowed: false}
+});
+replSet.startSet();
+replSet.initiateWithHighElectionTimeout();
+
+let primary = replSet.getPrimary();
+let primaryDB = primary.getDB(dbName);
+const secondary = replSet.getSecondary();
+const secondaryDb = secondary.getDB(dbName);
+const primaryColl = primaryDB.getCollection(collName);
+
+const nDocs = 200;
+resetAndInsert(replSet, primaryDB, collName, nDocs);
+assert.commandWorked(
+ primaryDB.runCommand({createIndexes: collName, indexes: [{key: {a: 1}, name: "a_1"}]}));
+replSet.awaitReplication();
+assert.eq(primaryColl.find({}).count(), nDocs);
+
+// Set up inconsistency.
+const skipUnindexingDocumentWhenDeleted =
+ configureFailPoint(primaryDB, "skipUnindexingDocumentWhenDeleted", {indexName: "a_1"});
+jsTestLog("Deleting docs");
+const stableTimestamp = assert.commandWorked(primaryColl.deleteMany({}));
+
+replSet.awaitReplication();
+assert.eq(primaryColl.find({}).count(), 0);
+assert.eq(secondaryDb.getCollection(collName).find({}).count(), 0);
+
+const rollbackTest = new RollbackTest(jsTestName(), replSet);
+primary = rollbackTest.getPrimary();
+primaryDB = primary.getDB(dbName);
+
+// Hold stable timestamp.
+const stableTimestampFailPoint = configureFailPoint(
+ primary, "holdStableTimestampAtSpecificTimestamp", {timestamp: stableTimestamp});
+
+// TODO SERVER-89921: Uncomment validateMode and secondaryIndex once the relevant tickets are
+// backported.
+runDbCheck(rollbackTest,
+ primaryDB,
+ collName,
+ {
+ maxDocsPerBatch: 20 //, validateMode: "extraIndexKeysCheck", secondaryIndex: "a_1"
+ });
+
+// TODO SERVER-89921: Uncomment checkHealthLog once the relevant tickets are backported.
+// Check that the old primary prior to transitioning to rollback has start, batch, and stop entries.
+const oldPrimaryHealthLog = primary.getDB("local").system.healthlog;
+// checkHealthLog(oldPrimaryHealthLog, logQueries.recordNotFoundQuery, nDocs);
+checkHealthLog(oldPrimaryHealthLog, logQueries.startStopQuery, 2);
+
+const rollbackNode = rollbackTest.transitionToRollbackOperations();
+rollbackTest.transitionToSyncSourceOperationsBeforeRollback();
+rollbackTest.transitionToSyncSourceOperationsDuringRollback();
+rollbackTest.transitionToSteadyStateOperations({skipDataConsistencyChecks: true});
+
+primary = rollbackTest.getPrimary();
+const primaryHealthLog = primary.getDB("local").system.healthlog;
+const rollbackNodeHealthLog = rollbackNode.getDB("local").system.healthlog;
+
+// TODO SERVER-89921: Change the # of logs to check once the relevant tickets are backported.
+// Check that the start, batch (10 batches), and stop entries on the rollback node are all warning
+// logs.
+checkHealthLog(rollbackNodeHealthLog, logQueries.duringStableRecovery, 3); // 12
+// The rollback node will contain start, batch, and stop entries from when it was primary. Check
+// that there are no extra error logs other than recordNotFound.
+checkHealthLog(rollbackNodeHealthLog, logQueries.startStopQuery, 2);
+// checkHealthLog(rollbackNodeHealthLog, logQueries.recordNotFoundQuery, nDocs);
+checkHealthLog(rollbackNodeHealthLog, logQueries.allErrorsOrWarningsQuery, 3); // nDocs + 12
+
+// TODO SERVER-89921: Uncomment the following checkHealthLog once the relevant tickets are
+// backported.
+// Check that the primary only has the batch inconsistent entries from when it was secondary.
+// checkHealthLog(primaryHealthLog, logQueries.inconsistentBatchQuery, 10);
+// Check that the primary does not have other error/warning entries.
+// checkHealthLog(primaryHealthLog, logQueries.allErrorsOrWarningsQuery, 10);
+
+skipUnindexingDocumentWhenDeleted.off();
+stableTimestampFailPoint.off();
+rollbackTest.stop(null /* checkDataConsistencyOptions */, true /* skipDataConsistencyCheck */);
diff --git a/jstests/replsets/ignore_dbcheck_in_startup_recovery.js b/jstests/replsets/ignore_dbcheck_in_startup_recovery.js
new file mode 100644
index 00000000000..ff770e38ec4
--- /dev/null
+++ b/jstests/replsets/ignore_dbcheck_in_startup_recovery.js
@@ -0,0 +1,101 @@
+/**
+ * Test that dbcheck command will be ignored during startup recovery.
+ *
+ * @tags: [
+ * featureFlagSecondaryIndexChecksInDbCheck, requires_persistence
+ * ]
+ */
+
+load("jstests/libs/fail_point_util.js");
+load("jstests/replsets/libs/dbcheck_utils.js");
+
+// This test injects inconsistencies between replica set members; do not fail because of expected
+// dbHash differences.
+TestData.skipCollectionAndIndexValidation = true;
+TestData.skipCheckDBHashes = true;
+
+const dbName = "ignore_dbcheck_in_startup_recovery";
+const collName = "ignore_dbcheck_in_startup_recovery-collection";
+
+const replSet = new ReplSetTest({
+ name: jsTestName(),
+ nodes: 2,
+ nodeOptions: {setParameter: {dbCheckHealthLogEveryNBatches: 1}}
+});
+replSet.startSet();
+replSet.initiateWithHighElectionTimeout();
+
+let primary = replSet.getPrimary();
+const primaryDb = primary.getDB(dbName);
+let secondary = replSet.getSecondary();
+const secondaryDb = secondary.getDB(dbName);
+const primaryColl = primaryDb.getCollection(collName);
+
+const nDocs = 200;
+resetAndInsert(replSet, primaryDb, collName, nDocs);
+assert.commandWorked(
+ primaryDb.runCommand({createIndexes: collName, indexes: [{key: {a: 1}, name: "a_1"}]}));
+replSet.awaitReplication();
+assert.eq(primaryColl.find({}).count(), nDocs);
+
+// Set up inconsistency.
+const skipUnindexingDocumentWhenDeleted =
+ configureFailPoint(primaryDb, "skipUnindexingDocumentWhenDeleted", {indexName: "a_1"});
+jsTestLog("Deleting docs");
+const stableTimestamp = assert.commandWorked(primaryColl.deleteMany({}));
+
+replSet.awaitReplication();
+assert.eq(primaryColl.find({}).count(), 0);
+assert.eq(secondaryDb.getCollection(collName).find({}).count(), 0);
+
+configureFailPoint(primary, "holdStableTimestampAtSpecificTimestamp", {timestamp: stableTimestamp});
+
+// TODO SERVER-89921: Uncomment minKey, maxKey, validateMode and secondaryIndex once the relevant
+// tickets are backported.
+runDbCheck(replSet,
+ primaryDb,
+ collName,
+ {
+ maxDocsPerBatch: 20,
+ batchWriteConcern: {w: 2},
+ // minKey: {a: "0"},
+ // maxKey: {a: "199"},
+ // , validateMode: "extraIndexKeysCheck", secondaryIndex: "a_1"
+ },
+ true /*awaitCompletion*/);
+
+// Wait to make sure that the secondary applied the stop entry before the ungraceful shutdown.
+replSet.awaitNodesAgreeOnAppliedOpTime();
+
+// Perform ungraceful shutdown of the secondary node and do not clean the db path directory.
+replSet.stop(
+ 1, 9, {allowedExitCode: MongoRunner.EXIT_SIGKILL}, {forRestart: true, skipValidation: true});
+
+secondary = replSet.start(secondary,
+ {
+ setParameter: {
+ "failpoint.stopReplProducer": tojson({"mode": "alwaysOn"}),
+ },
+ },
+ {noCleanData: true});
+
+primary = replSet.getPrimary();
+
+const primaryHealthLog = primary.getDB("local").system.healthlog;
+const secondaryHealthLog = secondary.getDB("local").system.healthlog;
+
+// Check that the start and batch entries are warning logs since the node skips dbcheck during
+// startup recovery.
+checkHealthLog(secondaryHealthLog, logQueries.duringStableRecovery, 3);
+// Check that the initial sync node does not have other info or error/warning entries.
+checkHealthLog(secondaryHealthLog, logQueries.infoBatchQuery, 0);
+checkHealthLog(secondaryHealthLog, logQueries.allErrorsOrWarningsQuery, 3);
+
+// TODO SERVER-89921: Uncomment checkHealthLog once the relevant tickets are backported.
+// Check that the primary logged an error health log entry for each document with missing index key.
+// checkHealthLog(primaryHealthLog, logQueries.recordNotFoundQuery, nDocs);
+// Check that the primary does not have other error/warning entries.
+// checkHealthLog(primaryHealthLog, logQueries.allErrorsOrWarningsQuery, nDocs);
+
+skipUnindexingDocumentWhenDeleted.off();
+replSet.stopSet();
diff --git a/jstests/replsets/libs/dbcheck_utils.js b/jstests/replsets/libs/dbcheck_utils.js
index 5bf564b54b0..b138322a07e 100644
--- a/jstests/replsets/libs/dbcheck_utils.js
+++ b/jstests/replsets/libs/dbcheck_utils.js
@@ -32,12 +32,26 @@ const logQueries = {
},
duringInitialSyncQuery:
{severity: "warning", "msg": "cannot execute dbcheck due to ongoing initial sync"},
+ duringStableRecovery:
+ {severity: "warning", "msg": "cannot execute dbcheck due to ongoing stable recovering"},
errorQuery: {"severity": "error"},
warningQuery: {"severity": "warning"},
infoOrErrorQuery:
{$or: [{"severity": "info", "operation": "dbCheckBatch"}, {"severity": "error"}]},
infoBatchQuery: {"severity": "info", "operation": "dbCheckBatch"},
inconsistentBatchQuery: {"severity": "error", "msg": "dbCheck batch inconsistent"},
+ startStopQuery: {
+ $or: [
+ {"operation": "dbCheckStart", "severity": "info"},
+ {"operation": "dbCheckStop", "severity": "info"}
+ ]
+ },
+ writeConcernErrorQuery: {severity: "error", "msg": "dbCheck failed waiting for writeConcern"},
+ skipApplyingBatchOnSecondaryQuery: {
+ severity: "warning",
+ "msg":
+ "skipping applying dbcheck batch because the 'skipApplyingDbCheckBatchOnSecondary' parameter is on",
+ },
};
// Apply function on all secondary nodes except arbiters.
@@ -430,7 +444,7 @@ const assertForDbCheckErrorsForAllNodes =
* Utility for checking if the featureFlagSecondaryIndexChecksInDbCheck is on.
*/
function checkSecondaryIndexChecksInDbCheckFeatureFlagEnabled(conn) {
- return FeatureFlagUtil.isPresentAndEnabled(conn, 'SecondaryIndexChecksInDbCheck');
+ return FeatureFlagUtil.isEnabled(conn.getDB("admin"), 'SecondaryIndexChecksInDbCheck');
}
function checkNumSnapshots(debugBuild, expectedNumSnapshots) {
diff --git a/jstests/replsets/libs/rollback_test.js b/jstests/replsets/libs/rollback_test.js
index 40b602e5b61..d6838deffcf 100644
--- a/jstests/replsets/libs/rollback_test.js
+++ b/jstests/replsets/libs/rollback_test.js
@@ -543,11 +543,11 @@ function RollbackTest(name = "RollbackTest", replSet) {
return curPrimary;
};
- this.stop = function(checkDataConsistencyOptions) {
+ this.stop = function(checkDataConsistencyOptions, skipDataConsistencyCheck = false) {
const start = new Date();
restartServerReplication(tiebreakerNode);
rst.awaitReplication();
- if (!doneConsistencyChecks) {
+ if (!doneConsistencyChecks && !skipDataConsistencyCheck) {
this.checkDataConsistency(checkDataConsistencyOptions);
}
transitionIfAllowed(State.kStopped);
diff --git a/jstests/replsets/log_wt_stats_during_secondary_oplog_application.js b/jstests/replsets/log_wt_stats_during_secondary_oplog_application.js
new file mode 100644
index 00000000000..d7a9d8858de
--- /dev/null
+++ b/jstests/replsets/log_wt_stats_during_secondary_oplog_application.js
@@ -0,0 +1,46 @@
+/**
+ * Tests that the server prints storage statistics along with slow secondary oplog application
+ * logs.
+ *
+ * @tags: [requires_wiredtiger, requires_persistence]
+ */
+
+load("jstests/libs/fail_point_util.js");
+load("jstests/replsets/rslib.js");
+
+const name = "log_wt_stats_during_secondary_oplog_application";
+const rst = new ReplSetTest({nodes: [{}, {rsConfig: {priority: 0}}]});
+rst.startSet();
+rst.initiate();
+
+let primary = rst.getPrimary();
+let secondary = rst.getSecondary();
+
+// Create a collection and write some data to it.
+assert.commandWorked(primary.getDB(name).createCollection("readFromDisk"));
+assert.commandWorked(primary.getDB(name)["readFromDisk"].insert({x: "value"}));
+
+// Cleanly shut down the secondary and restart it. This will clear the local cache and ensure
+// that we need to read from disk the next time we write to the collection, resulting in
+// actual storage statistics instead of empty storage statistics.
+rst.stop(secondary, undefined /* signal */, {} /* opts */, {forRestart: true});
+rst.start(secondary, {} /* options */, true /* restart */, false /* waitForHealth */);
+
+// Ensure secondary completes startup recovery.
+secondary = rst.getSecondary();
+
+// Set profiling level to 2 so that we log all operations.
+assert.commandWorked(secondary.getDB(name).setProfilingLevel(2, 0));
+
+// Issue a new write to the primary that will require reading from disk.
+assert.commandWorked(primary.getDB(name)["readFromDisk"].insert({x: "sloth"}));
+rst.awaitReplication();
+
+// Make sure we log that insert op.
+const slowLogLine = checkLog.containsLog(secondary, "sloth");
+jsTestLog(slowLogLine);
+
+// Make sure we've logged a storage statistic as well.
+assert(slowLogLine.includes("bytesRead"));
+
+rst.stopSet();
diff --git a/jstests/replsets/nodes_eventually_sync_from_closer_data_center.js b/jstests/replsets/nodes_eventually_sync_from_closer_data_center.js
index 8ba24bdaa9b..c29e7705614 100644
--- a/jstests/replsets/nodes_eventually_sync_from_closer_data_center.js
+++ b/jstests/replsets/nodes_eventually_sync_from_closer_data_center.js
@@ -105,7 +105,13 @@ assert.soon(() => {
const syncSourcePingTime = replSetGetStatus.members[0].pingMs;
const receivedSyncSourceHb = (syncSourcePingTime > 60);
- return (receivedCentralHb && receivedSyncSourceHb);
+ // Wait for enough heartbeat's from the desired sync source so that our understanding of the
+ // ping time to that node is at least 'changeSyncSourceThresholdMillis' less than the ping time
+ // to our current sync source.
+ const centralSecondaryPingTime = replSetGetStatus.members[1].pingMs;
+ const exceedsChangeSyncSourceThreshold = (syncSourcePingTime - centralSecondaryPingTime > 5);
+
+ return (receivedCentralHb && receivedSyncSourceHb && exceedsChangeSyncSourceThreshold);
});
const replSetGetStatus = assert.commandWorked(testNode.adminCommand({replSetGetStatus: 1}));
diff --git a/jstests/replsets/reconstruct_prepared_transactions_initial_sync.js b/jstests/replsets/reconstruct_prepared_transactions_initial_sync.js
index 99018d864c5..56169ee402c 100644
--- a/jstests/replsets/reconstruct_prepared_transactions_initial_sync.js
+++ b/jstests/replsets/reconstruct_prepared_transactions_initial_sync.js
@@ -59,6 +59,10 @@ assert.commandWorked(sessionColl1.insert({_id: 1}));
assert.commandWorked(sessionColl2.insert({_id: 2}));
assert.commandWorked(sessionColl3.insert({_id: 3}));
assert.commandWorked(sessionColl3.insert({_id: 4}));
+assert.commandWorked(sessionColl3.insert({_id: 5}));
+
+// Add a validator so we can make sure validation doesn't cause initial sync to fail.
+assert.commandWorked(testDB.runCommand({collMod: collName, validator: {b: {$exists: false}}}));
jsTestLog("Preparing three transactions");
@@ -111,7 +115,7 @@ jsTestLog("Running operations while collection cloning is paused");
// Perform writes while collection cloning is paused so that we know they must be applied during
// the oplog application stage of initial sync.
-assert.commandWorked(testColl.insert({_id: 5}));
+assert.commandWorked(testColl.insert({_id: 999}));
let session4 = primary.startSession();
let sessionDB4 = session4.getDatabase(dbName);
@@ -125,6 +129,22 @@ session4.startTransaction();
assert.commandWorked(sessionColl4.update({_id: 4}, {_id: 4, a: 1}));
const prepareTimestamp4 = PrepareHelpers.prepareTransaction(session4, {w: 1});
+let session5 = primary.startSession();
+let sessionDB5 = session5.getDatabase(dbName);
+const sessionColl5 = sessionDB5.getCollection(collName);
+
+jsTestLog("Preparing the fifth transaction");
+
+// Prepare a transaction that would fail validation while collection cloning is paused so that its
+// oplog entry must be applied during the oplog application phase of initial sync.
+session5.startTransaction();
+assert.commandWorked(sessionDB5.runCommand({
+ update: collName,
+ updates: [{q: {_id: 5}, u: {_id: 5, a: 1, b: 2}}],
+ bypassDocumentValidation: true
+}));
+const prepareTimestamp5 = PrepareHelpers.prepareTransaction(session5, {w: 1});
+
jsTestLog("Resuming initial sync");
// Resume initial sync.
@@ -145,7 +165,7 @@ const secondaryColl = secondary.getDB(dbName).getCollection(collName);
// changes to the documents from any of the prepared transactions after initial sync. Also, make
// sure that the writes that happened when collection cloning was paused happened.
const res = secondaryColl.find().sort({_id: 1}).toArray();
-assert.eq(res, [{_id: 1}, {_id: 2}, {_id: 3}, {_id: 4}, {_id: 5}], res);
+assert.eq(res, [{_id: 1}, {_id: 2}, {_id: 3}, {_id: 4}, {_id: 5}, {_id: 999}], res);
jsTestLog("Checking that the first transaction is properly prepared");
@@ -173,9 +193,15 @@ jsTestLog("Committing the fourth transaction");
assert.commandWorked(PrepareHelpers.commitTransaction(session4, prepareTimestamp4));
replTest.awaitReplication();
+jsTestLog("Committing the fifth transaction");
+
+assert.commandWorked(PrepareHelpers.commitTransaction(session5, prepareTimestamp5));
+replTest.awaitReplication();
+
// Make sure that we can see the data from a committed transaction on the secondary if it was
// applied during secondary oplog application.
-assert.docEq(secondaryColl.findOne({_id: 4}), {_id: 4, a: 1});
+assert.docEq({_id: 4, a: 1}, secondaryColl.findOne({_id: 4}));
+assert.docEq({_id: 5, a: 1, b: 2}, secondaryColl.findOne({_id: 5}));
jsTestLog("Stepping up the secondary");
@@ -271,4 +297,4 @@ assert.commandWorked(sessionDB3.adminCommand(
assert.eq(testColl.find({_id: 3}).toArray(), [{_id: 3}]);
replTest.stopSet();
-})(); \ No newline at end of file
+})();
diff --git a/jstests/replsets/tenant_migration_abort_forget_retry.js b/jstests/replsets/tenant_migration_abort_forget_retry.js
deleted file mode 100644
index 21913140ba6..00000000000
--- a/jstests/replsets/tenant_migration_abort_forget_retry.js
+++ /dev/null
@@ -1,119 +0,0 @@
-/**
- * Starts a tenant migration that aborts, either due to the
- * abortTenantMigrationBeforeLeavingBlockingState failpoint or due to receiving donorAbortMigration,
- * and then issues a donorForgetMigration command. Finally, starts a second tenant migration with
- * the same tenantId as the aborted migration, and expects this second migration to go through.
- *
- * @tags: [
- * incompatible_with_eft,
- * incompatible_with_macos,
- * incompatible_with_windows_tls,
- * requires_majority_read_concern,
- * requires_persistence,
- * serverless,
- * ]
- */
-
-(function() {
-"use strict";
-
-load("jstests/libs/fail_point_util.js");
-load("jstests/libs/parallelTester.js");
-load("jstests/libs/uuid_util.js");
-load("jstests/replsets/libs/tenant_migration_test.js");
-load("jstests/replsets/libs/tenant_migration_util.js");
-
-const kTenantIdPrefix = "testTenantId";
-let testNum = 0;
-
-function makeTenantId() {
- return kTenantIdPrefix + testNum++;
-}
-
-const tenantMigrationTest =
- new TenantMigrationTest({name: jsTestName(), quickGarbageCollection: true});
-
-(() => {
- const migrationId1 = extractUUIDFromObject(UUID());
- const migrationId2 = extractUUIDFromObject(UUID());
- const tenantId = makeTenantId();
-
- // Start a migration with the "abortTenantMigrationBeforeLeavingBlockingState" failPoint
- // enabled. The migration will abort as a result, and a status of "kAborted" should be returned.
- jsTestLog(
- "Starting a migration that is expected to abort due to setting abortTenantMigrationBeforeLeavingBlockingState failpoint. migrationId: " +
- migrationId1 + ", tenantId: " + tenantId);
- const donorPrimary = tenantMigrationTest.getDonorPrimary();
- const abortFp =
- configureFailPoint(donorPrimary, "abortTenantMigrationBeforeLeavingBlockingState");
- TenantMigrationTest.assertAborted(tenantMigrationTest.runMigration(
- {migrationIdString: migrationId1, tenantId: tenantId}, {automaticForgetMigration: false}));
- abortFp.off();
-
- // Forget the aborted migration.
- jsTestLog("Forgetting aborted migration with migrationId: " + migrationId1);
- assert.commandWorked(tenantMigrationTest.forgetMigration(migrationId1));
-
- // Try running a new migration with the same tenantId. It should succeed, since the previous
- // migration with the same tenantId was aborted.
- jsTestLog("Attempting to run a new migration with the same tenantId. New migrationId: " +
- migrationId2 + ", tenantId: " + tenantId);
- TenantMigrationTest.assertCommitted(
- tenantMigrationTest.runMigration({migrationIdString: migrationId2, tenantId: tenantId}));
- tenantMigrationTest.waitForMigrationGarbageCollection(migrationId2, tenantId);
-})();
-
-(() => {
- const migrationId1 = extractUUIDFromObject(UUID());
- const migrationId2 = extractUUIDFromObject(UUID());
- const tenantId = makeTenantId();
-
- jsTestLog(
- "Starting a migration that is expected to abort in blocking state due to receiving donorAbortMigration. migrationId: " +
- migrationId1 + ", tenantId: " + tenantId);
-
- const donorPrimary = tenantMigrationTest.getDonorPrimary();
- let fp = configureFailPoint(donorPrimary, "pauseTenantMigrationBeforeLeavingBlockingState");
- assert.commandWorked(
- tenantMigrationTest.startMigration({migrationIdString: migrationId1, tenantId: tenantId}));
-
- fp.wait();
-
- const donorRstArgs = TenantMigrationUtil.createRstArgs(tenantMigrationTest.getDonorRst());
- const tryAbortThread = new Thread(TenantMigrationUtil.tryAbortMigrationAsync,
- {migrationIdString: migrationId1, tenantId: tenantId},
- donorRstArgs,
- TenantMigrationUtil.runTenantMigrationCommand);
- tryAbortThread.start();
-
- // Wait for donorAbortMigration command to start.
- assert.soon(() => {
- const res = assert.commandWorked(
- donorPrimary.adminCommand({currentOp: true, desc: "tenant donor migration"}));
- const op = res.inprog.find(op => extractUUIDFromObject(op.instanceID) === migrationId1);
- return op.receivedCancellation;
- });
-
- fp.off();
-
- tryAbortThread.join();
- assert.commandWorked(tryAbortThread.returnData());
-
- TenantMigrationTest.assertAborted(tenantMigrationTest.waitForMigrationToComplete(
- {migrationIdString: migrationId1, tenantId: tenantId}));
-
- // Forget the aborted migration.
- jsTestLog("Forgetting aborted migration with migrationId: " + migrationId1);
- assert.commandWorked(tenantMigrationTest.forgetMigration(migrationId1));
-
- // Try running a new migration with the same tenantId. It should succeed, since the previous
- // migration with the same tenantId was aborted.
- jsTestLog("Attempting to run a new migration with the same tenantId. New migrationId: " +
- migrationId2 + ", tenantId: " + tenantId);
- TenantMigrationTest.assertCommitted(
- tenantMigrationTest.runMigration({migrationIdString: migrationId2, tenantId: tenantId}));
- tenantMigrationTest.waitForMigrationGarbageCollection(migrationId2, tenantId);
-})();
-
-tenantMigrationTest.stop();
-})();
diff --git a/jstests/replsets/timeseries_mixed_schema_bucket_initial_sync.js b/jstests/replsets/timeseries_mixed_schema_bucket_initial_sync.js
new file mode 100644
index 00000000000..c1031db50d2
--- /dev/null
+++ b/jstests/replsets/timeseries_mixed_schema_bucket_initial_sync.js
@@ -0,0 +1,74 @@
+/**
+ * Tests initial sync with a time-series collection that contains mixed-schema buckets.
+ *
+ * @tags: [
+ * requires_fcv_60,
+ * ]
+ */
+(function() {
+"use strict";
+
+load("jstests/core/timeseries/libs/timeseries.js"); // For 'TimeseriesTest'.
+
+TestData.skipEnforceTimeseriesBucketsAreAlwaysCompressedOnValidate = true;
+
+const replTest = new ReplSetTest({nodes: 1});
+replTest.startSet();
+replTest.initiate();
+
+const primary = replTest.getPrimary();
+const db = primary.getDB(jsTestName());
+const coll = db.coll;
+const bucketsColl = db["system.buckets." + coll.getName()];
+
+const bucket = {
+ _id: ObjectId("65a6eb806ffc9fa4280ecac4"),
+ control: {
+ version: NumberInt(1),
+ min: {
+ _id: ObjectId("65a6eba7e6d2e848e08c3750"),
+ t: ISODate("2024-01-16T20:48:00Z"),
+ a: 1,
+ },
+ max: {
+ _id: ObjectId("65a6eba7e6d2e848e08c3751"),
+ t: ISODate("2024-01-16T20:48:39.448Z"),
+ a: "a",
+ },
+ },
+ meta: 0,
+ data: {
+ _id: {
+ 0: ObjectId("65a6eba7e6d2e848e08c3750"),
+ 1: ObjectId("65a6eba7e6d2e848e08c3751"),
+ },
+ t: {
+ 0: ISODate("2024-01-16T20:48:39.448Z"),
+ 1: ISODate("2024-01-16T20:48:39.448Z"),
+ },
+ a: {
+ 0: "a",
+ 1: 1,
+ },
+ }
+};
+
+assert.commandWorked(
+ db.createCollection(coll.getName(), {timeseries: {timeField: "t", metaField: "m"}}));
+assert.commandWorked(
+ db.runCommand({collMod: coll.getName(), timeseriesBucketsMayHaveMixedSchemaData: true}));
+assert.commandWorked(bucketsColl.insert(bucket));
+
+const secondary = replTest.add();
+replTest.reInitiate();
+replTest.waitForState(secondary, ReplSetTest.State.SECONDARY);
+replTest.awaitReplication();
+
+const primaryColl = primary.getDB(db.getName())[bucketsColl.getName()];
+const secondaryColl = secondary.getDB(db.getName())[bucketsColl.getName()];
+
+assert(TimeseriesTest.bucketsMayHaveMixedSchemaData(primaryColl));
+assert(TimeseriesTest.bucketsMayHaveMixedSchemaData(secondaryColl));
+
+replTest.stopSet();
+})();
diff --git a/jstests/sharding/agg_union_with_lookup.js b/jstests/sharding/agg_union_with_lookup.js
new file mode 100644
index 00000000000..587f3f85d20
--- /dev/null
+++ b/jstests/sharding/agg_union_with_lookup.js
@@ -0,0 +1,76 @@
+/**
+ * SERVER-88439 - when run against a sharded collection, this query caused a use after free
+ * when running getMore against the returned cursor.
+ * @tags: [
+ * # Needs $lookup to support sharded foreign collections.
+ * requires_fcv_51,
+ * ]
+ */
+
+function insertDocs(coll) {
+ assert.commandWorked(coll.insert([
+ {v: 1, y: -3},
+ {v: 2, y: -2},
+ {v: 3, y: -1},
+ {v: 4, y: 1},
+ {v: 5, y: 2},
+ {v: 6, y: 3},
+ {v: 7, y: 4}
+ ]));
+}
+
+const st = new ShardingTest({shards: 2, mongos: 1});
+
+const conn = st.s;
+
+// Setup the collection.
+const coll = conn.getCollection("test." + jsTestName() + "_1");
+coll.drop();
+insertDocs(coll);
+assert.commandWorked(coll.createIndex({y: 1}));
+st.shardColl(coll,
+ /* key */ {y: 1},
+ /* split at */ {y: 0},
+ /* move chunk containing */ {y: 1},
+ /* db */ coll.getDB().getName(),
+ /* waitForDelete */ true);
+
+// Construct the command that causes the problem. The problem was observed during the
+// subsequent getMore.
+const cmd = {
+ aggregate: coll.getName(),
+ pipeline: [
+ {$unionWith: {
+ coll: coll.getName(),
+ pipeline: [
+ {$unionWith: {
+ coll: coll.getName(),
+ pipeline: [
+ {$lookup: {
+ from: coll.getName(),
+ as: "lookedUp",
+ localField: "y",
+ foreignField: "y",
+ }}
+ ],
+ }},
+ ]
+ }},
+ ],
+ cursor: {batchSize: 1},
+};
+
+const initialResult = assert.commandWorked(coll.runCommand(cmd));
+const cursor = initialResult.cursor;
+
+const getMore = {
+ getMore: cursor.id,
+ collection: coll.getName(),
+ batchSize: 1000
+};
+const getMoreResult = assert.commandWorked(coll.runCommand(getMore));
+const allResults = cursor.firstBatch.concat(getMoreResult.cursor.nextBatch);
+
+assert.eq(allResults.length, 21);
+
+st.stop();
diff --git a/jstests/sharding/all_collection_stats.js b/jstests/sharding/all_collection_stats.js
index 2fd89236e70..1635d6f0573 100644
--- a/jstests/sharding/all_collection_stats.js
+++ b/jstests/sharding/all_collection_stats.js
@@ -9,6 +9,47 @@
(function() {
'use strict';
+function checkResults(aggregationPipeline, checksToDo) {
+ assert.soon(() => {
+ const results = adminDb.aggregate(aggregationPipeline).toArray();
+ assert.lte(numCollections, results.length);
+
+ for (let i = 0; i < numCollections; i++) {
+ try {
+ const coll = "coll" + i;
+
+ // To check that the data retrieve from $_internalAllCollectionStats is correct we
+ // will call $collStats for each namespace to retrieve its storage stats and compare
+ // the two outputs.
+ const expectedResults = testDb.getCollection(coll)
+ .aggregate([{$collStats: {storageStats: {}}}])
+ .toArray();
+ assert.neq(null, expectedResults);
+ assert.eq(1, expectedResults.length);
+
+ let exists = false;
+ for (const data of results) {
+ const ns = data.ns;
+ if (dbName + "." + coll === ns) {
+ checksToDo(data, expectedResults);
+ exists = true;
+ break;
+ }
+ }
+ assert(exists,
+ "Expected to have $_internalAllCollectionStats results for coll" + i);
+ } catch (e) {
+ // As we perform two logical executions of $collStats they might return different
+ // storageSizes since WT may have rewritten the file during a checkpoint or
+ // background compaction. We retry the operation as it is a transient error.
+ jsTest.log(e);
+ return false;
+ }
+ }
+ return true;
+ });
+}
+
// Configure initial sharding cluster
const st = new ShardingTest({shards: 2});
const mongos = st.s;
@@ -16,56 +57,41 @@ const mongos = st.s;
const dbName = "test";
const testDb = mongos.getDB(dbName);
const adminDb = mongos.getDB("admin");
+const numCollections = 4;
// Insert sharded collections to validate the aggregation stage
-for (let i = 0; i < 10; i++) {
+for (let i = 0; i < (numCollections / 2); i++) {
const coll = "coll" + i;
assert(st.adminCommand({shardcollection: dbName + "." + coll, key: {skey: 1}}));
assert.commandWorked(testDb.getCollection(coll).insert({skey: i}));
}
// Insert some unsharded collections to validate the aggregation stage
-for (let i = 10; i < 20; i++) {
+for (let i = numCollections / 2; i < numCollections; i++) {
const coll = "coll" + i;
assert.commandWorked(testDb.getCollection(coll).insert({skey: i}));
}
-// Get output data
-const outputData =
- adminDb.aggregate([{$_internalAllCollectionStats: {stats: {storageStats: {}}}}]).toArray();
-assert.gte(outputData.length, 20);
-
// Testing for comparing each collection returned from $_internalAllCollectionStats to $collStats
-for (let i = 0; i < 20; i++) {
- const coll = "coll" + i;
- const expectedResults =
- testDb.getCollection(coll).aggregate([{$collStats: {storageStats: {}}}]).toArray();
- assert.neq(null, expectedResults);
- assert.eq(expectedResults.length, 1);
-
- let exists = false;
- for (const data of outputData) {
- const ns = data.ns;
- if (dbName + "." + coll === ns) {
- assert.eq(data.host, expectedResults[0].host);
- assert.eq(data.shard, expectedResults[0].shard);
- assert.eq(data.storageStats.size, expectedResults[0].storageStats.size);
- assert.eq(data.storageStats.count, expectedResults[0].storageStats.count);
- assert.eq(data.storageStats.avgObjSize, expectedResults[0].storageStats.avgObjSize);
- assert.eq(data.storageStats.storageSize, expectedResults[0].storageStats.storageSize);
- assert.eq(data.storageStats.freeStorageSize,
- expectedResults[0].storageStats.freeStorageSize);
- assert.eq(data.storageStats.nindexes, expectedResults[0].storageStats.nindexes);
- assert.eq(data.storageStats.totalIndexSize,
- expectedResults[0].storageStats.totalIndexSize);
- assert.eq(data.storageStats.totalSize, expectedResults[0].storageStats.totalSize);
- exists = true;
- break;
- }
- }
+(function testInternalAllCollectionStats() {
+ const aggregationPipeline = [{$_internalAllCollectionStats: {stats: {storageStats: {}}}}];
- assert(exists);
-}
+ const checksToDo = (left, right) => {
+ const msg = "Expected same output from $_internalAllCollectionStats and $collStats " +
+ "for same namespace";
+ assert.eq(left.host, right[0].host, msg);
+ assert.eq(left.shard, right[0].shard, msg);
+ assert.eq(left.storageStats.size, right[0].storageStats.size, msg);
+ assert.eq(left.storageStats.count, right[0].storageStats.count, msg);
+ assert.eq(left.storageStats.avgObjSize, right[0].storageStats.avgObjSize, msg);
+ assert.eq(left.storageStats.storageSize, right[0].storageStats.storageSize, msg);
+ assert.eq(left.storageStats.freeStorageSize, right[0].storageStats.freeStorageSize, msg);
+ assert.eq(left.storageStats.nindexes, right[0].storageStats.nindexes, msg);
+ assert.eq(left.storageStats.totalIndexSize, right[0].storageStats.totalIndexSize, msg);
+ assert.eq(left.storageStats.totalSize, right[0].storageStats.totalSize, msg);
+ };
+ checkResults(aggregationPipeline, checksToDo);
+})();
// Test valid query with empty specification
assert.commandWorked(
diff --git a/jstests/sharding/balance_random_data_distribution.js b/jstests/sharding/balance_random_data_distribution.js
new file mode 100644
index 00000000000..36c58f47ab9
--- /dev/null
+++ b/jstests/sharding/balance_random_data_distribution.js
@@ -0,0 +1,117 @@
+/*
+ * Test that the balancer redistributes data from multiple tracked collections across the
+ * cluster and it is able to converge within a limited amount of time.
+ * (Data amount & distribution, as well as per-collection maxChunkSize, are randomly chosen).
+ *
+ * @tags: [
+ * requires_fcv_60,
+ * does_not_support_stepdowns, # TODO SERVER-89797 remove this tag.
+ * ]
+ * */
+
+(function() {
+"use strict";
+
+load("jstests/libs/parallel_shell_helpers.js");
+
+const numShards = 2;
+Random.setRandomSeed();
+
+const st = new ShardingTest({shards: numShards});
+
+const clusterMaxChunkSizeMB = 8;
+const collectionBalancedTimeoutMS = 10 * 60 * 1000 /* 10min */;
+
+const numDatabases = numShards;
+const numCollInDB = 3;
+const dbNamePrefix = 'test_db_';
+const collNamePrefix = 'coll_';
+
+// 1. Setup an initial set of collections.
+for (let i = 0; i < numDatabases; ++i) {
+ const dbName = dbNamePrefix + `${i}`;
+ const primaryShardId = st[`shard${i}`].shardName;
+ // Avoid assigning the same primary shard for every collection.
+ assert.commandWorked(st.s.adminCommand({enableSharding: dbName, primaryShard: primaryShardId}));
+ for (let j = 0; j < numCollInDB; ++j) {
+ let collName = collNamePrefix + `${j}`;
+ const coll = st.s.getDB(dbName)[collName];
+ const ns = coll.getFullName();
+ // Use {_id: 1} as shard key to allow room for imbalance as documents get later inserted.
+ st.s.adminCommand({shardCollection: ns, key: {_id: 1}});
+ const collMaxChunkSizeMB = Random.randInt(clusterMaxChunkSizeMB - 1) + 1;
+ assert.commandWorked(st.s.adminCommand({
+ configureCollectionBalancing: ns,
+ chunkSize: collMaxChunkSizeMB,
+ }));
+ }
+}
+
+// 2. Launch the balancer and start multiple workers inserting random data into the existing
+// collections.
+st.startBalancer();
+
+function doBatchInserts(
+ numDatabases, dbNamePrefix, numCollInDB, collNamePrefix, clusterMaxChunkSizeMB) {
+ Random.setRandomSeed();
+ const numOfBatchInserts = 8;
+ const bigString =
+ 'X'.repeat(1024 * 1024 - 30); // Almost 1MB, to create documents of exactly 1MB
+
+ for (let i = 0; i < numOfBatchInserts; ++i) {
+ const dbName = dbNamePrefix + `${Random.randInt(numDatabases)}`;
+ let randomDB = db.getSiblingDB(dbName);
+ const collName = collNamePrefix + `${Random.randInt(numCollInDB)}`;
+ const coll = randomDB[collName];
+
+ const numDocs = Random.randInt(clusterMaxChunkSizeMB - 1) + 1;
+ let insertBulkOp = coll.initializeUnorderedBulkOp();
+ for (let i = 0; i < numDocs; ++i) {
+ insertBulkOp.insert({s: bigString});
+ }
+
+ assert.commandWorked(insertBulkOp.execute());
+ }
+}
+
+const numBackgroundBatchInserters = 5;
+let backgroundBatchInserters = [];
+for (let i = 0; i < numBackgroundBatchInserters; ++i) {
+ backgroundBatchInserters.push(startParallelShell(funWithArgs(doBatchInserts,
+ numDatabases,
+ dbNamePrefix,
+ numCollInDB,
+ collNamePrefix,
+ clusterMaxChunkSizeMB),
+ st.s.port));
+}
+
+// 3. Once the insertion workers are done, verify that the balancer may bring each tracked
+// collection to a "balanced" state within the deadline.
+for (let joinInserter of backgroundBatchInserters) {
+ joinInserter();
+}
+
+let testedAtLeastOneCollection = false;
+for (let i = 0; i < numDatabases; i++) {
+ const dbName = dbNamePrefix + `${i}`;
+ for (let j = 0; j < numCollInDB; j++) {
+ const ns = dbName + '.' + collNamePrefix + `${j}`;
+
+ const coll = st.s.getCollection(ns);
+ if (coll.countDocuments({}) === 0) {
+ // Skip empty collections
+ continue;
+ }
+ testedAtLeastOneCollection = true;
+
+ // Wait for collection to be considered balanced
+ sh.awaitCollectionBalance(coll, collectionBalancedTimeoutMS, 1000 /* 1s interval */);
+ sh.verifyCollectionIsBalanced(coll);
+ }
+
+ assert(testedAtLeastOneCollection);
+}
+
+st.stop();
+}());
diff --git a/jstests/sharding/balancer_defragmentation_merge_chunks.js b/jstests/sharding/balancer_defragmentation_merge_chunks.js
index 8bb0cb601d2..dc287f9772d 100644
--- a/jstests/sharding/balancer_defragmentation_merge_chunks.js
+++ b/jstests/sharding/balancer_defragmentation_merge_chunks.js
@@ -286,7 +286,8 @@ jsTest.log("Changed uuid causes defragmentation to restart");
}));
st.startBalancer();
// Reshard collection
- assert.commandWorked(db.adminCommand({reshardCollection: nss, key: {key2: 1}}));
+ assert.commandWorked(
+ db.adminCommand({reshardCollection: nss, key: {key2: 1}, numInitialChunks: 1}));
// Let defragementation run
clearFailPointOnConfigNodes("afterBuildingNextDefragmentationPhase");
defragmentationUtil.waitForEndOfDefragmentation(st.s, nss);
diff --git a/jstests/sharding/balancer_warns_draining_shards_blocked.js b/jstests/sharding/balancer_warns_draining_shards_blocked.js
new file mode 100644
index 00000000000..18af7a8cf59
--- /dev/null
+++ b/jstests/sharding/balancer_warns_draining_shards_blocked.js
@@ -0,0 +1,68 @@
+/*
+ * Verifies the balancer emits a warning when a removed shard cannot be drained due to balancing
+ * being disabled. There are two cases:
+ * - Balancer is disabled.
+ * - Balancing is disabled for a collection, which has chunks on draining shards.
+ */
+
+load("jstests/libs/fail_point_util.js");
+load("jstests/libs/parallel_shell_helpers.js");
+load('jstests/sharding/libs/find_chunks_util.js');
+
+const st = new ShardingTest({
+ shards: 2,
+ config: 1,
+ rs: {nodes: 1},
+ other: {
+ enableBalancer: false,
+ }
+});
+
+const mongos = st.s0;
+const configDB = st.getDB('config');
+
+const dbName = 'test';
+const collName = 'collToDrain';
+const ns = dbName + '.' + collName;
+const testDB = st.getDB(dbName);
+const coll = testDB.getCollection(collName);
+
+// Shard collection with shard0 as db primary.
+assert.commandWorked(
+ mongos.adminCommand({enablesharding: dbName, primaryShard: st.shard0.shardName}));
+assert.commandWorked(mongos.adminCommand({shardCollection: ns, key: {x: 1}}));
+
+assert.commandWorked(st.s.adminCommand({split: ns, middle: {x: 0}}));
+assert.commandWorked(st.s.adminCommand({moveChunk: ns, find: {x: -1}, to: st.shard0.shardName}));
+assert.commandWorked(st.s.adminCommand({moveChunk: ns, find: {x: 1}, to: st.shard1.shardName}));
+
+// Check that there are only 2 chunks before starting draining.
+const chunksBeforeDrain = findChunksUtil.findChunksByNs(configDB, ns).toArray();
+assert.eq(2, chunksBeforeDrain.length);
+
+// Force checks to happen continuously to speedup the test.
+const csrsPrimary = st.configRS.getPrimary();
+configureFailPoint(csrsPrimary, "forceBalancerWarningChecks");
+
+let awaitRemoveShard = startParallelShell(funWithArgs(function(shardName) {
+ load("jstests/sharding/libs/remove_shard_util.js");
+ removeShard(db, shardName);
+ }, st.shard1.shardName), st.s.port);
+
+// Test warning when the balancer is disabled.
+// "Draining of removed shards cannot be completed because the balancer is disabled"
+checkLog.containsJson(csrsPrimary, 6434000);
+
+sh.disableBalancing(coll);
+st.startBalancer();
+
+// Test warning when the balancer is enabled, but a specific collection is disabled.
+// "Draining of removed shards cannot be completed because the balancer is disabled for a collection
+// which has chunks in those shards".
+checkLog.containsJson(csrsPrimary, 7977400);
+
+// Re-enable balancing to let test terminate.
+sh.enableBalancing(coll);
+awaitRemoveShard();
+
+st.stop();
diff --git a/jstests/sharding/cancel_coordinate_txn_commit_with_tickets_exhausted.js b/jstests/sharding/cancel_coordinate_txn_commit_with_tickets_exhausted.js
index 91af933d10d..0ea93b8ae2a 100644
--- a/jstests/sharding/cancel_coordinate_txn_commit_with_tickets_exhausted.js
+++ b/jstests/sharding/cancel_coordinate_txn_commit_with_tickets_exhausted.js
@@ -26,6 +26,7 @@
load("jstests/libs/fail_point_util.js");
load('jstests/libs/parallelTester.js');
load("jstests/sharding/libs/create_sharded_collection_util.js");
+load("jstests/libs/auto_retry_transaction_in_sharding.js"); // For withTxnAndAutoRetryOnMongos.
const kNumWriteTickets = 10;
const st = new ShardingTest({
@@ -82,10 +83,10 @@ const sessionCollection = session.getDatabase(dbName).getCollection(collName);
// transactionThread won't need to persist a topology time. The scenario reported in SERVER-60685
// depended on the TransactionCoordinator being interrupted while persisting the participant list
// which happens after waiting for the topology time to become durable.
-session.startTransaction();
-assert.commandWorked(sessionCollection.insert({key: 400}));
-assert.commandWorked(sessionCollection.insert({key: -400}));
-assert.commandWorked(session.commitTransaction_forTesting());
+withTxnAndAutoRetryOnMongos(session, () => {
+ assert.commandWorked(sessionCollection.insert({key: 400}));
+ assert.commandWorked(sessionCollection.insert({key: -400}));
+});
const hangWithLockDuringBatchRemoveFp = configureFailPoint(txnCoordinator, failpointName);
diff --git a/jstests/sharding/change_stream_lookup_single_shard_cluster.js b/jstests/sharding/change_stream_lookup_single_shard_cluster.js
index e9ae2492ba7..fc1ae516f8c 100644
--- a/jstests/sharding/change_stream_lookup_single_shard_cluster.js
+++ b/jstests/sharding/change_stream_lookup_single_shard_cluster.js
@@ -2,6 +2,8 @@
// cluster only has a single shard, and that it can therefore successfully look up a document in a
// sharded collection.
// @tags: [
+// # If a rollback is triggered during a stepdown, the change stream cursor can become invalid.
+// does_not_support_stepdowns,
// requires_majority_read_concern,
// uses_change_streams,
// bf25011,
diff --git a/jstests/sharding/change_streams_shards_start_in_sync.js b/jstests/sharding/change_streams_shards_start_in_sync.js
index 4cf64d5f54c..cb57974099c 100644
--- a/jstests/sharding/change_streams_shards_start_in_sync.js
+++ b/jstests/sharding/change_streams_shards_start_in_sync.js
@@ -7,6 +7,8 @@
// and 'B' will be seen in the changestream before 'C'.
// @tags: [
// does_not_support_stepdowns,
+// # This test is flaky when running on PPC64 variants.
+// ppc64le_incompatible,
// requires_majority_read_concern,
// uses_change_streams,
// ]
diff --git a/jstests/sharding/cluster_time_across_add_shard.js b/jstests/sharding/cluster_time_across_add_shard.js
index 57c611cf1d2..ff983be7fea 100644
--- a/jstests/sharding/cluster_time_across_add_shard.js
+++ b/jstests/sharding/cluster_time_across_add_shard.js
@@ -102,7 +102,16 @@ for (let session of sessions) {
// Verify that the application is able to use a signed cluster time although the addShard
// or transitionFromDedicatedConfigServer command has not been run.
- assert.commandWorked(session.getDatabase("admin").runCommand("hello"));
+ assert.soon(() => {
+ const res = session.getDatabase("admin").runCommand("hello");
+ // TODO (SERVER-78909): KeysCollectionManager::getKeysForValidation() should retry
+ // refreshing if the refresh failed with ReadConcernMajorityNotAvailableYet
+ if (res.code == ErrorCodes.KeyNotFound) {
+ return false;
+ }
+ assert.commandWorked(res);
+ return true;
+ });
assert.eq(session.getClusterTime().signature.keyId, lastClusterTime.signature.keyId);
}
diff --git a/jstests/sharding/collection_uuid_reshard_collection.js b/jstests/sharding/collection_uuid_reshard_collection.js
index b500165b69e..49548d92fcf 100644
--- a/jstests/sharding/collection_uuid_reshard_collection.js
+++ b/jstests/sharding/collection_uuid_reshard_collection.js
@@ -39,8 +39,12 @@ const uuid = function() {
resetColl(coll);
// The command succeeds when provided with the correct collection UUID.
-assert.commandWorked(mongos.adminCommand(
- {reshardCollection: coll.getFullName(), key: newKeyDoc, collectionUUID: uuid()}));
+assert.commandWorked(mongos.adminCommand({
+ reshardCollection: coll.getFullName(),
+ key: newKeyDoc,
+ collectionUUID: uuid(),
+ numInitialChunks: 1
+}));
// The command fails when provided with a UUID with no corresponding collection.
resetColl(coll);
@@ -49,6 +53,7 @@ let res = assert.commandFailedWithCode(mongos.adminCommand({
reshardCollection: coll.getFullName(),
key: newKeyDoc,
collectionUUID: nonexistentUUID,
+ numInitialChunks: 1,
}),
ErrorCodes.CollectionUUIDMismatch);
assert.eq(res.db, db.getName());
@@ -63,6 +68,7 @@ res = assert.commandFailedWithCode(mongos.adminCommand({
reshardCollection: coll2.getFullName(),
key: newKeyDoc,
collectionUUID: uuid(),
+ numInitialChunks: 1,
}),
ErrorCodes.CollectionUUIDMismatch);
assert.eq(res.db, db.getName());
@@ -79,6 +85,7 @@ res = assert.commandFailedWithCode(mongos.adminCommand({
reshardCollection: coll3.getFullName(),
key: newKeyDoc,
collectionUUID: uuid(),
+ numInitialChunks: 1,
}),
ErrorCodes.CollectionUUIDMismatch);
assert.eq(res.db, otherDB.getName());
@@ -93,6 +100,7 @@ res = assert.commandFailedWithCode(mongos.adminCommand({
reshardCollection: coll2.getFullName(),
key: newKeyDoc,
collectionUUID: uuid(),
+ numInitialChunks: 1,
}),
ErrorCodes.CollectionUUIDMismatch);
assert.eq(res.db, db.getName());
@@ -108,6 +116,7 @@ res = assert.commandFailedWithCode(mongos.adminCommand({
reshardCollection: view.getFullName(),
key: newKeyDoc,
collectionUUID: uuid(),
+ numInitialChunks: 1,
}),
ErrorCodes.CollectionUUIDMismatch);
assert.eq(res.db, db.getName());
diff --git a/jstests/sharding/configsvr_remove_chunks.js b/jstests/sharding/configsvr_remove_chunks.js
index 32bd4de8e6a..9eed04de342 100644
--- a/jstests/sharding/configsvr_remove_chunks.js
+++ b/jstests/sharding/configsvr_remove_chunks.js
@@ -48,7 +48,9 @@ function insertLeftoverChunks(configDB, uuid) {
let st = new ShardingTest({mongos: 1, shards: 1});
-const configDB = st.s.getDB('config');
+// Use retriable writes when writing to the config server since these are not automatically retried
+const mongosSession = st.s.startSession({retryWrites: true});
+const configDB = mongosSession.getDatabase("config");
const dbName = "test";
const collName = "foo";
diff --git a/jstests/sharding/documents_db_not_exist.js b/jstests/sharding/documents_db_not_exist.js
index 1742d149516..55d49349125 100644
--- a/jstests/sharding/documents_db_not_exist.js
+++ b/jstests/sharding/documents_db_not_exist.js
@@ -1,6 +1,6 @@
/**
* Tests that $documents stage continues even when the database does not exist
- * @tags: [requires_fcv_62, multiversion_incompatible]
+ * @tags: [multiversion_incompatible]
*
*/
diff --git a/jstests/sharding/drop_database_before_write_is_targeted.js b/jstests/sharding/drop_database_before_write_is_targeted.js
index d758ca5e950..18414baa1b9 100644
--- a/jstests/sharding/drop_database_before_write_is_targeted.js
+++ b/jstests/sharding/drop_database_before_write_is_targeted.js
@@ -5,7 +5,11 @@
* @tags: [
* # TODO (SERVER-84043): Requires the mongos to define the fail point. Enable multiversion
* # once 8.0 becomes last LTS.
- * multiversion_incompatible
+ * multiversion_incompatible,
+ * # The createDatabase command inside of the write might fail with FailedToSatisfyReadPreference
+ * # if it does not find a primary. This is not a retriable error, and is correct, but
+ * # incompatible with this test.
+ * does_not_support_stepdowns,
* ]
*/
diff --git a/jstests/sharding/health_monitor/progress_monitor_doesnt_crash_on_not_critical.js b/jstests/sharding/health_monitor/progress_monitor_doesnt_crash_on_not_critical.js
index 5b4b582f164..66433f99037 100644
--- a/jstests/sharding/health_monitor/progress_monitor_doesnt_crash_on_not_critical.js
+++ b/jstests/sharding/health_monitor/progress_monitor_doesnt_crash_on_not_critical.js
@@ -1,7 +1,7 @@
/*
* @tags: [multiversion_incompatible]
*/
-const PROGRESS_TIMEOUT_SECONDS = 5;
+const PROGRESS_TIMEOUT_SECONDS = 3;
(function() {
'use strict';
@@ -45,7 +45,7 @@ assert.commandWorked(
st.s1.adminCommand({"configureFailPoint": 'hangTestHealthObserver', "mode": "alwaysOn"}));
// Wait for the progress monitor timeout to elapse.
-sleep(1.1 * PROGRESS_TIMEOUT_SECONDS * 1000);
+sleep(2.1 * PROGRESS_TIMEOUT_SECONDS * 1000);
// Servers should be still be alive.
jsTestLog("Expect monogs processes to still be alive");
@@ -55,7 +55,7 @@ jsTestLog("Change observer to critical");
changeObserverIntensity(st.s1, 'test', 'critical');
// Wait for the progress monitor timeout to elapse.
-sleep(1.1 * PROGRESS_TIMEOUT_SECONDS * 1000);
+sleep((2.1 * PROGRESS_TIMEOUT_SECONDS * 1000) + 1000);
jsTestLog("Done sleeping");
// Servers should be still be alive.
diff --git a/jstests/sharding/hedged_reads.js b/jstests/sharding/hedged_reads.js
index bd121680d0a..10b655d5608 100644
--- a/jstests/sharding/hedged_reads.js
+++ b/jstests/sharding/hedged_reads.js
@@ -1,5 +1,10 @@
/**
* Tests hedging metrics in the serverStatus output.
+ * @tags: [
+ * # This test is known to be racey due to implementation of hedged reads (SERVER-65329).
+ * # Disable windows testing as this feature is deprecated in v8.0.
+ * incompatible_with_windows_tls,
+ * ]
*/
(function() {
"use strict";
@@ -95,7 +100,9 @@ try {
setCommandDelay(sortedNodes[0], "count", kBlockCmdTimeMS, ns);
// Make the hedged request block for a while to allow the operation to start on the other node.
- setCommandDelay(sortedNodes[1], "count", 100, ns);
+ // The delay is intentionally large so we avoid the race where a killOp can arrive before the
+ // request.
+ setCommandDelay(sortedNodes[1], "count", 1000, ns);
const comment = "test_kill_initial_request_" + ObjectId();
assert.commandWorked(testDB.runCommand({
@@ -126,7 +133,9 @@ try {
setCommandDelay(sortedNodes[1], "count", kBlockCmdTimeMS, ns);
// Make the initial request block for a while to allow the operation to start on the other node.
- setCommandDelay(sortedNodes[0], "count", 100, ns);
+ // The delay is intentionally large so we avoid the race where a killOp can arrive before the
+ // request.
+ setCommandDelay(sortedNodes[0], "count", 1000, ns);
const comment = "test_kill_additional_request_" + ObjectId();
assert.commandWorked(testDB.runCommand({
diff --git a/jstests/sharding/index_operations_abort_concurrent_outgoing_migrations.js b/jstests/sharding/index_operations_abort_concurrent_outgoing_migrations.js
index fa0511ab27f..d2fad117f10 100644
--- a/jstests/sharding/index_operations_abort_concurrent_outgoing_migrations.js
+++ b/jstests/sharding/index_operations_abort_concurrent_outgoing_migrations.js
@@ -13,6 +13,8 @@ load("jstests/libs/feature_flag_util.js");
// Test deliberately inserts orphans outside of migration.
TestData.skipCheckOrphans = true;
+// TODO (SERVER-91380): remove skipCheckingIndexesConsistentAcrossCluster flag.
+TestData.skipCheckingIndexesConsistentAcrossCluster = true;
/*
* Runs moveChunk on the host to move the chunk to the given shard.
@@ -192,8 +194,7 @@ if (FeatureFlagUtil.isEnabled(st.shard0.getDB('admin'), "ShardKeyIndexOptionalHa
// Verify dropping the shard key index succeeds.
ShardedIndexUtil.assertIndexDoesNotExistOnShard(
st.shard0, dbName, collName, hashedShardKey);
- ShardedIndexUtil.assertIndexDoesNotExistOnShard(
- st.shard1, dbName, collName, hashedShardKey);
+ // TODO (SERVER-91380): assert the shard key is not present on recipient shard1 as well.
});
}
diff --git a/jstests/sharding/libs/mongos_api_params_util.js b/jstests/sharding/libs/mongos_api_params_util.js
index 696ef0d1c1c..7de6a36dcda 100644
--- a/jstests/sharding/libs/mongos_api_params_util.js
+++ b/jstests/sharding/libs/mongos_api_params_util.js
@@ -1412,7 +1412,7 @@ let MongosAPIParametersUtil = (function() {
};
});
- const st = new ShardingTest({mongos: 1, shards: 2, rs: {nodes: 1}});
+ const st = new ShardingTest({mongos: 1, shards: 2, config: 1, rs: {nodes: 1}});
const listCommandsRes = st.s0.adminCommand({listCommands: 1});
assert.commandWorked(listCommandsRes);
diff --git a/jstests/sharding/libs/remove_shard_util.js b/jstests/sharding/libs/remove_shard_util.js
new file mode 100644
index 00000000000..c096e45b8d4
--- /dev/null
+++ b/jstests/sharding/libs/remove_shard_util.js
@@ -0,0 +1,46 @@
+// Make it easier to understand whether or not returns from the assert.soon are being retried.
+const kRetry = false;
+const kNoRetry = true;
+
+function removeShard(shardingTestOrConn, shardName, timeout) {
+ if (timeout == undefined) {
+ timeout = 10 * 60 * 1000; // 10 minutes
+ }
+
+ var s;
+ if (shardingTestOrConn instanceof ShardingTest) {
+ s = shardingTestOrConn.s;
+ } else {
+ s = shardingTestOrConn;
+ }
+
+ assert.soon(function() {
+ let res;
+ if (TestData.configShard && shardName == "config") {
+ // Need to use transitionToDedicatedConfigServer if trying
+ // to remove config server as a shard
+ res = s.adminCommand({transitionToDedicatedConfigServer: shardName});
+ } else {
+ res = s.adminCommand({removeShard: shardName});
+ }
+ if (!res.ok) {
+ if (res.code === ErrorCodes.ShardNotFound) {
+ // If the config server primary steps down right after removing the config.shards
+ // doc for the shard but before responding with "state": "completed", the mongos
+ // would retry the _configsvrRemoveShard command against the new config server
+ // primary, which would not find the removed shard in its ShardRegistry if it has
+ // done a ShardRegistry reload after the config.shards doc for the shard was
+ // removed. This would cause the command to fail with ShardNotFound.
+ return kNoRetry;
+ }
+ if (res.code === ErrorCodes.HostUnreachable && TestData.runningWithConfigStepdowns) {
+ // The mongos may exhaust its retries due to having consecutive config stepdowns. In
+ // this case, the mongos will return a HostUnreachable error.
+ // We should retry the operation when this happens.
+ return kRetry;
+ }
+ }
+ assert.commandWorked(res);
+ return res.state == 'completed';
+ }, "failed to remove shard " + shardName + " within " + timeout + "ms", timeout);
+}
diff --git a/jstests/sharding/mongos_rs_shard_failure_tolerance.js b/jstests/sharding/mongos_rs_shard_failure_tolerance.js
index 66c2133c90a..890fe0533ea 100644
--- a/jstests/sharding/mongos_rs_shard_failure_tolerance.js
+++ b/jstests/sharding/mongos_rs_shard_failure_tolerance.js
@@ -19,7 +19,15 @@ TestData.skipCheckOrphans = true;
(function() {
'use strict';
-var st = new ShardingTest({shards: 3, mongos: 1, other: {rs: true, rsOptions: {nodes: 2}}});
+var st = new ShardingTest({
+ shards: 3,
+ other: {
+ rs: true,
+ // Disables elections to avoid secondaries becoming primaries after stepdowns. The test
+ // relies on specific topology changes done explicitly.
+ rsOptions: {nodes: 2, settings: {electionTimeoutMillis: ReplSetTest.kForeverMillis}}
+ },
+});
var mongos = st.s0;
var admin = mongos.getDB("admin");
@@ -130,7 +138,19 @@ jsTest.log("Testing active connection with second primary down...");
// Reads with read prefs
mongosConnActive.setSecondaryOk();
assert.neq(null, mongosConnActive.getCollection(collSharded.toString()).findOne({_id: -1}));
-assert.neq(null, mongosConnActive.getCollection(collSharded.toString()).findOne({_id: 1}));
+// This special retry logic is to mimic connection pool timeout in v8.0 and later. In earlier
+// versions, the connection pool may time out with NetworkInterfaceExceededTimeLimit, which
+// is not a retryable error. This is necessary because the now downed primary may time out
+// with NetworkInterfaceExceededTimeLimit instead of HostUnreachable.
+var res = null;
+try {
+ res = mongosConnActive.getCollection(collSharded.toString()).findOne({_id: 1});
+} catch (e) {
+ // RSM marks failed host.
+ assert.commandFailedWithCode(e, ErrorCodes.NetworkInterfaceExceededTimeLimit);
+ res = mongosConnActive.getCollection(collSharded.toString()).findOne({_id: 1});
+}
+assert.neq(null, res);
assert.neq(null, mongosConnActive.getCollection(collUnsharded.toString()).findOne({_id: 1}));
mongosConnActive.setSecondaryOk(false);
diff --git a/jstests/sharding/query/aggregation_currentop.js b/jstests/sharding/query/aggregation_currentop.js
index 58d63128329..207d93b42f2 100644
--- a/jstests/sharding/query/aggregation_currentop.js
+++ b/jstests/sharding/query/aggregation_currentop.js
@@ -13,7 +13,7 @@
* applicable.
*
* This test requires replica set configuration and user credentials to persist across a restart.
- * @tags: [requires_persistence, uses_transactions, uses_prepare_transaction]
+ * @tags: [requires_persistence, uses_transactions, uses_prepare_transaction, requires_fcv_60]
*/
// Restarts cause issues with authentication for awaiting replication.
@@ -411,7 +411,8 @@ function runCommonTests(conn, curOpSpec) {
explain: true
}));
- let expectedStages = [{$currentOp: {idleConnections: true}}, {$match: {desc: {$eq: "test"}}}];
+ let expectedStages =
+ [{$currentOp: {idleConnections: true, allUsers: false}}, {$match: {desc: {$eq: "test"}}}];
if (isRemoteShardCurOp) {
assert.docEq(explainPlan.splitPipeline.shardsPart, expectedStages);
diff --git a/jstests/sharding/query/collation_lookup.js b/jstests/sharding/query/collation_lookup.js
index 8c479d8e12a..0e9577b43ca 100644
--- a/jstests/sharding/query/collation_lookup.js
+++ b/jstests/sharding/query/collation_lookup.js
@@ -299,130 +299,6 @@ function runTests(withDefaultCollationColl, withoutDefaultCollationColl, collati
assert(arrayEq(expected, res),
"Expected " + tojson(expected) + " to equal " + tojson(res) + " up to ordering");
- // Test that an explicit collation on the $lookup stage is respected.
- res = withoutDefaultCollationColl
- .aggregate(
- [
- {$match: {_id: "lowercase"}},
- {
- $lookup: {
- from: withoutDefaultCollationColl.getName(),
- localField: "str",
- foreignField: "str",
- as: "matched",
- _internalCollation: collation["collation"],
- },
- },
- ])
- .toArray();
- assert.eq(1, res.length, tojson(res));
-
- expected = [{_id: "lowercase", str: "abc"}, {_id: "uppercase", str: "ABC"}];
- assert(
- arrayEq(expected, res[0].matched),
- "Expected " + tojson(expected) + " to equal " + tojson(res[0].matched) + " up to ordering");
-
- res = withoutDefaultCollationColl
- .aggregate(
- [
- {$match: {_id: "lowercase"}},
- {
- $lookup: {
- from: withoutDefaultCollationColl.getName(),
- let : {str1: "$str"},
- pipeline: [
- {$match: {$expr: {$eq: ["$str", "$$str1"]}}},
- {
- $lookup: {
- from: withoutDefaultCollationColl.getName(),
- let : {str2: "$str"},
- pipeline: [{$match: {$expr: {$eq: ["$str", "$$str1"]}}}],
- as: "matched2"
- }
- }
- ],
- as: "matched1",
- _internalCollation: collation["collation"],
- },
- }
- ])
- .toArray();
- assert.eq(1, res.length, tojson(res));
-
- expected = [
- {
- "_id": "lowercase",
- "str": "abc",
- "matched2": [{"_id": "lowercase", "str": "abc"}, {"_id": "uppercase", "str": "ABC"}]
- },
- {
- "_id": "uppercase",
- "str": "ABC",
- "matched2": [{"_id": "lowercase", "str": "abc"}, {"_id": "uppercase", "str": "ABC"}]
- }
- ];
- assert(arrayEq(expected, res[0].matched1),
- "Expected " + tojson(expected) + " to equal " + tojson(res[0].matched1) +
- " up to ordering");
-
- // Test that an explicit collation on the $lookup stage takes precedence over a command
- // collation.
- res = withoutDefaultCollationColl
- .aggregate(
- [
- {$match: {_id: "lowercase"}},
- {
- $lookup: {
- from: withoutDefaultCollationColl.getName(),
- localField: "str",
- foreignField: "str",
- as: "matched",
- _internalCollation: {locale: "simple"},
- },
- },
- ],
- collation)
- .toArray();
- assert.eq(1, res.length, tojson(res));
-
- expected = [{_id: "lowercase", str: "abc"}];
- assert(
- arrayEq(expected, res[0].matched),
- "Expected " + tojson(expected) + " to equal " + tojson(res[0].matched) + " up to ordering");
-
- res = withoutDefaultCollationColl
- .aggregate(
- [
- {$match: {_id: "lowercase"}},
- {
- $lookup: {
- from: withoutDefaultCollationColl.getName(),
- let : {str1: "$str"},
- pipeline: [
- {$match: {$expr: {$eq: ["$str", "$$str1"]}}},
- {
- $lookup: {
- from: withoutDefaultCollationColl.getName(),
- let : {str2: "$str"},
- pipeline: [{$match: {$expr: {$eq: ["$str", "$$str1"]}}}],
- as: "matched2"
- }
- }
- ],
- as: "matched1",
- _internalCollation: {locale: "simple"},
- },
- }
- ],collation)
- .toArray();
- assert.eq(1, res.length, tojson(res));
-
- expected =
- [{"_id": "lowercase", "str": "abc", "matched2": [{"_id": "lowercase", "str": "abc"}]}];
- assert(arrayEq(expected, res[0].matched1),
- "Expected " + tojson(expected) + " to equal " + tojson(res[0].matched1) +
- " up to ordering");
-
// Test that the $lookup stage uses the "simple" collation if a collation isn't set on the
// collection or the aggregation operation, even if the foreign collection has a collation.
res = withoutDefaultCollationColl
diff --git a/jstests/sharding/query/merge_nondefault_read_concern.js b/jstests/sharding/query/merge_nondefault_read_concern.js
index 70df9207bd8..f59e21ee876 100644
--- a/jstests/sharding/query/merge_nondefault_read_concern.js
+++ b/jstests/sharding/query/merge_nondefault_read_concern.js
@@ -1,7 +1,6 @@
/**
* Tests that $merge doesn't fail when a non-default readConcern is
* set on the session.
- * @tags: [requires_fcv_71]
*/
(function() {
"use strict";
diff --git a/jstests/sharding/range_deletions_has_index.js b/jstests/sharding/range_deletions_has_index.js
index deef14a9550..9f00ca8970b 100644
--- a/jstests/sharding/range_deletions_has_index.js
+++ b/jstests/sharding/range_deletions_has_index.js
@@ -14,6 +14,7 @@ const st = new ShardingTest({shards: {rs0: {nodes: 2}}});
// Test index gets created with an empty range deletions collection
let newPrimary = st.rs0.getSecondaries()[0];
+st.rs0.awaitReplication();
assert.commandWorked(newPrimary.adminCommand({replSetStepUp: 1}));
st.rs0.waitForPrimary();
const rangeDeletionColl = newPrimary.getDB("config").getCollection("rangeDeletions");
diff --git a/jstests/sharding/range_deletions_setFCV.js b/jstests/sharding/range_deletions_setFCV.js
index a664e20ab54..d5bb9658e5f 100644
--- a/jstests/sharding/range_deletions_setFCV.js
+++ b/jstests/sharding/range_deletions_setFCV.js
@@ -13,6 +13,8 @@
load("jstests/libs/fail_point_util.js");
load('jstests/libs/parallel_shell_helpers.js');
+load("jstests/sharding/libs/chunk_bounds_util.js");
+load("jstests/sharding/libs/find_chunks_util.js");
const rangeDeleterBatchSize = 128;
@@ -23,75 +25,128 @@ const st = new ShardingTest({
}
});
-// Setup database and collection for test
const dbName = 'db';
+const numDocsInColl = 1000;
const db = st.getDB(dbName);
+const configDB = st.getDB('config');
+const primaryShard = st.shard0;
assert.commandWorked(
- st.s.adminCommand({enableSharding: dbName, primaryShard: st.shard0.shardName}));
-const coll = db['test'];
-const nss = coll.getFullName();
-assert.commandWorked(st.s.adminCommand({shardCollection: nss, key: {_id: 1}}));
+ st.s.adminCommand({enableSharding: dbName, primaryShard: primaryShard.shardName}));
-assert.commandWorked(db.adminCommand({setFeatureCompatibilityVersion: lastContinuousFCV}));
-
-function assertOrphanCountIsCorrectOrMissing(conn, ns, numOrphans) {
- let fcv =
- assert.commandWorked(conn.adminCommand({getParameter: 1, featureCompatibilityVersion: 1}));
+function checkNumOrphansOnRangeDeletionTask(conn, ns, numOrphans) {
const rangeDeletionDoc =
conn.getDB("config").getCollection("rangeDeletions").findOne({nss: ns});
- if (fcv.featureCompatibilityVersion.version === "6.0") {
- assert.neq(
- null,
- rangeDeletionDoc,
- "did not find document for namespace " + ns +
- ", contents of config.rangeDeletions on " + conn + ": " +
- tojson(conn.getDB("config").getCollection("rangeDeletions").find().toArray()));
- assert.eq(numOrphans,
- rangeDeletionDoc.numOrphanDocs,
- "Incorrect count of orphaned documents in config.rangeDeletions on " + conn +
- ": expected " + numOrphans +
- " orphaned documents but found range deletion document " +
- tojson(rangeDeletionDoc));
+ assert.neq(null,
+ rangeDeletionDoc,
+ "did not find document for namespace " + ns +
+ ", contents of config.rangeDeletions on " + conn + ": " +
+ tojson(conn.getDB("config").getCollection("rangeDeletions").find().toArray()));
+ assert.eq(numOrphans,
+ rangeDeletionDoc.numOrphanDocs,
+ "Incorrect count of orphaned documents in config.rangeDeletions on " + conn +
+ ": expected " + numOrphans +
+ " orphaned documents but found range deletion document " +
+ tojson(rangeDeletionDoc));
+}
+
+function moveChunkAndCheckRangeDeletionTasksUponFCVUpgrade(nss, donorShard, moveChunkCmd) {
+ // Ensure that no outstanding range deletion task will actually be executed (so that their
+ // recovery docs may be inspected).
+ let beforeDeletionFailpoint = configureFailPoint(donorShard, "hangBeforeDoingDeletion");
+ let afterDeletionFailpoint = configureFailPoint(donorShard, "hangAfterDoingDeletion");
+
+ // Downgrade the cluster
+ assert.commandWorked(db.adminCommand({setFeatureCompatibilityVersion: lastContinuousFCV}));
+
+ // Upgrade the cluster - pausing the process before the "drain outstanding migrations" step
+ let pauseBeforeDrainingMigrations =
+ configureFailPoint(donorShard, "hangBeforeDrainingMigrations");
+ const joinFCVUpgrade = startParallelShell(
+ funWithArgs(function(fcv) {
+ assert.commandWorked(db.adminCommand({setFeatureCompatibilityVersion: fcv}));
+ }, latestFCV), st.s.port);
+ pauseBeforeDrainingMigrations.wait();
+ // Complete a migration and check the pending range deletion tasks in the donor
+ assert.commandWorked(db.adminCommand(moveChunkCmd));
+
+ pauseBeforeDrainingMigrations.off();
+ joinFCVUpgrade();
+ // Check the batches are deleted correctly
+ const numBatches = numDocsInColl / rangeDeleterBatchSize;
+ assert(numBatches > 0);
+ for (let i = 0; i < numBatches; i++) {
+ // Wait for failpoint and check num orphans
+ beforeDeletionFailpoint.wait();
+ checkNumOrphansOnRangeDeletionTask(
+ donorShard, nss, numDocsInColl - rangeDeleterBatchSize * i);
+ // Unset and reset failpoint without allowing any batches deleted in the meantime
+ afterDeletionFailpoint = configureFailPoint(donorShard, "hangAfterDoingDeletion");
+ beforeDeletionFailpoint.off();
+ afterDeletionFailpoint.wait();
+ beforeDeletionFailpoint = configureFailPoint(donorShard, "hangBeforeDoingDeletion");
+ afterDeletionFailpoint.off();
}
+ beforeDeletionFailpoint.off();
+ assert.commandWorked(donorShard.rs.getPrimary().adminCommand({cleanupOrphaned: nss}));
}
-// Insert some docs into the collection.
-const numDocs = 1000;
-let bulk = coll.initializeUnorderedBulkOp();
-for (let i = 0; i < numDocs; i++) {
- bulk.insert({_id: i});
+function testAgainstCollectionWithRangeShardKey() {
+ // Fill up a sharded collection
+ const coll = db['collWithRangeShardKey'];
+ const nss = coll.getFullName();
+ assert.commandWorked(st.s.adminCommand({shardCollection: nss, key: {_id: 1}}));
+
+ // Insert some docs into the collection.
+ let bulk = coll.initializeUnorderedBulkOp();
+ for (let i = 0; i < numDocsInColl; i++) {
+ bulk.insert({_id: i});
+ }
+ assert.commandWorked(bulk.execute());
+
+ const moveChunkCmd = {moveChunk: nss, find: {_id: 0}, to: st.shard1.shardName};
+
+ moveChunkAndCheckRangeDeletionTasksUponFCVUpgrade(nss, primaryShard, moveChunkCmd);
}
-assert.commandWorked(bulk.execute());
-
-// Pause before first range deletion task
-let beforeDeletionFailpoint = configureFailPoint(st.shard0, "hangBeforeDoingDeletion");
-let afterDeletionFailpoint = configureFailPoint(st.shard0, "hangAfterDoingDeletion");
-
-// Upgrade FCV to 6.0
-let pauseBeforeDrainingMigrations = configureFailPoint(st.shard0, "hangBeforeDrainingMigrations");
-const FCVUpgrade = startParallelShell(
- funWithArgs(function(fcv) {
- assert.commandWorked(db.adminCommand({setFeatureCompatibilityVersion: fcv}));
- }, latestFCV), st.s.port);
-pauseBeforeDrainingMigrations.wait();
-assert.commandWorked(db.adminCommand({moveChunk: nss, find: {_id: 0}, to: st.shard1.shardName}));
-
-pauseBeforeDrainingMigrations.off();
-// Check the batches are deleted correctly
-const numBatches = numDocs / rangeDeleterBatchSize;
-for (let i = 0; i < numBatches; i++) {
- // Wait for failpoint and check num orphans
- beforeDeletionFailpoint.wait();
- assertOrphanCountIsCorrectOrMissing(st.shard0, nss, numDocs - rangeDeleterBatchSize * i);
- // Unset and reset failpoint without allowing any batches deleted in the meantime
- afterDeletionFailpoint = configureFailPoint(st.shard0, "hangAfterDoingDeletion");
- beforeDeletionFailpoint.off();
- afterDeletionFailpoint.wait();
- beforeDeletionFailpoint = configureFailPoint(st.shard0, "hangBeforeDoingDeletion");
- afterDeletionFailpoint.off();
+
+function testAgainstCollectionWithHashedShardKey() {
+ const collName = 'collWithHashedShardKey';
+ const hotKeyValue = 'hotKeyValue';
+ const hashedKeyValue = convertShardKeyToHashed(hotKeyValue);
+ const docWithHotShardKey = {k: hotKeyValue};
+ const coll = db[collName];
+ const nss = coll.getFullName();
+ assert.commandWorked(
+ st.s.adminCommand({shardCollection: nss, key: {k: 'hashed'}, numInitialChunks: 1}));
+
+ // Insert some docs into the collection.
+ let bulk = coll.initializeUnorderedBulkOp();
+ for (let i = 0; i < numDocsInColl; i++) {
+ bulk.insert(docWithHotShardKey);
+ }
+ assert.commandWorked(bulk.execute());
+
+ // All the documents are supposed to be stored within a single shard
+ const allCollChunks = findChunksUtil.findChunksByNs(configDB, nss).toArray();
+ const chunksWithDoc = allCollChunks.filter((chunk) => {
+ return chunkBoundsUtil.containsKey({k: hashedKeyValue}, chunk.min, chunk.max);
+ });
+ assert.eq(1, chunksWithDoc.length);
+ const shardHoldingData = chunksWithDoc[0].shard === st.shard0.shardName ? st.shard0 : st.shard1;
+ const shardWithoutData =
+ shardHoldingData.shardName === st.shard0.shardName ? st.shard1 : st.shard0;
+
+ const moveChunkCmd = {
+ moveChunk: nss,
+ bounds: [chunksWithDoc[0].min, chunksWithDoc[0].max],
+ to: shardWithoutData.shardName
+ };
+
+ moveChunkAndCheckRangeDeletionTasksUponFCVUpgrade(nss, shardHoldingData, moveChunkCmd);
}
-beforeDeletionFailpoint.off();
-FCVUpgrade();
+// Test Cases
+testAgainstCollectionWithRangeShardKey();
+testAgainstCollectionWithHashedShardKey();
+
st.stop();
})();
diff --git a/jstests/sharding/refresh_sessions.js b/jstests/sharding/refresh_sessions.js
index c6d229707ca..dec07890b38 100644
--- a/jstests/sharding/refresh_sessions.js
+++ b/jstests/sharding/refresh_sessions.js
@@ -8,8 +8,15 @@ var sessionsDb = "config";
var refresh = {refreshLogicalSessionCacheNow: 1};
var startSession = {startSession: 1};
-// Create a cluster with 1 shard.
-var cluster = new ShardingTest({shards: 2});
+var cluster = new ShardingTest({
+ mongos: [{setParameter: {sessionWriteConcernTimeoutSystemMillis: 0, sessionMaxBatchSize: 500}}],
+ shards: 2,
+ rs: {setParameter: {sessionWriteConcernTimeoutSystemMillis: 0, sessionMaxBatchSize: 500}},
+ other: {
+ configOptions:
+ {setParameter: {sessionWriteConcernTimeoutSystemMillis: 0, sessionMaxBatchSize: 500}}
+ }
+});
// Test that we can refresh without any sessions, as a sanity check.
{
diff --git a/jstests/sharding/reshard_collection_basic.js b/jstests/sharding/reshard_collection_basic.js
index 4b527757ecd..2dee0d4e5e7 100644
--- a/jstests/sharding/reshard_collection_basic.js
+++ b/jstests/sharding/reshard_collection_basic.js
@@ -212,29 +212,37 @@ let presetReshardedChunks =
*/
jsTest.log('Fail if sharding is disabled.');
-assert.commandFailedWithCode(mongos.adminCommand({reshardCollection: ns, key: {newKey: 1}}),
- ErrorCodes.NamespaceNotFound);
+assert.commandFailedWithCode(
+ mongos.adminCommand({reshardCollection: ns, key: {newKey: 1}, numInitialChunks: 1}),
+ ErrorCodes.NamespaceNotFound);
assert.commandWorked(mongos.adminCommand({enableSharding: kDbName}));
jsTest.log("Fail if collection is unsharded.");
-assert.commandFailedWithCode(mongos.adminCommand({reshardCollection: ns, key: {newKey: 1}}),
- ErrorCodes.NamespaceNotSharded);
+assert.commandFailedWithCode(
+ mongos.adminCommand({reshardCollection: ns, key: {newKey: 1}, numInitialChunks: 1}),
+ ErrorCodes.NamespaceNotSharded);
assert.commandWorked(mongos.adminCommand({shardCollection: ns, key: {oldKey: 1}}));
jsTest.log("Fail if missing required key.");
-assert.commandFailedWithCode(mongos.adminCommand({reshardCollection: ns}), 40414);
+assert.commandFailedWithCode(mongos.adminCommand({reshardCollection: ns, numInitialChunks: 1}),
+ 40414);
jsTest.log("Fail if unique is specified and is true.");
assert.commandFailedWithCode(
- mongos.adminCommand({reshardCollection: ns, key: {newKey: 1}, unique: true}),
+ mongos.adminCommand(
+ {reshardCollection: ns, key: {newKey: 1}, unique: true, numInitialChunks: 1}),
ErrorCodes.BadValue);
jsTest.log("Fail if collation is specified and is not {locale: 'simple'}.");
-assert.commandFailedWithCode(
- mongos.adminCommand({reshardCollection: ns, key: {newKey: 1}, collation: {locale: 'en_US'}}),
- ErrorCodes.BadValue);
+assert.commandFailedWithCode(mongos.adminCommand({
+ reshardCollection: ns,
+ key: {newKey: 1},
+ collation: {locale: 'en_US'},
+ numInitialChunks: 1
+}),
+ ErrorCodes.BadValue);
jsTest.log("Fail if both numInitialChunks and _presetReshardedChunks are provided.");
assert.commandFailedWithCode(mongos.adminCommand({
@@ -263,6 +271,7 @@ jsTest.log("Fail if zone provided is invalid for storage.");
assert.commandFailedWithCode(mongos.adminCommand({
reshardCollection: ns,
key: {"_id": "hashed"},
+ numInitialChunks: 1,
zones: [{min: {"_id": {"$minKey": 1}}, max: {"_id": {"$maxKey": 1}}, zone: "Namezone"}]
}),
ErrorCodes.BadValue);
@@ -301,13 +310,16 @@ assert.commandFailedWithCode(mongos.getDB('test').system.resharding.mycoll.inser
mongos.getDB(kDbName)[collName].drop();
jsTest.log("Succeed when correct locale is provided.");
-assertReshardCollOk({reshardCollection: ns, key: {newKey: 1}, collation: {locale: 'simple'}}, 1);
+assertReshardCollOk(
+ {reshardCollection: ns, key: {newKey: 1}, collation: {locale: 'simple'}, numInitialChunks: 1},
+ 1);
jsTest.log("Succeed base case.");
-assertReshardCollOk({reshardCollection: ns, key: {newKey: 1}}, 1);
+assertReshardCollOk({reshardCollection: ns, key: {newKey: 1}, numInitialChunks: 1}, 1);
jsTest.log("Succeed if unique is specified and is false.");
-assertReshardCollOk({reshardCollection: ns, key: {newKey: 1}, unique: false}, 1);
+assertReshardCollOk({reshardCollection: ns, key: {newKey: 1}, unique: false, numInitialChunks: 1},
+ 1);
jsTest.log(
"Succeed if _presetReshardedChunks is provided and test commands are enabled (default).");
@@ -344,6 +356,7 @@ assertReshardCollOk({
key: {newKey: 1},
unique: false,
collation: {locale: 'simple'},
+ numInitialChunks: 1,
zones: [{zone: newZoneName, min: {newKey: 5}, max: {newKey: 10}}]
},
3);
@@ -353,8 +366,8 @@ assertReshardCollOk({
reshardCollection: ns,
key: {newKey: 1},
unique: false,
- numInitialChunks: 1,
collation: {locale: 'simple'},
+ numInitialChunks: 1,
zones: [{zone: newZoneName, min: {newKey: MinKey}, max: {newKey: MaxKey}}]
},
1);
@@ -380,6 +393,7 @@ assertReshardCollOk({
key: {oldKey: 1, newKey: 1},
unique: false,
collation: {locale: 'simple'},
+ numInitialChunks: 1,
zones: [{zone: existingZoneName, min: {oldKey: 0}, max: {oldKey: 5}}]
},
3);
diff --git a/jstests/sharding/reshard_collection_joins_existing_operation.js b/jstests/sharding/reshard_collection_joins_existing_operation.js
index cd47186a5bd..72f5a19630e 100644
--- a/jstests/sharding/reshard_collection_joins_existing_operation.js
+++ b/jstests/sharding/reshard_collection_joins_existing_operation.js
@@ -22,8 +22,12 @@ load("jstests/sharding/libs/resharding_test_fixture.js");
const makeConfigsvrReshardCollectionThread = (configsvrConnString, ns) => {
return new Thread((configsvrConnString, ns) => {
const configsvr = new Mongo(configsvrConnString);
- assert.commandWorked(configsvr.adminCommand(
- {_configsvrReshardCollection: ns, key: {newKey: 1}, writeConcern: {w: "majority"}}));
+ assert.commandWorked(configsvr.adminCommand({
+ _configsvrReshardCollection: ns,
+ key: {newKey: 1},
+ numInitialChunks: 1,
+ writeConcern: {w: "majority"}
+ }));
}, configsvrConnString, ns);
};
diff --git a/jstests/sharding/resharding_change_stream_namespace_filtering.js b/jstests/sharding/resharding_change_stream_namespace_filtering.js
index 85b5fd8a33d..d286b7f928c 100644
--- a/jstests/sharding/resharding_change_stream_namespace_filtering.js
+++ b/jstests/sharding/resharding_change_stream_namespace_filtering.js
@@ -48,8 +48,8 @@ for (let i = 0; i < 100; ++i) {
}
// Reshard the 'coll_reshard' collection on {b: 1}.
-assert.commandWorked(
- mongosDB.adminCommand({reshardCollection: mongosReshardColl.getFullName(), key: {b: 1}}));
+assert.commandWorked(mongosDB.adminCommand(
+ {reshardCollection: mongosReshardColl.getFullName(), key: {b: 1}, numInitialChunks: 1}));
// Confirm that the change stream we opened on 'coll_other' only sees the sentinel 'insert' but does
// not see the earlier 'reshardBegin' or 'reshardDoneCatchUp' events on the 'coll_reshard'
diff --git a/jstests/sharding/resharding_coordinator_recovers_abort_decision.js b/jstests/sharding/resharding_coordinator_recovers_abort_decision.js
index d7b13c2b068..623f1adda62 100644
--- a/jstests/sharding/resharding_coordinator_recovers_abort_decision.js
+++ b/jstests/sharding/resharding_coordinator_recovers_abort_decision.js
@@ -93,7 +93,12 @@ reshardingTest.withReshardingInBackground(
assert.commandWorked(mongos.getDB("admin").killOp(ops[0].opid));
- reshardingTest.stepUpNewPrimaryOnShard(reshardingTest.configShardName);
+ // Step down the config shard's primary.
+ let configRS = reshardingTest.getReplSetForShard(reshardingTest.configShardName);
+ let primary = configRS.getPrimary();
+ assert.commandWorked(
+ primary.getDB("admin").runCommand({replSetStepDown: 60, force: true}));
+ configRS.waitForPrimary();
// After a stepdown, the _configsvrReshardCollection command will be retried by the
// primary shard. We use the reshardCollectionJoinedExistingOperation failpoint to
@@ -112,7 +117,6 @@ reshardingTest.withReshardingInBackground(
// Wait for secondaries to recover and catchup with primary before turning off the
// failpoints as a replication roll back can disconnect the test client.
- const configRS = reshardingTest.getReplSetForShard(reshardingTest.configShardName);
configRS.awaitSecondaryNodes();
configRS.awaitReplication();
reshardCollectionJoinedFailPointsList.forEach(
diff --git a/jstests/sharding/resharding_disallow_drop.js b/jstests/sharding/resharding_disallow_drop.js
index 144abd55b16..089c8f5a87f 100644
--- a/jstests/sharding/resharding_disallow_drop.js
+++ b/jstests/sharding/resharding_disallow_drop.js
@@ -31,7 +31,8 @@ const reshardingPauseBeforeInsertCoordinatorDocFailpoint =
configureFailPoint(st.configRS.getPrimary(), "pauseBeforeInsertCoordinatorDoc");
assert.commandFailedWithCode(
- db.adminCommand({reshardCollection: ns, key: {newKey: 1}, maxTimeMS: 1000}),
+ db.adminCommand(
+ {reshardCollection: ns, key: {newKey: 1}, maxTimeMS: 1000, numInitialChunks: 1}),
ErrorCodes.MaxTimeMSExpired);
// Wait for resharding to start running on the configsvr
@@ -53,7 +54,8 @@ assert.commandFailedWithCode(db.runCommand({drop: collName, maxTimeMS: 5000}),
// Finish resharding
reshardingPauseBeforeInsertCoordinatorDocFailpoint.off();
-assert.commandWorked(db.adminCommand({reshardCollection: ns, key: {newKey: 1}}));
+assert.commandWorked(
+ db.adminCommand({reshardCollection: ns, key: {newKey: 1}, numInitialChunks: 1}));
// Now the drop can complete
assert.commandWorked(db.runCommand({drop: collName}));
diff --git a/jstests/sharding/retryable_write_error_labels.js b/jstests/sharding/retryable_write_error_labels.js
index 23b0ff3c831..f4cf2db1a8e 100644
--- a/jstests/sharding/retryable_write_error_labels.js
+++ b/jstests/sharding/retryable_write_error_labels.js
@@ -137,6 +137,10 @@ function testMongodError(errorCode, isWCError) {
function testMongosError() {
const shard0Primary = st.rs0.getPrimary();
+ // Insert initial documents used by the test.
+ const docs = [{k: 0, x: 0}, {k: 1, x: 1}];
+ assert.commandWorked(shard0Primary.getDB(dbName)[collName].insert(docs));
+
// Test retryable writes.
jsTestLog("Retryable write should return mongos shutdown error with RetryableWriteError label");
@@ -211,7 +215,7 @@ function testMongosError() {
const sessionDb = session.getDatabase(dbName);
const sessionColl = sessionDb.getCollection(collName);
session.startTransaction();
- assert.commandWorked(sessionColl.update({}, {$inc: {x: 1}}));
+ assert.commandWorked(sessionColl.update({k: 0}, {$inc: {x: 1}}));
return sessionDb.adminCommand({
commitTransaction: 1,
txnNumber: NumberLong(session.getTxnNumber_forTesting()),
@@ -248,7 +252,7 @@ function testMongosError() {
const sessionDb = session.getDatabase(dbName);
const sessionColl = sessionDb.getCollection(collName);
session.startTransaction();
- assert.commandWorked(sessionColl.update({}, {$inc: {x: 1}}));
+ assert.commandWorked(sessionColl.update({k: 1}, {$inc: {x: 1}}));
return sessionDb.adminCommand({
abortTransaction: 1,
txnNumber: NumberLong(session.getTxnNumber_forTesting()),
diff --git a/jstests/sharding/run_restore.js b/jstests/sharding/run_restore.js
index 3dfbd0b5b38..b5dd22e10f9 100644
--- a/jstests/sharding/run_restore.js
+++ b/jstests/sharding/run_restore.js
@@ -12,6 +12,12 @@
load("jstests/libs/feature_flag_util.js");
+// Because we restart nodes in standalone mode, it's possible for fast count, which doesn't
+// discriminate between majority committed data and locally committed data, and the true count,
+// which only includes majority committed data on standalones, to diverge. Therefore skip
+// validating fast count.
+TestData.skipEnforceFastCountOnValidate = true;
+
const s =
new ShardingTest({name: "runRestore", shards: 2, mongos: 1, config: 1, other: {chunkSize: 1}});
diff --git a/jstests/sharding/run_restore_unsharded.js b/jstests/sharding/run_restore_unsharded.js
index 038e79f1dd9..30591a0bbb5 100644
--- a/jstests/sharding/run_restore_unsharded.js
+++ b/jstests/sharding/run_restore_unsharded.js
@@ -11,6 +11,12 @@
load("jstests/libs/feature_flag_util.js");
+// Because we restart nodes in standalone mode, it's possible for fast count, which doesn't
+// discriminate between majority committed data and locally committed data, and the true count,
+// which only includes majority committed data on standalones, to diverge. Therefore skip
+// validating fast count.
+TestData.skipEnforceFastCountOnValidate = true;
+
const s =
new ShardingTest({name: "runRestore", shards: 2, mongos: 1, config: 1, other: {chunkSize: 1}});
diff --git a/jstests/sharding/secondaries_clear_filtering_metadata.js b/jstests/sharding/secondaries_clear_filtering_metadata.js
new file mode 100644
index 00000000000..a42ce83a8e7
--- /dev/null
+++ b/jstests/sharding/secondaries_clear_filtering_metadata.js
@@ -0,0 +1,73 @@
+/**
+ * Verifies that secondaries clear their filtering metadata whenever a collection is created.
+ *
+ * TODO (SERVER-91143): Move and adapt this test to the `core_sharding_passthrough` suite once the
+ * infrastructure is ready to support at least two routers.
+ */
+
+const st = new ShardingTest({mongos: 2, shards: 2, rs: {nodes: 2}});
+
+const s0 = st.s0;
+const s1 = st.s1;
+
+const dbName = "MyDb";
+const collName = "MyColl";
+const collNs = dbName + "." + collName;
+
+assert.commandWorked(s0.adminCommand({enableSharding: dbName, primaryShard: st.shard0.shardName}));
+assert.commandWorked(s0.adminCommand({shardCollection: collNs, key: {x: 1}}));
+assert.commandWorked(s0.adminCommand({split: collNs, middle: {x: 0}}));
+assert.commandWorked(s0.adminCommand({moveChunk: collNs, find: {x: 0}, to: st.shard1.shardName}));
+
+// router0: SV1
+// router1: Empty
+// shard0: primary=SV1, secondary=UNKNOWN
+// shard1: primary=SV2, secondary=UNKNOWN
+
+assert.commandWorked(s0.getDB(dbName).MyColl.insert({x: -100}));
+assert.commandWorked(s0.getDB(dbName).MyColl.insert({x: 100}));
+assert.commandWorked(s1.getDB(dbName).MyColl.insert({x: -1000}));
+assert.commandWorked(s1.getDB(dbName).MyColl.insert({x: 1000}));
+
+// router0: SV1
+// router1: SV1
+// shard0: primary=SV1, secondary=UNKNOWN
+// shard1: primary=SV2, secondary=UNKNOWN
+
+s0.getDB(dbName).MyColl.drop();
+
+// router0: Empty
+// router1: SV1 (not aware of drop)
+// shard0: primary=UNKNOWN, secondary=UNKNOWN
+// shard1: primary=UNKNOWN, secondary=UNKNOWN
+
+// router1 will target shard1, then shard0.
+s1.getDB(dbName).MyColl.find({x: 0}).readPref('secondary').toArray();
+
+// router0: Empty
+// router1: Empty
+// shard0: primary=UNSHARDED, secondary=UNSHARDED
+// shard1: primary=UNSHARDED, secondary=UNSHARDED
+
+assert.commandWorked(s0.adminCommand({shardCollection: collNs, key: {y: 1}}));
+assert.commandWorked(s0.getDB(dbName).MyColl.insert({y: 42}));
+
+// router0: SV1
+// router1: Empty
+// shard0: primary=SV1, secondary=UNKNOWN
+// shard1: primary=UNSHARDED, secondary=UNSHARDED
+
+// This should reset shard1's shard version to be UNKNOWN on all nodes.
+assert.commandWorked(s0.adminCommand({movePrimary: dbName, to: st.shard1.shardName}));
+
+// router0: SV1
+// router1: Empty
+// shard0: primary=SV1, secondary=UNKNOWN
+// shard1: primary=UNKNOWN, secondary=UNKNOWN
+
+// If this were to equal 0 it would mean that s1 sent an UNSHARDED version to a stale secondary on
+// the new dbPrimary shard1. Being 1 means we're doing the correct thing here.
+assert.eq(s1.getDB(dbName).MyColl.find({}).readPref('secondary').itcount(), 1);
+assert.eq(s0.getDB(dbName).MyColl.find({}).itcount(), 1);
+
+st.stop();
diff --git a/jstests/sharding/shard_encrypted_collection.js b/jstests/sharding/shard_encrypted_collection.js
index d4c4de4f642..9c467a2b86b 100644
--- a/jstests/sharding/shard_encrypted_collection.js
+++ b/jstests/sharding/shard_encrypted_collection.js
@@ -40,6 +40,10 @@ function testShardingCommand(command) {
let commandObj = {};
commandObj[command] = kDbName + '.basic';
+ if (command === "reshardCollection") {
+ commandObj['numInitialChunks'] = 1;
+ }
+
jsTestLog('Fail ' + command + ' if shard key is an encrypted field');
commandObj['key'] = {firstName: 1};
res = mongos.adminCommand(commandObj);
diff --git a/jstests/sharding/shard_keys_with_dollar_sign.js b/jstests/sharding/shard_keys_with_dollar_sign.js
index c7fbbc73be5..5748a99cd3e 100644
--- a/jstests/sharding/shard_keys_with_dollar_sign.js
+++ b/jstests/sharding/shard_keys_with_dollar_sign.js
@@ -42,7 +42,8 @@ function testValidation(key, {isValidIndexKey, isValidShardKey}) {
}
assert.commandWorked(st.s.adminCommand({shardCollection: ns2, key: {_id: 1}}));
- const reshardCollectionRes = st.s.adminCommand({reshardCollection: ns2, key});
+ const reshardCollectionRes =
+ st.s.adminCommand({reshardCollection: ns2, key, numInitialChunks: 1});
if (isValidShardKey) {
assert.commandWorked(reshardCollectionRes);
} else {
diff --git a/jstests/sharding/swallow_unnecessary_uuid_mismatch_error.js b/jstests/sharding/swallow_unnecessary_uuid_mismatch_error.js
new file mode 100644
index 00000000000..b4dc7636ed4
--- /dev/null
+++ b/jstests/sharding/swallow_unnecessary_uuid_mismatch_error.js
@@ -0,0 +1,58 @@
+// Tests that a deleteMany operation on a cluster doesn't return a UUID mismatch in case it targets
+// a shard with no chunks.
+//
+(function() {
+"use strict";
+const st = new ShardingTest({shards: 3});
+
+const db = st.s.getDB(jsTestName());
+assert.commandWorked(
+ st.s.adminCommand({enableSharding: db.getName(), primaryShard: st.shard0.shardName}));
+
+const shardedColl1 = db.sharded_1;
+
+assert.commandWorked(shardedColl1.insert({_id: 0}));
+assert.commandWorked(shardedColl1.insert({_id: 10}));
+assert.commandWorked(shardedColl1.insert({_id: 50}));
+assert.commandWorked(shardedColl1.insert({_id: 100}));
+
+const splitChunk = function(coll, splitPointKeyValue) {
+ assert.commandWorked(
+ st.s.adminCommand({split: coll.getFullName(), middle: {_id: splitPointKeyValue}}));
+};
+
+const uuid = function(coll) {
+ return assert.commandWorked(db.runCommand({listCollections: 1}))
+ .cursor.firstBatch.find(c => c.name === coll.getName())
+ .info.uuid;
+};
+
+// shard0: [inf, 50), shard1: [50, inf), shard2 has no chunks
+assert.commandWorked(
+ st.s.adminCommand({shardCollection: shardedColl1.getFullName(), key: {_id: 1}}));
+splitChunk(shardedColl1, 50);
+assert.commandWorked(st.s.adminCommand(
+ {moveChunk: shardedColl1.getFullName(), find: {_id: 50}, to: st.shard1.shardName}));
+
+const cmdObj = {
+ delete: shardedColl1.getName(),
+ collectionUUID: uuid(shardedColl1),
+ deletes: [{
+ q: {
+ $and:
+ [{$expr: {$gte: ["$_id", {$literal: 0}]}}, {$expr: {$lt: ["$_id", {$literal: 99}]}}]
+ },
+ limit: 0,
+ hint: {_id: 1}
+ }],
+};
+
+// Run a multi-write which should only target shards 0 & 1. This could target shard 2 but we
+// shouldn't see any UUID mismatch errors since shard2 has no chunks and a delete is correctly
+// defined in this case.
+let res = db.runCommand(cmdObj);
+assert.commandWorked(res);
+// Only 3 documents fulfill the criteria so verify we've deleted them.
+assert.eq(3, res.n);
+st.stop();
+})();
diff --git a/jstests/sharding/timeseries_multiple_mongos.js b/jstests/sharding/timeseries_multiple_mongos.js
index dbf88f6fa56..6b6aee4987c 100644
--- a/jstests/sharding/timeseries_multiple_mongos.js
+++ b/jstests/sharding/timeseries_multiple_mongos.js
@@ -298,19 +298,6 @@ if (TimeseriesTest.timeseriesUpdatesAndDeletesEnabled(st.shard0) &&
cmdObj: {
update: collName,
updates: [{
- q: {},
- u: {$inc: {[metaField + ".b"]: 1}},
- multi: true,
- }]
- },
- numProfilerEntries: {sharded: 2, unsharded: 1},
- });
-
- runTest({
- shardKey: {[metaField + ".a"]: 1},
- cmdObj: {
- update: collName,
- updates: [{
q: {[metaField + ".a"]: 1},
u: {$inc: {[metaField + ".b"]: -1}},
multi: true,
@@ -324,19 +311,6 @@ if (TimeseriesTest.timeseriesUpdatesAndDeletesEnabled(st.shard0) &&
cmdObj: {
update: bucketsCollName,
updates: [{
- q: {},
- u: {$inc: {["meta.b"]: 1}},
- multi: true,
- }]
- },
- numProfilerEntries: {sharded: 2, unsharded: 1},
- });
-
- runTest({
- shardKey: {[metaField + ".a"]: 1},
- cmdObj: {
- update: bucketsCollName,
- updates: [{
q: {["meta.a"]: 1},
u: {$inc: {["meta.b"]: -1}},
multi: true,
@@ -351,18 +325,6 @@ if (TimeseriesTest.timeseriesUpdatesAndDeletesEnabled(st.shard0) &&
cmdObj: {
delete: collName,
deletes: [{
- q: {},
- limit: 0,
- }],
- },
- numProfilerEntries: {sharded: 2, unsharded: 1},
- });
-
- runTest({
- shardKey: {[metaField]: 1},
- cmdObj: {
- delete: collName,
- deletes: [{
q: {[metaField]: 0},
limit: 0,
}],
@@ -375,18 +337,6 @@ if (TimeseriesTest.timeseriesUpdatesAndDeletesEnabled(st.shard0) &&
cmdObj: {
delete: bucketsCollName,
deletes: [{
- q: {},
- limit: 0,
- }],
- },
- numProfilerEntries: {sharded: 2, unsharded: 1},
- });
-
- runTest({
- shardKey: {[metaField]: 1},
- cmdObj: {
- delete: bucketsCollName,
- deletes: [{
q: {meta: 0},
limit: 0,
}],
diff --git a/jstests/sharding/ttl_deletes_not_targeting_orphaned_documents.js b/jstests/sharding/ttl_deletes_not_targeting_orphaned_documents.js
index 10ec9c91e31..7590dce0a73 100644
--- a/jstests/sharding/ttl_deletes_not_targeting_orphaned_documents.js
+++ b/jstests/sharding/ttl_deletes_not_targeting_orphaned_documents.js
@@ -21,14 +21,12 @@ const testDB = st.s.getDB('test');
const coll = testDB[jsTest.name()];
const collName = coll.getFullName();
+// Shard a collection on _id:1 so that the initial chunk will reside on the primary shard (shard0)
assert.commandWorked(
st.s.adminCommand({enableSharding: dbName, primaryShard: st.shard0.shardName}));
assert.commandWorked(st.s.adminCommand({shardCollection: collName, key: {_id: 1}}));
-// Initialize TTL index: delete documents with field `a: <current date>` after 20 seconds
-assert.commandWorked(coll.createIndex({a: 1}, {expireAfterSeconds: 20}));
-
-// Insert documents that are going to be deleted in 20 seconds
+// Insert documents that are going to be deleted by the TTL index created later on
const currTime = new Date();
var bulk = coll.initializeUnorderedBulkOp();
const nDocs = 100;
@@ -37,16 +35,20 @@ for (let i = 0; i < nDocs; i++) {
}
assert.commandWorked(bulk.execute());
-// Move all documents on other shards
+// Move all documents to the other shard (shard1) but keep a chunk on shard0 to create the TTL index
+assert.commandWorked(st.s.adminCommand({split: collName, middle: {_id: -1}}));
assert.commandWorked(
st.s.adminCommand({moveChunk: collName, find: {_id: 0}, to: st.shard1.shardName}));
-// Verify that TTL index worked properly on owned documents
+// Initialize TTL index: delete documents with field `a: <current date>` older than 1 second
+assert.commandWorked(coll.createIndex({a: 1}, {expireAfterSeconds: 1}));
+
+// Verify that TTL index worked properly on owned documents on shard1
assert.soon(function() {
return coll.countDocuments({}) == 0;
}, "Failed to move all documents", 60000 /* 60 seconds */, 5000 /* 5 seconds */);
-// Verify that TTL index did not delete orphaned documents
+// Verify that TTL index did not delete orphaned documents on shard0
assert.eq(nDocs, st.rs0.getPrimary().getCollection(collName).countDocuments({}));
st.stop();
diff --git a/jstests/sharding/txn_recover_decision_using_recovery_router.js b/jstests/sharding/txn_recover_decision_using_recovery_router.js
index 09afd9a8a04..62818ab0bb2 100644
--- a/jstests/sharding/txn_recover_decision_using_recovery_router.js
+++ b/jstests/sharding/txn_recover_decision_using_recovery_router.js
@@ -185,8 +185,19 @@ const waitForCommitTransactionToComplete = function(coordinatorRs, lsid, txnNumb
});
};
-let st =
- new ShardingTest({shards: 2, rs: {nodes: 2}, mongos: 2, other: {mongosOptions: {verbose: 3}}});
+let st = new ShardingTest({
+ shards: 2,
+ rs: {nodes: 2},
+ rsOptions: {
+ setParameter: {
+ // Set this to match the value of transactionLifetimeLimitSeconds to avoid transition
+ // failure due to not being able to acquire the lock quickly enough.
+ maxTransactionLockRequestTimeoutMillis: TestData.transactionLifetimeLimitSeconds * 1000
+ }
+ },
+ mongos: 2,
+ other: {mongosOptions: {verbose: 3}}
+});
// The default WC is majority and this test can't satisfy majority writes.
assert.commandWorked(st.s.adminCommand(
diff --git a/jstests/sharding/verify_sessions_expiration_sharded.js b/jstests/sharding/verify_sessions_expiration_sharded.js
index bc3cf254755..ea225b96d04 100644
--- a/jstests/sharding/verify_sessions_expiration_sharded.js
+++ b/jstests/sharding/verify_sessions_expiration_sharded.js
@@ -123,6 +123,10 @@ for (let i = 0; i < 3; i++) {
lastUseValues[j] = sessionsCollectionArray[j].lastUse;
}
}
+
+ // Date_t has the granularity of milliseconds, so we have to make sure we don't run this loop
+ // faster than that.
+ sleep(10);
}
// 3. Verify that letting sessions expire (simulated by manual deletion) will kill their
diff --git a/jstests/ssl/libs/localhost-cn-with-san.pem b/jstests/ssl/libs/localhost-cn-with-san.pem
index a61872a2572..2222609932a 100644
--- a/jstests/ssl/libs/localhost-cn-with-san.pem
+++ b/jstests/ssl/libs/localhost-cn-with-san.pem
@@ -3,52 +3,52 @@
#
# Localhost based certificate using non-matching subject alternate name.
-----BEGIN CERTIFICATE-----
-MIIDkDCCAnigAwIBAgIEK/BYqDANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDkDCCAnigAwIBAgIERiogkTANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTM3WhcNMjYwNDE4MTYxMTM3WjBvMQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ3WhcNMjYwOTA3MTYxNDQ3WjBvMQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDESMBAGA1UEAwwJ
-bG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqlZamwHT
-pAqR86G/mi2s9o+8FSiAlvkUccgo5hsH4iba4p0SS4x/QNxnevrHbVB8RK44+cqC
-iKWo1njOsaL8C5f0Sy+wNxjRdiZzms7GP8kuOla3EOdkP9NvCshIGFSs/YyK6I9Q
-P4F530tRfbEiLQPJLnjai/jdLmXVnYm+odwDDvE9JYkqhB15XFfhqNfsjwon0mf1
-N1K2ipU9hRhEgn1k8ewRLTaTB6JzcPToqp+rDQ7SE7eHthXOKuqRG0wT3cQt8Jaa
-AbZzXmYYrKOVvsKf1KtqwNrBkdalCwoT1kFFTZXGgHw8sWrZLWNsmdh3CceWP41/
-pr+WXNFxhQOaeQIDAQABoy8wLTATBgNVHSUEDDAKBggrBgEFBQcDATAWBgNVHREE
-DzANggtleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAqRCIEpjoX1FS1B5l
-yxiDfn+fVwTXPdet06ZRq++jpEcyGugIg8ttDYNlxjwZzqUF7YHFSOQRrJjq+Fd7
-qRPJDJO5KdZMBdoV4nYZK++H29DJoEp2rmHyfaowXZKSoQISt0Vl0KO+phA4/Ez9
-qcPUQ4bKy7PDa5xoIM9XJnzuOkMIFY8N3GhJxacE8ClpHK/3QjbxeWzo5hMx2EPp
-4rohrF6XK7tOeSmHYeIlEVi5jsBRfZYyZ457qoOk4iQStKlY/tEMTU16apCGsAsh
-0TDWMFcEQQKLioVD00G7rI2cxJQcI0ao/sYjCMB12IsO7M73lmBSzRfdbEhXzKlq
-v5QWCQ==
+bG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzaABiDJK
+rLBFw/VeBu0yFo6o6ZgYAxqSnV7hi8a7SIfcol3WwdUTAzUGoJhQYYNQgRCvSzSk
+3u5Nbz736u6RpQYCrQbXG0qSgnQVGOvqAL5GE+jXNf6r4TkuPMkYRgWsQq118H1M
+N/tJ5ZSS4dq4f15xBogaH+Eb4/O5v/Bedh/1pS7c6E6y9UEAVvYCySGXjXM11TjP
+DjxDgq6TDbkc4F/YAh7e0+CoRgB0yb3zi6j3TPmBBxWaVsWJ75rZekwHztBaBn79
+DqrqqU0U0jqrKJMHiguj1Qtzoxl0C724vD8GhgBq5nNAlAv7shLvZH0KA7QvY2kz
+5maXLbxFnmvUuQIDAQABoy8wLTATBgNVHSUEDDAKBggrBgEFBQcDATAWBgNVHREE
+DzANggtleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAgP67hT3lnCHBcugv
+Gt4wE8xSUt9rk6xyyf1VGF7v0ErqSykG5rEnjMG0vc+/77u/+JCace0CDv/7eqlR
+BJWilgC3JIi/kXOTFxFxk5AD6NGUYx32UDlZgUe20LXBwm7rSzGfAOT9trphLlKD
+4gW88bY9n9iLI87LutKR6wZ/opm/1YW9w2kGAUMBXHPTltWMXcNsElsV/+E8farS
+KlDCciELkRHIL/DrlKd+l17T82wa4d2WvyQaIUgvnicwOE8iVEeaZuXwxoMb/0q7
+jKGFmBgB9hNTkR9aGYsvI8+s0GmqOL7fK/mAc9YDvn6fw5qNyhx4DW0g0FecqFGI
+6ixfUg==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCqVlqbAdOkCpHz
-ob+aLaz2j7wVKICW+RRxyCjmGwfiJtrinRJLjH9A3Gd6+sdtUHxErjj5yoKIpajW
-eM6xovwLl/RLL7A3GNF2JnOazsY/yS46VrcQ52Q/028KyEgYVKz9jIroj1A/gXnf
-S1F9sSItA8kueNqL+N0uZdWdib6h3AMO8T0liSqEHXlcV+Go1+yPCifSZ/U3UraK
-lT2FGESCfWTx7BEtNpMHonNw9Oiqn6sNDtITt4e2Fc4q6pEbTBPdxC3wlpoBtnNe
-Zhiso5W+wp/Uq2rA2sGR1qULChPWQUVNlcaAfDyxatktY2yZ2HcJx5Y/jX+mv5Zc
-0XGFA5p5AgMBAAECggEAAjTpOEIt2nRh0LLqgPmFiw2HdhTsea8UfZk4rEacDLtj
-Tu624lX+PooiI9ezd5YySaaPp4EzRnY7qIRY0QFrHjvU6lg5S3UlsNAG0XsUdc0w
-9m0NV1T87go/TMoDVTs3c245Vhr6edvahxCckNkFRaBXBMjWRhxnlGxi/JTcDIdE
-sJxTPyUywjEGpfoSmbQ6xHSmsM20lAehsRqReh4L49zrRvql4IKqI5RMmodQfmtG
-x/M++o8r23EQhU9nZ+7NOi5xtctYXASStpfWewZnclMGEe09upuRtuOWjXch7U8b
-VURlC9doBMR396okPBU191eBkMxAdwJBV8sRC3ONMQKBgQC1eqll+UvXHNtXETMx
-fMdrH2WkXxK4t0aDEatHP+Yq6a/mqSLNp+nYuwIH/Id5SV49sWRyYXabTHNcJf6i
-PpkIqJji7wGMNPN6+ZeXzWeiEb2cCHH1WUpF7QYhlYmXfa+wD8Oh72O8MOjBARKB
-MBV53wSydx789plH52hs5NUW6QKBgQDwSHKttLT5WGMWDdL0/3aQchs3YKt1qkdU
-fQIlURqvvZInJb2FUCS26LS3r1BsNqdXaxxKdxfkkNs8JK4Io0sPmz+J42sgvYRq
-OoCcxakwFDFw22Uz6Vs4dv5qr364RSc5xwg7NPTbRe94xCpl2GfKMCYMo7H/8Qjy
-dninmZFNEQKBgDYsw9z5KrawmpnHPK0NPsqvuLv01bXmoFoIMEU4whEVablFzGnw
-MlLMoLKZpCeEy2lHR2ENz0ZU8CsV/Imafjyjd+Bm0ON1+yk+0Q4z9zfea+fkbYB8
-gzuUojvsVAKxNn0sd44j1HYdc54KH+gI3qBe/xv3i3ygcOmSHw5C0YnhAoGAbDLD
-aRLxV0KEw96PuwD6G8s2FDa0nrSBkDsGZ1VhJffAQ16MO+a90ZtyHTCVj1UA/61c
-vO9p0+OixS9jKsKVPz7SWr4MdF7CrK8RUQb0y5CcPsycgsa26/MxV0sVTdbd9fd4
-7mhHRiH01rXGvbu36OTLjW987NpWBBBy/k15j3ECgYBzOFtZmCH0dA5mc80uRgeq
-u6km9d/1QjqtXTu5uG3N7CpAAoCGMZiY+aWKewHBBRXDKoMHhe4YqgolvlZY/oSJ
-WYoWMD1SyPxN9ZPCwmxZR4kYDfQYyHslrChxNLnFUzCabmj74oPzOgIWSPlOW2Hi
-OkSGJwtPwI6s8kD/PxXTOw==
+MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQDNoAGIMkqssEXD
+9V4G7TIWjqjpmBgDGpKdXuGLxrtIh9yiXdbB1RMDNQagmFBhg1CBEK9LNKTe7k1v
+Pvfq7pGlBgKtBtcbSpKCdBUY6+oAvkYT6Nc1/qvhOS48yRhGBaxCrXXwfUw3+0nl
+lJLh2rh/XnEGiBof4Rvj87m/8F52H/WlLtzoTrL1QQBW9gLJIZeNczXVOM8OPEOC
+rpMNuRzgX9gCHt7T4KhGAHTJvfOLqPdM+YEHFZpWxYnvmtl6TAfO0FoGfv0Oquqp
+TRTSOqsokweKC6PVC3OjGXQLvbi8PwaGAGrmc0CUC/uyEu9kfQoDtC9jaTPmZpct
+vEWea9S5AgMBAAECggEBAJde4+HUS/6mYSVpmsd0k7vhV11nFr4qMKZi85zHNpWl
+Vnm8pNzaM33X6kIM/pdaaMgqdTDi10A5o41yiGVNLLCUJSIk9/NiSUp5lBJdkUzs
+xX/gl5VrHjLVukELNLBPesk3EqxwQMyxU2wLnLlhHxK8fm31gW3YdISxphszIwbH
+G60Sa2oUrzWprtrOvhgFO/MUe54k7ltvWKBFh+Z1nflK7JgtRSWar1fZ28Ko4Nf5
+pC3VY7/zGzHs+A2qtvZLnM0wZjKEpP31yUMUi06HYcNL6lW2vfJJMwPS5CkbX2Ps
+6oKdxl4oC6kEDPLbaFTtYSsaAznkJOa1m03e7wF6sDUCgYEA9Te0rsfe7XVkq+vJ
+OrTkSliZh91lhhMWVyY5PWUVSkGx/+tw+h5tvTJhv5O3mPoHlcvS25Dn63p/2RSV
+JKsVbX4Hgdlv30OGftua72goO5XR7Tw7IisISoQn7A0m3w8Fb1W1FPdO9M+v2F0E
+Dio9Mg3tyUBbOYsA38sfKmSVoNsCgYEA1qqgP/whdzLXTU+ccQVLmiKBGpw1xDNp
+cI7K5vsmPMhOoR2FDgYe5j6/ggIe+jgBWVB+tKw/+RFzWeoivno0QcVvojutuQeq
+oYI99rlppzHwLStt+KQD+IwevDlSQPduZWRY2czUUja7exvVaYA4GJD/bGosG6If
+I0piVGYIuvsCgYEA1BH3GukULLzH8b8a6sCiZoG1VcDtGkTLn1cZTbVr8iparH+L
+12QVd/hofOxdbdleUfhSRT1OtWHdy3l3epzTDTxfdbb8f1PAr1lw5vdnRBDP2qGq
+amRY6Ujd1dGR+nrdMmonDxjKmgI7i5z18uIoxm8xZElaG6vRd7oNG/adSN0CgYEA
+kRdyiMzZsb9jVpXgn2N83glEScAbdylosvNQoR5PkfWxb6SMMhZg/C6dMjpMxcLk
+5oFJosRp2Oa6mKNwKF5gw7O26Gh92vobkl59ky1vA9r1AxK/mbcCGBRdEcuMlOyo
+aU+R3mRbfdYQkf0WGeDYCYK3oYeBmIvTj/7Ox0zPydECgYEA1EFC3o0H9e5ZKQKe
+wRFwKXmHdYDh1GgK9F7QSK14PNjno57n5Ibecb45kGsAIdkaCEnmtQbZLoFKPd/C
+3NVn6ufQVfi34EJnUNM8mTOhFSch6yIeFPkkpPZNXqOsHznOwze84AIwYobgWdP3
+dL3GfY+v2lKB9FgFpud41focFFY=
-----END PRIVATE KEY-----
diff --git a/jstests/ssl/libs/localhost-cn-with-san.pem.digest.sha1 b/jstests/ssl/libs/localhost-cn-with-san.pem.digest.sha1
index 193c08dd914..0fcfde10453 100644
--- a/jstests/ssl/libs/localhost-cn-with-san.pem.digest.sha1
+++ b/jstests/ssl/libs/localhost-cn-with-san.pem.digest.sha1
@@ -1 +1 @@
-BA6EB9A33BBB0A3D2F4741DEFF9D507063F4683B \ No newline at end of file
+32B94BA3DAC534E62EB5A78B4468A8DD4DF42BF1 \ No newline at end of file
diff --git a/jstests/ssl/libs/localhost-cn-with-san.pem.digest.sha256 b/jstests/ssl/libs/localhost-cn-with-san.pem.digest.sha256
index a1e91316bca..29dbf817bc1 100644
--- a/jstests/ssl/libs/localhost-cn-with-san.pem.digest.sha256
+++ b/jstests/ssl/libs/localhost-cn-with-san.pem.digest.sha256
@@ -1 +1 @@
-779655A5D1CE2E6071C0A10595C49C166A015CC1F65520EE564BB4BBA53F49A0 \ No newline at end of file
+5ABBAAA207CD0A88EBD71EE97D10DA66428B8A930B6149E5CE708D4024FE4AD6 \ No newline at end of file
diff --git a/jstests/ssl/ssl_ingress_conn_metrics.js b/jstests/ssl/ssl_ingress_conn_metrics.js
new file mode 100644
index 00000000000..729b3d21674
--- /dev/null
+++ b/jstests/ssl/ssl_ingress_conn_metrics.js
@@ -0,0 +1,60 @@
+/**
+ * Tests ingress connection metrics.
+ *
+ * @tags: [requires_fcv_60]
+ */
+
+"use strict";
+
+(function() {
+load("jstests/ssl/libs/ssl_helpers.js");
+
+if (detectDefaultTLSProtocol() !== "TLS1_3") {
+ // Short-circuit and exit test immediately -- before TLS 1.3, we can't use
+ // opensslCipherSuiteConfig.
+ jsTestLog("Platform does not support TLS 1.3; skipping test.");
+ return;
+}
+
+// We use 'opensslCipherSuiteConfig' to deterministically set the cipher suite negotiated when
+// openSSL is being used. This can be different on Windows/OSX implementations.
+let cipherSuite = "TLS_AES_256_GCM_SHA384";
+
+const tlsOptions = {
+ tlsMode: "requireTLS",
+ tlsCertificateKeyFile: "jstests/libs/server.pem",
+ tlsCAFile: "jstests/libs/ca.pem",
+ setParameter: {opensslCipherSuiteConfig: cipherSuite},
+};
+
+// Get the logId that corresponds to the implementation of TLS being used.
+let logId;
+switch (determineSSLProvider()) {
+ case "openssl":
+ logId = 6723801;
+ break;
+ case "windows":
+ logId = 6723802;
+ // This cipher is chosen to represent the cipher negotiated by Windows Server 2019 by
+ // default.
+ cipherSuite = "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384";
+ break;
+ case "apple":
+ logId = 6723803;
+ // We log only the cipher represented as its enum value in this code path. This corresponds
+ // to the hex value 0xC030 which maps to the cipher suite
+ // "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384". This cipher is chosen by OSX 12.1 by default.
+ cipherSuite = 49200;
+ break;
+ default:
+ assert(false, "Failed to determine that we are using a supported SSL provider");
+}
+
+jsTestLog("Establishing connection to mongod");
+const mongod = MongoRunner.runMongod(Object.merge(tlsOptions));
+// Start a new connection to check that 'durationMicros' is cumulatively measured in server status
+assert.soon(() => checkLog.checkContainsOnceJson(mongod, logId, {"cipher": cipherSuite}),
+ "failed waiting for log line with negotiated cipher info");
+
+MongoRunner.stopMongod(mongod);
+}());
diff --git a/jstests/ssl/x509/certs.yml b/jstests/ssl/x509/certs.yml
index e0aae5afd1b..234bd0d2d8f 100644
--- a/jstests/ssl/x509/certs.yml
+++ b/jstests/ssl/x509/certs.yml
@@ -764,6 +764,23 @@ certs:
- 'ca.pem'
- 'intermediate-ca.pem'
+- name: "intermediate-ca-B.pem"
+ description: Secondary intermediate CA issued by the primary root CA.
+ Subject: {CN: "Intermediate CA B"}
+ extensions:
+ basicConstraints: {CA: true}
+ Issuer: "ca.pem"
+
+- name: "intermediate-ca-B-leaf.pem"
+ description: First end-entity certificate signed by intermediate CA B
+ Subject: {CN: "End-entity certificate via Intermediate CA B"}
+ Issuer: "intermediate-ca-B.pem"
+ extensions:
+ extendedKeyUsage: [serverAuth, clientAuth]
+ subjectAltName:
+ DNS: localhost
+ IP: 127.0.0.1
+
###
# Split Horizon
###
diff --git a/jstests/ssl/x509/mkcert.py b/jstests/ssl/x509/mkcert.py
index b4d5b459f45..69b0f571287 100755
--- a/jstests/ssl/x509/mkcert.py
+++ b/jstests/ssl/x509/mkcert.py
@@ -408,10 +408,25 @@ def convert_cert_to_pkcs12(cert):
ca = get_cert_path(cert['Issuer'])
passout = 'pass:' + pkcs12['passphrase']
- args = ['openssl', 'pkcs12', '-export', '-in', src, '-inkey', src, '-out', dest, '-passout', passout, '-certfile', ca]
- if cert.get('passphrase'):
- args.append('-passin')
- args.append('pass:' + cert['passphrase'])
+ args = [
+ "openssl",
+ "pkcs12",
+ "-legacy",
+ "-export",
+ "-in",
+ src,
+ "-inkey",
+ src,
+ "-out",
+ dest,
+ "-passout",
+ passout,
+ "-certfile",
+ ca,
+ ]
+ if cert.get("passphrase"):
+ args.append("-passin")
+ args.append("pass:" + cert["passphrase"])
subprocess.check_call(args)
diff --git a/jstests/ssl/x509/mkcrl.sh b/jstests/ssl/x509/mkcrl.sh
index 89fddb90e2c..059b4d6ae82 100755
--- a/jstests/ssl/x509/mkcrl.sh
+++ b/jstests/ssl/x509/mkcrl.sh
@@ -4,12 +4,26 @@ set -e
# This script uses the openssl command line tool to create CRLs.
OUTPUT_PATH="jstests/libs/"
+CA_PEM_PATH="${OUTPUT_PATH}/ca.pem"
+TRUSTED_CA_PEM_PATH="${OUTPUT_PATH}/trusted-ca.pem"
+die () {
+ [ $# -gt 0 ] && [ ! -z "$1" ] && echo "$1" >&2
+ exit 1
+}
+
+# Usage:
+# crl <ca_pem_file> <output_crl_file> {empty|expired|revoked} [pem_file_to_revoke]
crl() {
+ [ $# -lt 3 ] && die "Error: too few arguments"
+ [ -z "$1" ] && die "Error: must supply a CA file"
+ [ -z "$2" ] && die "Error: must supply an output filename"
+ [ "$3" = "revoked" ] && [ -z "$4" ] && die "Error: must supply a certificate file to revoke"
+
CADB=$(mktemp -d)
- CA="jstests/libs/ca.pem"
+ CA="$1"
CONFIG="${CADB}/config"
- DEST="${OUTPUT_PATH}/$1"
+ DEST="${OUTPUT_PATH}/$2"
echo '01' > "$CADB/serial"
touch "$CADB/index.txt" "$CADB/index.txt.attr"
echo -e "[ ca ]\ndefault_ca = CA_default\n" > "$CONFIG"
@@ -17,18 +31,22 @@ crl() {
echo -e "certificate = $CA\nprivate_key = $CA\ndefault_md = sha256" >> "$CONFIG"
VALIDITY_OPTIONS="-days 824 -crldays 823"
- if [ "$2" = "expired" ]; then
- # -enddate 010101000000Z = expires on 0:00:00, Jan 1, 2000.
- # -crlsec 1 = valid for 1 second from now.
+ if [ "$3" = "expired" ]; then
+ # -enddate 010101000000Z = expires on 0:00:00, Jan 1, 2000.
+ # -crlsec 1 = valid for 1 second from now.
# i.e. this certificate will be completely invalid very soon.
VALIDITY_OPTIONS="-enddate 010101000000Z -crlsec 1"
- elif [ "$2" = "revoked" ]; then
- openssl ca -config "$CADB/config" -revoke "jstests/libs/client_revoked.pem"
+ elif [ "$3" = "revoked" ]; then
+ openssl ca -config "$CADB/config" -revoke "$4"
fi
openssl ca -config "$CADB/config" -gencrl -out "$DEST" -md sha256 $VALIDITY_OPTIONS
jstests/ssl/x509/mkdigest.py crl sha256 "$DEST"
jstests/ssl/x509/mkdigest.py crl sha1 "$DEST"
}
-crl crl.pem empty
-crl crl_expired.pem expired
-crl crl_client_revoked.pem revoked
+
+crl $CA_PEM_PATH crl.pem empty
+crl $CA_PEM_PATH crl_expired.pem expired
+crl $CA_PEM_PATH crl_client_revoked.pem revoked "jstests/libs/client_revoked.pem"
+crl $CA_PEM_PATH crl_intermediate_ca_B_revoked.pem revoked "jstests/libs/intermediate-ca-B.pem"
+crl $TRUSTED_CA_PEM_PATH crl_from_trusted_ca.pem empty
+crl "jstests/libs/intermediate-ca-B.pem" crl_from_intermediate_ca_B.pem empty \ No newline at end of file
diff --git a/jstests/ssl/x509/root-and-trusted-ca.pem b/jstests/ssl/x509/root-and-trusted-ca.pem
index 2f0c1d20bd1..50c9262556c 100644
--- a/jstests/ssl/x509/root-and-trusted-ca.pem
+++ b/jstests/ssl/x509/root-and-trusted-ca.pem
@@ -5,46 +5,46 @@
# Certificate from ca.pem
-----BEGIN CERTIFICATE-----
-MIIDeTCCAmGgAwIBAgIEUuls7DANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
+MIIDeTCCAmGgAwIBAgIEIGnWnzANBgkqhkiG9w0BAQsFADB0MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwOS2VybmVs
-IFRlc3QgQ0EwHhcNMjQwMTE1MTYxMTMzWhcNMjYwNDE4MTYxMTMzWjB0MQswCQYD
+IFRlc3QgQ0EwHhcNMjQwNjA1MTYxNDQ2WhcNMjYwOTA3MTYxNDQ2WjB0MQswCQYD
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENp
dHkxEDAOBgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEXMBUGA1UEAwwO
-S2VybmVsIFRlc3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDl
-0p4T7cqWDu/0AZ+5LTrt7U66WVm0Fm4yU8ZJgYpQ7BLuIGb664/BqpvitrKzogwh
-4O61sO1UtKOiD/KiyTjq8SzA1Go9WtdsIfDQkz6lU1cgy4HChOw/kLI6i012tg9E
-UzSoH+bvLxr18LtpOvyY6yLiT824AqN/Q/NjvRNrihh5HOcDkRR8+XzcWcg4fgKo
-8RvnEHxZ3jY7gpT5URfaisyOzNImWvB3hWjQseo7BpMIJLes7Sp2TSFtaHw0+Koe
-t2e/Ex9ls5X1fmN2Y5N9hUNN641eMMXUqIPdPq6mSeF7CCHWBETG+908TFBuQQJp
-ZJ8CmKeP7qJLxciseL7lAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
-hvcNAQELBQADggEBAHtFJmKTdyEGJlnl+zKNbOWK6+H8VglYQdWFojNXrWCnqiuK
-4NdEv8lTpEaUuV83Dz4neueFGiw9w0UIpspRPPahR5CVkVs1Oxy/LD3qAKPmxcJy
-nfj3eEYY7CSpc7TmNXHRFIWrv+40m7UJvfi+ns2MKL7IppY4A1bAwjoozvAI4rD+
-CkU61xGLYAD8YjzhNEu88LrIkV0JluBmsMen8tUce3rzVrNRouWpcc29am6JWyB6
-FLsPhUfHDZnxKl/SosXd2JvEDj27NvNtAEydpPQB4084KjDqfVzyJgMXLflkXBDS
-pdhzraLljLpRKZt6FvfDBDw4DzsW1abYUEUGJNg=
+S2VybmVsIFRlc3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDU
+tM92EQ+UJAvDZHjcHGCM5M2E/wHRXWV6z3pXNT+cZliEsUbCBqwA+rs3KYyT0NxM
+2bxDo7/yplFGEb8Kz3gZJGiXcp0WEqZKN8yfTd6p2OTzSlQ/Yw4wcsfnhDX/i2HK
+NQVh258vf1e4t8spr3udsPnfQo0ap/28F3Jq2QxGmKiTPQ2xdyWvk/K5zABHX4mu
+3c29FdViZpcYoKCdYhIsO7IWPBvvPQEqRDPRU/UDweYbJFyrlWNWMCislj0EfGIn
+LBhtXxeZHIXh9fWO8DfMzER+r1fIhxX7lvzdpyT+t3NcOGSWYRKcG8q2+iUnCK4H
+2a2Vg5YKQYGGWmkEQ++XAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggEBAMjiHKAOjasqJPeqSaibtcpClQ2qK6xVMvAdX2YofNzO9/WD
+T1vqF06nuUlUTN+onacW9bT/cABzX2WmBlXH3N0kkr3bQ3dZy6KJpZnLhat3TLYd
+pYWbbVvHUJ31DGnZXNpWzvH/7KSK/IUixfjlYXaKocRNacXtRlidKN1IgTjaMNvL
+gTGaeiaylRYQ0wwirxVJWUzCkRahVlu8nHipl4oWoRfzCxeKGLpXWPBBVJPmupxJ
+qeU0X4fppEYMfXBZLoA5XFPeGcA+epZxNCOEP9f+0CxLmJibe/IUWRcNPS2WWznT
+MV/vxlcqKt0YqxFFk8LzbYMfKa4RXKvk/xpy87g=
-----END CERTIFICATE-----
# Certificate from trusted-ca.pem
-----BEGIN CERTIFICATE-----
-MIIDojCCAoqgAwIBAgIEfeXcIzANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJV
+MIIDojCCAoqgAwIBAgIEDSAeGjANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEfMB0GA1UEAwwWVHJ1c3Rl
-ZCBLZXJuZWwgVGVzdCBDQTAeFw0yNDAxMTUxNjExNDdaFw0yNjA0MTgxNjExNDda
+ZCBLZXJuZWwgVGVzdCBDQTAeFw0yNDA2MDUxNjE0NDlaFw0yNjA5MDcxNjE0NDla
MHwxCzAJBgNVBAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazEWMBQGA1UEBwwNTmV3
IFlvcmsgQ2l0eTEQMA4GA1UECgwHTW9uZ29EQjEPMA0GA1UECwwGS2VybmVsMR8w
HQYDVQQDDBZUcnVzdGVkIEtlcm5lbCBUZXN0IENBMIIBIjANBgkqhkiG9w0BAQEF
-AAOCAQ8AMIIBCgKCAQEAriuvWSir0Jv40+VJsUsYmurNHP2rrtNs8a1cd2kPaI0Q
-6OkoKDx1oPNj3RCs2hz2JZISozLdm7NmCkitbrp4vjLoYcviw5ACb47eCsN5zqWs
-CDTSM7pFVV9Z6CdHYUD1+bGDbjSX0Zm2ipTXUYSzLGY79VhVbVYJ40dLzLIrH/5J
-eZ9FqF4FR7qOai0sjG5Xiu3r2NXsXYyP/pR8y42U7YUo3coXNjSVxEiWAltMTzUh
-psStrdBuZTzxMHY/r2GFy/xMP7QRaf41eVduBzYDfG7OyZMQQM99fgAbI9faiUms
-0MxIAqJ/7qtvjvWWMnsEjHaYHsLAqORKs+P479Q8rQIDAQABoywwKjAMBgNVHRME
+AAOCAQ8AMIIBCgKCAQEAyfVq3WLPJGI78RjLcU6TWsL67KzIA5FH5Cs2VLttWK+f
+zDwGKdbn3UBbsL+jw0Ixfe7lv5EZXABXVb4sYJ2zZLojwnBjnbfcTuaS/aYJe5Sd
+nExjhEGErTu3gD0ErXD3Zf+nQMlqTw0B870TkRDyuU3ZNwkGcJYPnWbM+iktHPoq
+JQ6IzxUFYgas0TfwBlDOOSbJSW9wHQO7vmg3xQGt7/dj2E8NpWFXBbxC91RFEmbv
++v3cbwwhYLogIAZTFsL4AcTrEpbmcR8f2B27gZlCGelMi/C+KAcHeEwHbHokY/A8
+DeBSpkAS8eCU/A434hb9tNKNy9pQpreV+qyfYaSSSwIDAQABoywwKjAMBgNVHRME
BTADAQH/MBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAAATANBgkqhkiG9w0BAQsF
-AAOCAQEAGhaCW8lgIamq/+uMpzOTU1ECyuz7Bsp4Qui2Bc3XwXqYuUmI/KcfLVGA
-t2fx6myU9aFic20Vkl6KivkP5x8JDCvSHS9go3QXXzS+HhF3Cr0Qa3i4lg9Acbym
-KQW2qks6wBNWNHCZnT02wW2EFAzTXPokfRV29+FrxS0lUjOeCN/EHoAbbT8HTys0
-IKTZNuEN270qs5IerfxtBnFfXjNjDXIJDM1QMDxZsJv5B1JG72WOcOMMbtxykfWH
-httiVA7JV5AR1KSGa9qbyl3xVRBxHXTPG7WUiAi96wHbLMf1wSdW6zRwFKkTwVeg
-dy884V8Wgu/DW0rtBZefM7n9RYYWfA==
+AAOCAQEAtWS7ufCbscbsvYef2HPkBK0By6HwMdaZDy90OckUvfOR8vUHH8FNfav/
+BUzIlDnO2lKFClvbeT584fDbYVqwQS3/6Pz2lyQ64vvKcmMHzqiA+nUW/DN1x92t
+KLbcs853RgDDz1XtXwMw2VvLC5gYWB6GZ+VVRWuLYgd/l0i+ckk3jG1F9+KPs8F0
+1CaSPkAX0HAaiiBXgNCWAm+z/JZO3fRwCo2s5hRBZ40d9ZprPJyH7n2x9Uyf6SP3
+7BfGakoer9LtraSaMnhrOHUMFuunVfOk/3wstu51sNcdDI5UpkJFZUwD8y7gyN2Z
+GQIsgSNXW4rN/5jamADn3WkC7bo2Tg==
-----END CERTIFICATE-----
diff --git a/jstests/ssl/x509/root-and-trusted-ca.pem.digest.sha1 b/jstests/ssl/x509/root-and-trusted-ca.pem.digest.sha1
index e771ea3472f..094d60417bb 100644
--- a/jstests/ssl/x509/root-and-trusted-ca.pem.digest.sha1
+++ b/jstests/ssl/x509/root-and-trusted-ca.pem.digest.sha1
@@ -1 +1 @@
-F2FE3C922B6A5408AA06C1A0EBBEAF0363C52046 \ No newline at end of file
+13D573B8FF4C9E4AAEF37A360BA2D52AAD8FAE48 \ No newline at end of file
diff --git a/jstests/ssl/x509/root-and-trusted-ca.pem.digest.sha256 b/jstests/ssl/x509/root-and-trusted-ca.pem.digest.sha256
index 6537d4ba893..7f833323449 100644
--- a/jstests/ssl/x509/root-and-trusted-ca.pem.digest.sha256
+++ b/jstests/ssl/x509/root-and-trusted-ca.pem.digest.sha256
@@ -1 +1 @@
-6796FD7146BB58523E125BCA35AB2D882A6A2699C82BA63496636386703A998C \ No newline at end of file
+ABFD56D37533C4F7EE311891B1749818EDB90DEBFC957968A37066688598C607 \ No newline at end of file
diff --git a/jstests/ssl/x509/trusted-client-testdb-roles.pem b/jstests/ssl/x509/trusted-client-testdb-roles.pem
index 22f5d8d567e..14853dde7a6 100644
--- a/jstests/ssl/x509/trusted-client-testdb-roles.pem
+++ b/jstests/ssl/x509/trusted-client-testdb-roles.pem
@@ -3,53 +3,53 @@
#
# Client certificate with X509 role grants via trusted chain.
-----BEGIN CERTIFICATE-----
-MIIDwzCCAqugAwIBAgIEYq3HEjANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJV
+MIIDwzCCAqugAwIBAgIEVqMO+TANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJV
UzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5ldyBZb3JrIENpdHkxEDAO
BgNVBAoMB01vbmdvREIxDzANBgNVBAsMBktlcm5lbDEfMB0GA1UEAwwWVHJ1c3Rl
-ZCBLZXJuZWwgVGVzdCBDQTAeFw0yNDAxMTUxNjExNDdaFw0yNjA0MTgxNjExNDda
+ZCBLZXJuZWwgVGVzdCBDQTAeFw0yNDA2MDUxNjE0NDlaFw0yNjA5MDcxNjE0NDla
MIGRMQswCQYDVQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxFjAUBgNVBAcMDU5l
dyBZb3JrIENpdHkxEDAOBgNVBAoMB01vbmdvREIxFTATBgNVBAsMDEtlcm5lbCBV
c2VyczEuMCwGA1UEAwwlVHJ1c3RlZCBLZXJuZWwgVGVzdCBDbGllbnQgV2l0aCBS
-b2xlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOafN2wNmmEvU3zh
-lyav/H8pbkTaa28X7tTLeEO4aC9n/XNLH3uUdenz8qwlNCXP+235O+zQfRUCIhEh
-uiAgqjICbfaCr7EsFTyC+RLrXMnUB+1xhre55x49twpYxfjjPuvzV/1UwHj4rsHC
-E9ja9aoWCGyCuLBVl5FG1zbe3JW7J791sAa0eydq8JQ1nFwYLkyOO5bXx60HwwiT
-Yc009bIsVoFLyL/tdxQAioX2X7D+rfT47qsanFwKbKvObBdaNHnde9mhRZglF6Vz
-RWEUTRBPP9o6cXbQaZxKmgpTh4Revb0cdW/TPNjINemlCzXMJ7HFFS8PK5ikSp5I
-95cTFdkCAwEAAaM3MDUwMwYLKwYBBAGCjikCAQEEJDEiMA8MBXJvbGUxDAZ0ZXN0
-REIwDwwFcm9sZTIMBnRlc3REQjANBgkqhkiG9w0BAQsFAAOCAQEAH8yfrdIgeqfY
-ZnNBzqQgBS5GtuHK2Tso7sg32d6a1iaKwEzmYX0XMgKcC695sSdk3PYacxB7IA6b
-dpAfa9JOJS2O1h5iQ00c71z0ehHzWDzgN6Dy+8V0GblQUg3hM4eoe6H1lPrDlLuD
-6lXmKV8F4dB+febZ1xcScj/GQsilYR/csrxnYkHI6/Kryid/7kqM122jRduSebkM
-jawFNuOBxw3CGKdjcvShEq7/ZjVwMwFkOOR5zW/bd3+9gPDfFU4aAxqVPYbuxAY5
-E39bFpc3kYClNVtv5Pw+4xb1z1zkh75Fb/uW2waSdK7p1FYAdzO77bolxHcQk1X9
-25kTAGsifQ==
+b2xlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANqAeofH+37l6Xgb
+TOhL2jjl/obvUxu0VqNMczWYchJNaXxsx1Aa3CJvypjn76ZKVcXoFaJWXeAU3qv5
+Oz5rvdoxK3vwPzZSzW3pXL9lEtYWtC36fnmk1CHEa/n1p0S/kWb5KIG+dF9D+JYO
+dqB9chGRxrTu9m0N8doATtBB+q+twY4OyhTacfYJjuS/xlvagm29QLTjIFxSspjQ
+O38Ki9WHBVO4E8r4nu9BGzsjQ7R6+m+Zl+hTo6ao1bxBEZEi4vJpeW/AQZHJ8+LY
+Fs04/dulqQtNG/9olLiGVfZJGzLQq9jvDd6DZUP0jwy2qDT2CoLg9Prh0IskL/jr
+Uf1Nk2MCAwEAAaM3MDUwMwYLKwYBBAGCjikCAQEEJDEiMA8MBXJvbGUxDAZ0ZXN0
+REIwDwwFcm9sZTIMBnRlc3REQjANBgkqhkiG9w0BAQsFAAOCAQEAfeejZUGDGtRm
+Dge9Cd1IytzFav8yzm8u1Ed/930TWzlqycmwANdDSf8RnKLIxBc9PWemfs2z8JZK
+fVK84fOAJZkqyDEDzVSi04oSLawZHeu4uxg3BmiwWlUcAfAyhd4+83YZYy909tu7
+eAsP/xvmbAlSUrOQ+Vn1pXOohIl8sFocYFCW1fq5uKQc9xrRPi10MIJrlXsFr+SI
+PrUYQ2DTsEHDRqGgBa4YDYd2ysVtFXq6bHjTKd54978XaTeTqE4ZycFgMIzIK+Jo
+bzXAhGqA8JnP+iLKlLW+AWAR1j1l3nRiZdps1/6qlJr9SmPUhrWYXhYPd9Cl7RQf
+q426PcO0dg==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
-MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDmnzdsDZphL1N8
-4Zcmr/x/KW5E2mtvF+7Uy3hDuGgvZ/1zSx97lHXp8/KsJTQlz/tt+Tvs0H0VAiIR
-IbogIKoyAm32gq+xLBU8gvkS61zJ1AftcYa3uecePbcKWMX44z7r81f9VMB4+K7B
-whPY2vWqFghsgriwVZeRRtc23tyVuye/dbAGtHsnavCUNZxcGC5MjjuW18etB8MI
-k2HNNPWyLFaBS8i/7XcUAIqF9l+w/q30+O6rGpxcCmyrzmwXWjR53XvZoUWYJRel
-c0VhFE0QTz/aOnF20GmcSpoKU4eEXr29HHVv0zzYyDXppQs1zCexxRUvDyuYpEqe
-SPeXExXZAgMBAAECggEAGdFVskREleAnM8oKcpONjAvOkykzkUSH4W0k2cn1aec1
-nbhZfit01tvPPTvN/nSt5FYcQgrmEdnDCBFzRYD6pK4WctwXAJnbh8Ju0VIleVfC
-CnAk4YEPkVhd2yvsf8wq4V3E6jCYeoJ2h+zq7WI30dJ1H3az59OxK9uXIMaqwZ0z
-b8ZPHWR4vk8DHi3VijjIFQttW3hq8PcwFcCEm2NeJv9RJI8itZUORx9OVqOcK73X
-TWlfExD3sZ4OmFoPHRoo1Co8lSYo3XJ3um4wtW7Z989ziOFO6gXSjN41Zd+oeA54
-pcaw+/ssVfrwqvkm1BcMiqZkB0J1Ki76R30ntvNJgQKBgQDt0dI5FGjPhBcfSnEj
-iHcMBpTiUFGGydfb/qstMh52aZVRr+bcIa50a6D1wmlhV+7ciM9fZJ/s6PhYdhJz
-ZBRnsxgz8LroRP9Y+QClLTDVZSgP2CFiBLKhcaB2ghQo0ywCUxAKq6kwyMfT/3p9
-KNB3cSmn0WT4EVagYgp9p8PewQKBgQD4QIkLv6eDK4OSKQxjHxLvWnJynrcWzVJ/
-OdQqGzlWFqsGZHdvLfXhQBWgisgrcX69p9cpJWq0PooYGoeo3B9k3yiPUC7T54SB
-9HXvjaynfgWif1noOTBrvNSTn2EpDe2PA2HIMcz+i367pQhJzzE1oct1rr0kWpwC
-aSLO00yVGQKBgCZf2Asr1um9R7nd2jnAmG0RVs7Z5P3Z7gHqqxZk4vN6gASpXJgi
-uzK/9z4Qu85gUQO287dR1lh1EzW6/6ks+fnttTcUXiSCla12qHr+usWESB2eY2yc
-k3JnklvtC3G2+X/6hTkjj+52R4BW1h4CCvlrAiy5JhC9Q3wntcem3X1BAoGBAKK/
-DBkbp+GiITssleZVdMBddzIVQso8CJ1HeAOynUAG1E/4hSPp6Yuly4fX86onWYNU
-CQX8dZt8dGOg4NaemCY09g4d7tUUrhXUAYzuQAX95AvHmVVYSJoYzPOKRNP5QYfE
-G9J2c4FcSdUSOADLR+N1EkEwMOcoT6Z07lDQzR/hAoGAYm7dtFZLa12/4oAY114U
-5lbPIDAGmRg8jF/sTXJMDmJexQqZSzJG0j94ir+qDgJfskb34k64p+3wqOpRnsdk
-mO2UVgICM6ho9ffS55Y1sFX8NbSEpV20t3wIuPRjFnC/on6oAiLmc2YZ/XA3L+k7
-MKJkCk2mkKyu36iIBwSDbfA=
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDagHqHx/t+5el4
+G0zoS9o45f6G71MbtFajTHM1mHISTWl8bMdQGtwib8qY5++mSlXF6BWiVl3gFN6r
++Ts+a73aMSt78D82Us1t6Vy/ZRLWFrQt+n55pNQhxGv59adEv5Fm+SiBvnRfQ/iW
+DnagfXIRkca07vZtDfHaAE7QQfqvrcGODsoU2nH2CY7kv8Zb2oJtvUC04yBcUrKY
+0Dt/CovVhwVTuBPK+J7vQRs7I0O0evpvmZfoU6OmqNW8QRGRIuLyaXlvwEGRyfPi
+2BbNOP3bpakLTRv/aJS4hlX2SRsy0KvY7w3eg2VD9I8Mtqg09gqC4PT64dCLJC/4
+61H9TZNjAgMBAAECggEBANe86z6Nkh/lWfOg4PqrijeLvxfzzRcZpEFwBoDwmBDC
+JlkX/mN1Yc0Om/cFanXCB5Z0ZIf4xo+ti345gulK8BUzXz/sIj282+Cd/VlsroB7
+wkNzhNUOjfUZP5N5nUIf86y8beZM6hH1xshCV5Z2xd3bFVsoZl+e2SDqFOdDfgVd
+sj1ai+OserrZuhyoOx2jxc++do3ptLsa5thG8kEm5i7tbs6O0D0rrSkvlreW1WCI
+1Ws3FNa1YY44RXnMVO42HNRCu5FlvYSJpEwNxXeS2zusvslJP7Pt4g0bplgStPBM
+DjG00Gb264vRRRjPgXR2WiIJKGTvtzBbgx0peGq3MQECgYEA+8ln2cIp4veS0DZS
+RY2u5wJFXnZ0Q5ShI4zfoStiSPNcmGcU7wh3lHZT9yu/TYLCr6IubnTXIUwohrmJ
+KERIQBkVP9qHcNoB6bITEj2jN4EvlkKfmgKwczo+MputVzUu2y9wd/zKdd3lQkY+
+lRX85ltHukEacAsYFqPUwvtq8CECgYEA3ih9D6G72RrWDfyL0xp7ioE+CNbjtAsg
+BmK/lT8gtR3PudVmXWGn4cRohzz95yGiDOkwe5trcujzNvbfy5InvTAldoIl0FhM
+DFH2TnVARwQSrttyLRj58Fxgx5ogJyto4gfo88247NsZB1PEe/4zVce300EErqjF
+HEHf1GowYwMCgYB5la1ncyJE7qZfkwuxeJSQCwGyduL3y2rwvtMygb+pWJNLKOPr
+9ZvA/k7XmbF8XXtj0p43SoakFqGvRSLdZfO5uCMRvZYPwcaQsiQRd+A8Kk7vcWae
+uVO5oNNuHszawtzIjSTzXAfsWOWfVkpcNcz08/k0EMISftj3/c79BOmD4QKBgDiN
+YACZsEL9BN58mm97v1Urv0nqwf40EsvtWU25yy6vzxBEVZGR6XWcVOuQSCYNNr5I
+ojHlB34x9K/aOnAM3ZbYacD4Mn4N7BX6y1N/n4Q0cjkW3cLDJ+Ta7zwAbQzrjQB0
++QUPKnMI9x8ZYNwbgp/kflQFqhZ4Ge0ui7b77SNXAoGBAK0i/7XpnmZ5ZGesCMtz
+8crwxtalotvpF5MhuM2hIe8RBE47c4bo1XrZk1Z9LUtlVwp/vcfJZn4gMsPoFUKI
+M+5iVWWhVRCmgAqUQBL9jXb0mpSCui4RPn/VZVrVkkS+17mFrO/dua8indMfWY05
+AulQhYcaDfjPk8GeHuuJZXp9
-----END PRIVATE KEY-----
diff --git a/jstests/ssl/x509/trusted-client-testdb-roles.pem.digest.sha1 b/jstests/ssl/x509/trusted-client-testdb-roles.pem.digest.sha1
index a07b145d60e..253b7580833 100644
--- a/jstests/ssl/x509/trusted-client-testdb-roles.pem.digest.sha1
+++ b/jstests/ssl/x509/trusted-client-testdb-roles.pem.digest.sha1
@@ -1 +1 @@
-50252051868F549ABAC777331801C9F3A9AC6F03 \ No newline at end of file
+5C24E646664ECD2B45BC3BDAB476A26BAC1FDBBB \ No newline at end of file
diff --git a/jstests/ssl/x509/trusted-client-testdb-roles.pem.digest.sha256 b/jstests/ssl/x509/trusted-client-testdb-roles.pem.digest.sha256
index 9118ac96a25..149747434a2 100644
--- a/jstests/ssl/x509/trusted-client-testdb-roles.pem.digest.sha256
+++ b/jstests/ssl/x509/trusted-client-testdb-roles.pem.digest.sha256
@@ -1 +1 @@
-B2664A42125E3C5247F6D796159CC0F3DFF7B414762F830F332FDD3D11628C2C \ No newline at end of file
+4091D0B41951A227EE31E13E678299C448ADDAC3AF61DA829FA9BE74BCCBBFD9 \ No newline at end of file
diff --git a/jstests/ssl_linear/mongo_uri_secondaries.js b/jstests/ssl_linear/mongo_uri_secondaries.js
index 374693d4667..37e42332eaf 100644
--- a/jstests/ssl_linear/mongo_uri_secondaries.js
+++ b/jstests/ssl_linear/mongo_uri_secondaries.js
@@ -5,8 +5,12 @@
// To install trusted-ca.pem for local testing on OSX, invoke the following at a console:
// security add-trusted-cert -d jstests/libs/trusted-ca.pem
+load('jstests/libs/python.js');
+
const HOST_TYPE = getBuildInfo().buildEnvironment.target_os;
if (HOST_TYPE == "windows") {
+ assert.eq(0, runProgram(getPython3Binary(), "jstests/ssl_linear/windows_castore_cleanup.py"));
+
// OpenSSL backed imports Root CA and intermediate CA
runProgram("certutil.exe", "-addstore", "-user", "-f", "CA", "jstests\\libs\\trusted-ca.pem");
diff --git a/jstests/ssl_linear/repl_ssl_noca.js b/jstests/ssl_linear/repl_ssl_noca.js
index 93b0e24a39f..700023a3f58 100644
--- a/jstests/ssl_linear/repl_ssl_noca.js
+++ b/jstests/ssl_linear/repl_ssl_noca.js
@@ -7,7 +7,11 @@
// TODO BUILD-17503 Remove this tag
// @tags: [incompatible_with_macos]
+load('jstests/libs/python.js');
+
if (_isWindows()) {
+ assert.eq(0, runProgram(getPython3Binary(), "jstests/ssl_linear/windows_castore_cleanup.py"));
+
// OpenSSL backed imports Root CA and intermediate CA
runProgram("certutil.exe", "-addstore", "-user", "-f", "CA", "jstests\\libs\\ca.pem");
diff --git a/jstests/ssl_linear/ssl_cert_selector.js b/jstests/ssl_linear/ssl_cert_selector.js
index 2579273b5b1..d52e5d1d5fb 100644
--- a/jstests/ssl_linear/ssl_cert_selector.js
+++ b/jstests/ssl_linear/ssl_cert_selector.js
@@ -3,12 +3,16 @@
* server.
*/
+load('jstests/libs/python.js');
load('jstests/ssl/libs/ssl_helpers.js');
requireSSLProvider('windows', function() {
'use strict';
if (_isWindows()) {
+ assert.eq(0,
+ runProgram(getPython3Binary(), "jstests/ssl_linear/windows_castore_cleanup.py"));
+
// SChannel backed follows Windows rules and only trusts Root in LocalMachine
runProgram("certutil.exe", "-addstore", "-f", "Root", "jstests\\libs\\ca.pem");
// Import a pfx file since it contains both a cert and private key and is easy to import
diff --git a/jstests/ssl_linear/ssl_with_system_ca.js b/jstests/ssl_linear/ssl_with_system_ca.js
index a9eef168978..5a4e0334699 100644
--- a/jstests/ssl_linear/ssl_with_system_ca.js
+++ b/jstests/ssl_linear/ssl_with_system_ca.js
@@ -7,10 +7,14 @@
(function() {
'use strict';
+load('jstests/libs/python.js');
+
const HOST_TYPE = getBuildInfo().buildEnvironment.target_os;
jsTest.log("HOST_TYPE = " + HOST_TYPE);
if (HOST_TYPE == "windows") {
+ assert.eq(0, runProgram(getPython3Binary(), "jstests/ssl_linear/windows_castore_cleanup.py"));
+
// OpenSSL backed imports Root CA and intermediate CA
runProgram("certutil.exe", "-addstore", "-user", "-f", "CA", "jstests\\libs\\trusted-ca.pem");
diff --git a/jstests/ssl_linear/windows_castore_cleanup.py b/jstests/ssl_linear/windows_castore_cleanup.py
new file mode 100644
index 00000000000..ff9de13219c
--- /dev/null
+++ b/jstests/ssl_linear/windows_castore_cleanup.py
@@ -0,0 +1,41 @@
+import subprocess
+import sys
+import re
+
+def findMongoCertsFromStore(store):
+ command = ["certutil", "-store", store]
+ subject_pattern = re.compile(r"Subject:.*O=MongoDB")
+ cn_pattern = re.compile(r"CN=([^,]+)")
+ cns = []
+
+ try:
+ output = subprocess.check_output(command, shell=True).decode("utf-8")
+ except subprocess.CalledProcessError as e:
+ print(f"Command {command} failed with error: {e}", file=sys.stderr)
+ sys.exit(1)
+
+ filtered = [s for s in output.splitlines() if re.match(subject_pattern, s)]
+ for line in filtered:
+ cn_match = re.search(cn_pattern, line)
+ if cn_match:
+ cns.append(cn_match.group(1))
+ return cns
+
+def deleteCertsByCNFromStore(store, cns):
+ command = ["certutil", "-delstore", "-f", store, "cn"]
+ for cn in cns:
+ command[4] = cn
+ try:
+ print(f"Deleting 'CN={cn}' from the '{store}' certificate store:\n\t{' ' .join(command)}")
+ subprocess.check_call(command, shell=True)
+ except subprocess.CalledProcessError as e:
+ print(f"Command {command} failed with error: {e}", file=sys.stderr)
+ sys.exit(1)
+
+my_cns = findMongoCertsFromStore("My")
+root_cns = findMongoCertsFromStore("Root")
+
+if my_cns + root_cns:
+ print(f"Unexpected MongoDB certs found on host. Clearing them from the system cert stores.")
+deleteCertsByCNFromStore("My", my_cns)
+deleteCertsByCNFromStore("Root", root_cns) \ No newline at end of file