diff options
author | Mohammad Dashti <mdashti@gmail.com> | 2021-04-10 19:29:51 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-04-10 20:05:27 +0000 |
commit | 2ff1849ef0c5b8d9ea59853e9e205d3e7b4581e1 (patch) | |
tree | bc60f74ec87a5d4f1fe51e03f80b64caa3b1ca62 | |
parent | ccca10b25ab33f15a90c7c60996a054b9f8cc458 (diff) | |
download | mongo-2ff1849ef0c5b8d9ea59853e9e205d3e7b4581e1.tar.gz |
SERVER-54925 Move away from using Bson_serialization_type “any”
-rw-r--r-- | buildscripts/idl/idl_check_compatibility.py | 48 | ||||
-rw-r--r-- | buildscripts/idl/idl_compatibility_errors.py | 54 | ||||
-rw-r--r-- | buildscripts/idl/tests/compatibility_test_fail/new/compatibility_test_fail_new.idl | 342 | ||||
-rw-r--r-- | buildscripts/idl/tests/compatibility_test_fail/old/compatibility_test_fail_old.idl | 372 | ||||
-rw-r--r-- | buildscripts/idl/tests/test_compatibility.py | 43 | ||||
-rw-r--r-- | src/mongo/db/ops/write_ops.cpp | 16 | ||||
-rw-r--r-- | src/mongo/db/ops/write_ops_parsers.h | 14 | ||||
-rw-r--r-- | src/mongo/db/pipeline/aggregation_request_helper.cpp | 16 | ||||
-rw-r--r-- | src/mongo/db/pipeline/aggregation_request_helper.h | 19 | ||||
-rw-r--r-- | src/mongo/db/pipeline/aggregation_request_test.cpp | 17 | ||||
-rw-r--r-- | src/mongo/db/query/hint_parser.cpp | 8 | ||||
-rw-r--r-- | src/mongo/db/query/max_time_ms_parser.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/query/max_time_ms_parser.h | 4 | ||||
-rw-r--r-- | src/mongo/db/query/query_request_test.cpp | 58 | ||||
-rw-r--r-- | src/mongo/idl/basic_types.h | 26 | ||||
-rw-r--r-- | src/mongo/idl/idl_parser.cpp | 16 | ||||
-rw-r--r-- | src/mongo/idl/idl_parser.h | 16 |
17 files changed, 920 insertions, 153 deletions
diff --git a/buildscripts/idl/idl_check_compatibility.py b/buildscripts/idl/idl_check_compatibility.py index 120a42d5a4f..77a187857ae 100644 --- a/buildscripts/idl/idl_check_compatibility.py +++ b/buildscripts/idl/idl_check_compatibility.py @@ -50,6 +50,7 @@ from idl.compiler import CompilerImportResolver from idl_compatibility_errors import IDLCompatibilityContext, IDLCompatibilityErrorCollection, dump_errors ALLOW_ANY_TYPE_LIST: List[str] = [ + # This list if only used in unit-tests. "commandAllowedAnyTypes", "commandAllowedAnyTypes-param-anyTypeParam", "commandAllowedAnyTypes-reply-anyTypeField", @@ -69,6 +70,12 @@ ALLOW_ANY_TYPE_LIST: List[str] = [ "replyFieldCppTypeNotEqual-reply-cppTypeNotEqualReplyField", "commandCppTypeNotEqual", "commandParameterCppTypeNotEqual-param-cppTypeNotEqualParam", + "replyFieldSerializerNotEqual-reply-serializerNotEqualReplyField", + "commandSerializerNotEqual", + "commandParameterSerializerNotEqual-param-serializerNotEqualParam", + "replyFieldDeserializerNotEqual-reply-deserializerNotEqualReplyField", + "commandDeserializerNotEqual", + "commandParameterDeserializerNotEqual-param-deserializerNotEqualParam", "newlyAddedReplyFieldTypeBsonAnyAllowed-reply-newlyAddedBsonSerializationTypeAnyReplyField", "replyFieldTypeBsonAnyWithVariantUnstable-reply-bsonSerializationTypeWithVariantAnyUnstableReplyField", "newlyAddedParamBsonAnyAllowList-param-newlyAddedBsonAnyAllowListParam", @@ -78,6 +85,12 @@ ALLOW_ANY_TYPE_LIST: List[str] = [ "commandParameterCppTypeNotEqualUnstable-param-cppTypeNotEqualParam", "replyFieldCppTypeNotEqualUnstable-reply-cppTypeNotEqualReplyUnstableField", "commandCppTypeNotEqualUnstable", + "commandParameterSerializerNotEqualUnstable-param-serializerNotEqualParam", + "replyFieldSerializerNotEqualUnstable-reply-serializerNotEqualReplyUnstableField", + "commandSerializerNotEqualUnstable", + "commandParameterDeserializerNotEqualUnstable-param-deserializerNotEqualParam", + "replyFieldDeserializerNotEqualUnstable-reply-deserializerNotEqualReplyUnstableField", + "commandDeserializerNotEqualUnstable", # TODO (SERVER-54956): Decide what to do with commands: (create, createIndexes). 'create-param-backwards', @@ -93,8 +106,17 @@ ALLOW_ANY_TYPE_LIST: List[str] = [ 'saslContinue-param-payload', 'saslContinue-reply-payload', - # TODO (SERVER-54925): Decide what to do with commands: - # (aggregate, find, update, delete, findAndModify, explain). + # These commands (aggregate, find, update, delete, findAndModify, explain) might contain some + # fields with type `any`. Currently, it's not possible to avoid the `any` type in those cases. + # Instead, here are the preventive measures in-place to catch unintentional breaking changes: + # 1- Added comments on top of custom serializers/deserializers (related to these fields) to + # let the future developers know that their modifications to these methods might lead to + # a breaking change in the API. + # 2- Added proper unit-tests to catch accidental changes to the custom serializers/deserializers + # by over-fitting on the current implementation of these custom serializers/deserializers. + # 3- Added further checks to the current script (idl_check_compatibility.py) to check for + # changing a custom serializer/deserializer and considering it as a potential breaking + # change. 'aggregate-param-pipeline', 'aggregate-param-explain', 'aggregate-param-allowDiskUse', @@ -289,10 +311,21 @@ def check_reply_field_type_recursive(ctxt: IDLCompatibilityContext, cmd_name, field_name, old_field_type.name, old_field.idl_file_path) return + # If cpp_type is changed, it's a potential breaking change. if old_field_type.cpp_type != new_field_type.cpp_type: ctxt.add_reply_field_cpp_type_not_equal_error(cmd_name, field_name, new_field_type.name, new_field.idl_file_path) + # If serializer is changed, it's a potential breaking change. + if (not old_field.unstable) and old_field_type.serializer != new_field_type.serializer: + ctxt.add_reply_field_serializer_not_equal_error( + cmd_name, field_name, new_field_type.name, new_field.idl_file_path) + + # If deserializer is changed, it's a potential breaking change. + if (not old_field.unstable) and old_field_type.deserializer != new_field_type.deserializer: + ctxt.add_reply_field_deserializer_not_equal_error( + cmd_name, field_name, new_field_type.name, new_field.idl_file_path) + if isinstance(old_field_type, syntax.VariantType): # If the new type is not variant just check the single type. new_variant_types = new_field_type.variant_types if isinstance( @@ -542,10 +575,21 @@ def check_param_or_command_type_recursive(ctxt: IDLCompatibilityContext, cmd_name, old_type.name, old_field.idl_file_path, param_name, is_command_parameter) return + # If cpp_type is changed, it's a potential breaking change. if old_type.cpp_type != new_type.cpp_type: ctxt.add_command_or_param_cpp_type_not_equal_error( cmd_name, new_type.name, new_field.idl_file_path, param_name, is_command_parameter) + # If serializer is changed, it's a potential breaking change. + if (not old_field.unstable) and old_type.serializer != new_type.serializer: + ctxt.add_command_or_param_serializer_not_equal_error( + cmd_name, new_type.name, new_field.idl_file_path, param_name, is_command_parameter) + + # If deserializer is changed, it's a potential breaking change. + if (not old_field.unstable) and old_type.deserializer != new_type.deserializer: + ctxt.add_command_or_param_deserializer_not_equal_error( + cmd_name, new_type.name, new_field.idl_file_path, param_name, is_command_parameter) + if isinstance(old_type, syntax.VariantType): if not isinstance(new_type, syntax.VariantType): if not old_field.unstable: diff --git a/buildscripts/idl/idl_compatibility_errors.py b/buildscripts/idl/idl_compatibility_errors.py index dc5c30a2105..02961c50ccf 100644 --- a/buildscripts/idl/idl_compatibility_errors.py +++ b/buildscripts/idl/idl_compatibility_errors.py @@ -112,6 +112,12 @@ ERROR_ID_ADDED_ACCESS_CHECK_FIELD = "ID0067" ERROR_ID_COMMAND_STRICT_TRUE_ERROR = "ID0068" ERROR_ID_GENERIC_ARGUMENT_REMOVED = "ID0069" ERROR_ID_GENERIC_ARGUMENT_REMOVED_REPLY_FIELD = "ID0070" +ERROR_ID_COMMAND_PARAMETER_SERIALIZER_NOT_EQUAL = "ID0071" +ERROR_ID_COMMAND_SERIALIZER_NOT_EQUAL = "ID0072" +ERROR_ID_REPLY_FIELD_SERIALIZER_NOT_EQUAL = "ID0073" +ERROR_ID_COMMAND_DESERIALIZER_NOT_EQUAL = "ID0074" +ERROR_ID_COMMAND_PARAMETER_DESERIALIZER_NOT_EQUAL = "ID0075" +ERROR_ID_REPLY_FIELD_DESERIALIZER_NOT_EQUAL = "ID0076" # TODO (SERVER-55203): Remove SKIPPED_COMMANDS logic. # Any breaking changes added to API V1 before releasing 5.0 should be added to SKIPPED_COMMANDS to @@ -730,6 +736,22 @@ class IDLCompatibilityContext(object): "that is not equal in the old and new versions.") % (command_name, field_name, type_name), file) + def add_reply_field_serializer_not_equal_error(self, command_name: str, field_name: str, + type_name: str, file: str) -> None: + """Add an error about the old and new reply field serializer not being equal.""" + self._add_error(ERROR_ID_REPLY_FIELD_SERIALIZER_NOT_EQUAL, command_name, + ("'%s' has a reply field or sub-field '%s' of type '%s' that has " + "serializer that is not equal in the old and new versions.") % + (command_name, field_name, type_name), file) + + def add_reply_field_deserializer_not_equal_error(self, command_name: str, field_name: str, + type_name: str, file: str) -> None: + """Add an error about the old and new reply field deserializer not being equal.""" + self._add_error(ERROR_ID_REPLY_FIELD_DESERIALIZER_NOT_EQUAL, command_name, + ("'%s' has a reply field or sub-field '%s' of type '%s' that has " + "deserializer that is not equal in the old and new versions.") % + (command_name, field_name, type_name), file) + def add_new_reply_field_type_not_enum_error(self, command_name: str, field_name: str, new_field_type: str, old_field_type: str, file: str) -> None: @@ -864,6 +886,38 @@ class IDLCompatibilityContext(object): ("'%s' or its sub-struct has command type '%s' that has cpp_type " "that is not equal in the old and new versions") % (command_name, type_name), file) + def add_command_or_param_serializer_not_equal_error(self, command_name: str, type_name: str, + file: str, field_name: Optional[str], + is_command_parameter: bool) -> None: + # pylint: disable=too-many-arguments,invalid-name + """Add an error about the old and new command or param serializer not being equal.""" + if is_command_parameter: + self._add_error(ERROR_ID_COMMAND_PARAMETER_SERIALIZER_NOT_EQUAL, command_name, + ("'%s' has field or sub-field '%s' of type '%s' that has " + "serializer that is not equal in the old and new versions") % + (command_name, field_name, type_name), file) + else: + self._add_error( + ERROR_ID_COMMAND_SERIALIZER_NOT_EQUAL, command_name, + ("'%s' or its sub-struct has command type '%s' that has serializer " + "that is not equal in the old and new versions") % (command_name, type_name), file) + + def add_command_or_param_deserializer_not_equal_error(self, command_name: str, type_name: str, + file: str, field_name: Optional[str], + is_command_parameter: bool) -> None: + # pylint: disable=too-many-arguments,invalid-name + """Add an error about the old and new command or param deserializer not being equal.""" + if is_command_parameter: + self._add_error(ERROR_ID_COMMAND_PARAMETER_DESERIALIZER_NOT_EQUAL, command_name, + ("'%s' has field or sub-field '%s' of type '%s' that has " + "deserializer that is not equal in the old and new versions") % + (command_name, field_name, type_name), file) + else: + self._add_error( + ERROR_ID_COMMAND_DESERIALIZER_NOT_EQUAL, command_name, + ("'%s' or its sub-struct has command type '%s' that has deserializer " + "that is not equal in the old and new versions") % (command_name, type_name), file) + def add_old_reply_field_bson_any_error(self, command_name: str, field_name: str, old_field_type: str, file: str) -> None: """ diff --git a/buildscripts/idl/tests/compatibility_test_fail/new/compatibility_test_fail_new.idl b/buildscripts/idl/tests/compatibility_test_fail/new/compatibility_test_fail_new.idl index b92612556a8..01da70b3e8c 100644 --- a/buildscripts/idl/tests/compatibility_test_fail/new/compatibility_test_fail_new.idl +++ b/buildscripts/idl/tests/compatibility_test_fail/new/compatibility_test_fail_new.idl @@ -41,7 +41,7 @@ types: description: "The bson_serialization_type changes from int in the old command's reply field type to [int, string] in the new command's reply field type" cpp_type: "std::int32_t" - + intStringToIntStringBool: bson_serialization_type: - int @@ -57,7 +57,7 @@ types: - int description: "The old bson_serialization_type contains 'any'" cpp_type: "std::int32_t" - + newBsonSerializationTypeAny: bson_serialization_type: - int @@ -79,6 +79,24 @@ types: description: "The old and new bson_serialization_type contains 'any'" cpp_type: "std::int32_t" + bsonSerializationTypeAnySerializerNotEqual: + bson_serialization_type: + - int + - any + description: "The old and new bson_serialization_type contains 'any'. The 'serializer' + field value here is different from the one defined in old." + cpp_type: "std::int64_t" + serializer: ::mongo::newSerializer + + bsonSerializationTypeAnyDeserializerNotEqual: + bson_serialization_type: + - int + - any + description: "The old and new bson_serialization_type contains 'any' The 'deserializer' + field value here is different from the one defined in old." + cpp_type: "std::int64_t" + deserializer: ::mongo::newDeserializer + intStringBoolToIntString: bson_serialization_type: - int @@ -97,7 +115,7 @@ types: enums: NewReplyFieldEnumNotSubset: - description: "The new reply type is an enum that is not a subset of the old reply type's + description: "The new reply type is an enum that is not a subset of the old reply type's enum values" type: string values: @@ -123,7 +141,7 @@ structs: unstableNewField: type: string unstable: true - + OptionalNewFieldReply: description: "This reply contains a field that is required in the old command but is optional in the new command." @@ -131,11 +149,11 @@ structs: optionalNewField: type: string optional: true - + MissingNewFieldReply: description: "This reply contains a field that exists in the old command but is missing in the new command." - + RequiredNewField: description: "This struct contains a field that is optional in the old command but is required in the new command." @@ -223,12 +241,28 @@ structs: variant: [array<oldBsonSerializationTypeAny>, array<newBsonSerializationTypeAny>] CppTypeNotEqualReply: - description: "This reply contains a field whose old and new type have a bson_serialization_type - that contains 'any' and the cpp_types are not equal" + description: "This reply contains a field whose old and new type have a + bson_serialization_type that contains 'any' and the cpp_types are not equal" fields: cppTypeNotEqualReplyField: type: bsonSerializationTypeAnyCppTypeNotEqual + SerializerNotEqualReply: + description: "This reply contains a field whose old and new type + have a bson_serialization_type that contains 'any' + and the serializers are not equal" + fields: + serializerNotEqualReplyField: + type: bsonSerializationTypeAnySerializerNotEqual + + DeserializerNotEqualReply: + description: "This reply contains a field whose old and new type have + a bson_serialization_type that contains 'any' and the + deserializers are not equal" + fields: + deserializerNotEqualReplyField: + type: bsonSerializationTypeAnyDeserializerNotEqual + NewlyAddedBsonSerializationTypeAnyReply: description: "This reply contains a newly added field whose type has a bson_serialization_type that contains 'any' that is not explicitly allowed" @@ -270,13 +304,29 @@ structs: variant: [oldBsonSerializationTypeAny, newBsonSerializationTypeAny] CppTypeNotEqualUnstableReply: - description: "This reply contains a field whose old and new type have a bson_serialization_type - that contains 'any' and the cpp_types are not equal and where the old field - is unstable" + description: "This reply contains a field whose old and new type have a + bson_serialization_type that contains 'any' and the cpp_types are + not equal and where the old field is unstable" fields: cppTypeNotEqualReplyUnstableField: type: bsonSerializationTypeAnyCppTypeNotEqual + SerializerNotEqualUnstableReply: + description: "This reply contains a field whose old and new type have a + bson_serialization_type that contains 'any' and the serializers are + not equal and where the old field is unstable" + fields: + serializerNotEqualReplyUnstableField: + type: bsonSerializationTypeAnySerializerNotEqual + + DeserializerNotEqualUnstableReply: + description: "This reply contains a field whose old and new type have a + bson_serialization_type that contains 'any' and the deserializers are + not equal and where the old field is unstable" + fields: + deserializerNotEqualReplyUnstableField: + type: bsonSerializationTypeAnyDeserializerNotEqual + NewlyAddedBsonSerializationTypeAnyStruct: description: "This struct contains a newly added field whose type has a bson_serialization_type that contains 'any' that is not explicitly allowed" @@ -323,41 +373,59 @@ structs: variant: [oldBsonSerializationTypeAny, newBsonSerializationTypeAny] CppTypeNotEqualUnstableStruct: - description: "This struct contains a field whose old and new type have a bson_serialization_type - that contains 'any' and the cpp_types are not equal and where the old field - is unstable" + description: "This struct contains a field whose old and new type have a + bson_serialization_type that contains 'any' and the cpp_types are + not equal and where the old field is unstable" fields: cppTypeNotEqualStructUnstableField: optional: true type: bsonSerializationTypeAnyCppTypeNotEqual + SerializerNotEqualUnstableStruct: + description: "This struct contains a field whose old and new type have a + bson_serialization_type that contains 'any' and the serializers are + not equal and where the old field is unstable" + fields: + serializerNotEqualStructUnstableField: + optional: true + type: bsonSerializationTypeAnySerializerNotEqual + + DeserializerNotEqualUnstableStruct: + description: "This struct contains a field whose old and new type have a + bson_serialization_type that contains 'any' and the deserializers are + not equal and where the old field is unstable" + fields: + deserializerNotEqualStructUnstableField: + optional: true + type: bsonSerializationTypeAnyDeserializerNotEqual + StructFieldTypeRecursiveReplyOne: - description: "This reply contains a field whose new type is a struct that is not + description: "This reply contains a field whose new type is a struct that is not compatible with the old field type" fields: structReplyField: type: UnstableNewFieldReply - + StructFieldTypeRecursiveReplyTwo: - description: "This reply contains a field whose new type is a struct that is not + description: "This reply contains a field whose new type is a struct that is not compatible with the old field type" fields: structReplyField: type: StructType StructType: - description: "This struct contains a field whose new type is incompatible with the + description: "This struct contains a field whose new type is incompatible with the old field type" fields: fieldOne: type: BsonNotSubsetReply - + NewVariantTypeReply: description: "This reply contains a new field that has a variant type while the old field is not a variant type" fields: newVariantTypeReplyField: - type: + type: variant: [int, string] NewVariantNotSubsetReply: @@ -365,7 +433,7 @@ structs: of the old variant types" fields: variantNotSubsetReplyField: - type: + type: variant: [int, bool, string] NewVariantNotSubsetReplyWithArray: @@ -373,7 +441,7 @@ structs: of the old variant types" fields: variantNotSubsetReplyField: - type: + type: variant: [array<int>, array<bool>, array<string>] NewVariantNotSubsetReplyTwo: @@ -381,7 +449,7 @@ structs: of the old variant types" fields: variantNotSubsetReplyFieldTwo: - type: + type: variant: [int, bool, string, double] NewVariantNotSubsetReplyTwoWithArray: @@ -389,15 +457,15 @@ structs: of the old variant types" fields: variantNotSubsetReplyFieldTwo: - type: + type: variant: [array<int>, array<bool>, array<string>, array<double>] - + VariantRecursiveReply: description: "This reply contains a field that has a new variant type that is not compatible with the old variant type" fields: variantRecursiveReplyField: - type: + type: variant: [int, intStringToIntStringBool] VariantRecursiveReplyWithArray: @@ -405,15 +473,15 @@ structs: compatible with the old variant type" fields: variantRecursiveReplyField: - type: + type: variant: [array<int>, array<intStringToIntStringBool>] - + NewVariantStructNotSubsetReply: description: "This reply contains a field whose new variant types are not a subset of the old variant types" fields: variantStructNotSubsetReplyField: - type: + type: variant: [int, string, StructType] NewVariantStructNotSubsetReplyWithArray: @@ -421,23 +489,23 @@ structs: of the old variant types" fields: variantStructNotSubsetReplyField: - type: + type: variant: [array<int>, array<string>, array<StructType>] - + VariantStructRecursiveReply: description: "This reply contains a field that has a new variant struct type that is not compatible with the old variant struct type" fields: variantStructRecursiveReplyField: - type: + type: variant: [int, StructFieldTypeRecursiveReplyTwo] - + VariantStructRecursiveReplyWithArray: description: "This reply contains a field that has a new variant struct type that is not compatible with the old variant struct type" fields: variantStructRecursiveReplyField: - type: + type: variant: [array<int>, array<StructFieldTypeRecursiveReplyTwo>] CommandParamStructRecursiveOne: @@ -507,7 +575,7 @@ structs: of the old variant types" fields: variantNotSupersetField: - type: + type: variant: [int, bool] VariantNotSupersetStructWithArray: @@ -515,7 +583,7 @@ structs: of the old variant types" fields: variantNotSupersetField: - type: + type: variant: [array<int>, array<bool>] VariantNotSupersetStructTwo: @@ -523,7 +591,7 @@ structs: of the old variant types" fields: variantNotSupersetFieldTwo: - type: + type: variant: [int, bool] VariantNotSupersetStructTwoWithArray: @@ -531,7 +599,7 @@ structs: of the old variant types" fields: variantNotSupersetFieldTwo: - type: + type: variant: [array<int>, array<bool>] NewTypeNotVariantStruct: @@ -546,7 +614,7 @@ structs: compatible with the old variant types" fields: variantRecursiveField: - type: + type: variant: [int, intStringBoolToIntString] VariantRecursiveStructWithArray: @@ -554,7 +622,7 @@ structs: compatible with the old variant types" fields: variantRecursiveField: - type: + type: variant: [array<int>, array<intStringBoolToIntString>] VariantStructNotSupersetStruct: @@ -562,7 +630,7 @@ structs: while the new one does not" fields: variantStructNotSupersetField: - type: + type: variant: [int, string] VariantStructNotSupersetStructWithArray: @@ -570,7 +638,7 @@ structs: while the new one does not" fields: variantStructNotSupersetField: - type: + type: variant: [array<int>, array<string>] VariantStructRecursiveStruct: @@ -637,7 +705,7 @@ commands: strict: true api_version: "1" reply_type: OkReply - + removedCommandParameter: description: "parameter will be removed from command in compatibility_test_fail/new which results in an error" @@ -784,6 +852,34 @@ commands: cppTypeNotEqualParam: type: bsonSerializationTypeAnyCppTypeNotEqual + commandParameterSerializerNotEqual: + description: "command fails because it has a parameter type that has a + bson_serialization_type that contains 'any' and where the serializers + are not equal" + command_name: commandParameterSerializerNotEqual + namespace: ignored + cpp_name: commandParameterSerializerNotEqual + strict: true + api_version: "1" + reply_type: OkReply + fields: + serializerNotEqualParam: + type: bsonSerializationTypeAnySerializerNotEqual + + commandParameterDeserializerNotEqual: + description: "command fails because it has a parameter type that has a + bson_serialization_type that contains 'any' and where the deserializers + are not equal" + command_name: commandParameterDeserializerNotEqual + namespace: ignored + cpp_name: commandParameterDeserializerNotEqual + strict: true + api_version: "1" + reply_type: OkReply + fields: + deserializerNotEqualParam: + type: bsonSerializationTypeAnyDeserializerNotEqual + oldCommandParamTypeBsonAnyUnstable: description: "old command fails because it has a parameter type that has a bson_serialization_type that contains 'any' and the old param is unstable" @@ -842,6 +938,36 @@ commands: type: bsonSerializationTypeAnyCppTypeNotEqual optional: true + commandParameterSerializerNotEqualUnstable: + description: "command fails because it has a parameter type that has a + bson_serialization_type that contains 'any' and where the serializers + are not equal" + command_name: commandParameterSerializerNotEqualUnstable + namespace: ignored + cpp_name: commandParameterSerializerNotEqualUnstable + strict: true + api_version: "1" + reply_type: OkReply + fields: + serializerNotEqualParam: + type: bsonSerializationTypeAnySerializerNotEqual + optional: true + + commandParameterDeserializerNotEqualUnstable: + description: "command fails because it has a parameter type that has a + bson_serialization_type that contains 'any' and where the deserializers + are not equal" + command_name: commandParameterDeserializerNotEqualUnstable + namespace: ignored + cpp_name: commandParameterDeserializerNotEqualUnstable + strict: true + api_version: "1" + reply_type: OkReply + fields: + deserializerNotEqualParam: + type: bsonSerializationTypeAnyDeserializerNotEqual + optional: true + parameterFieldTypeBsonAnyWithVariantUnstable: description: "command fails when its paramter field variant types have bson_serialization_type 'any' that is not compatible with each other" @@ -1040,7 +1166,7 @@ commands: strict: true api_version: "1" reply_type: UnstableNewFieldReply - + newReplyFieldOptional: description: "new command fails because it contains an optional reply field that is required in the corresponding old command" @@ -1211,8 +1337,8 @@ commands: strict: true api_version: "1" reply_type: OkReply - fields: - variantAnyField: + fields: + variantAnyField: type: BsonSerializationTypeWithVariantAnyStruct parameterFieldTypeBsonAnyWithVariantWithArray: @@ -1224,8 +1350,8 @@ commands: strict: true api_version: "1" reply_type: OkReply - fields: - variantAnyField: + fields: + variantAnyField: type: BsonSerializationTypeWithVariantAnyStructWithArray commandTypeBsonAnyWithVariant: @@ -1260,6 +1386,26 @@ commands: api_version: "1" reply_type: CppTypeNotEqualReply + replyFieldSerializerNotEqual: + description: "command fails because its reply field type has a bson_serialization_type + that contains 'any', and the serializers are not equal" + command_name: replyFieldSerializerNotEqual + namespace: ignored + cpp_name: replyFieldSerializerNotEqual + strict: true + api_version: "1" + reply_type: SerializerNotEqualReply + + replyFieldDeserializerNotEqual: + description: "command fails because its reply field type has a bson_serialization_type + that contains 'any', and the deserializers are not equal" + command_name: replyFieldDeserializerNotEqual + namespace: ignored + cpp_name: replyFieldDeserializerNotEqual + strict: true + api_version: "1" + reply_type: DeserializerNotEqualReply + newReplyFieldTypeStructRecursiveOne: description: "new command fails because its reply field type is a struct that is incompatible with the old reply field type struct" @@ -1385,6 +1531,28 @@ commands: api_version: "1" reply_type: OkReply + commandSerializerNotEqual: + description: "command fails because its type has a bson_serialization_type + that contains 'any' and the serializers are not equal" + command_name: commandSerializerNotEqual + namespace: type + type: bsonSerializationTypeAnySerializerNotEqual + cpp_name: commandSerializerNotEqual + strict: true + api_version: "1" + reply_type: OkReply + + commandDeserializerNotEqual: + description: "command fails because its type has a bson_serialization_type + that contains 'any' and the deserializers are not equal" + command_name: commandDeserializerNotEqual + namespace: type + type: bsonSerializationTypeAnyDeserializerNotEqual + cpp_name: commandDeserializerNotEqual + strict: true + api_version: "1" + reply_type: OkReply + oldTypeBsonAnyUnstable: description: "old command fails because its type has a bson_serialization_type that contains 'any' and the old type field is unstable" @@ -1420,7 +1588,8 @@ commands: commandCppTypeNotEqualUnstable: description: "command fails because its type has a bson_serialization_type - that contains 'any' and the cpp_types are not equal and the old type field is unstable" + that contains 'any' and the cpp_types are not equal and the + old type field is unstable" command_name: commandCppTypeNotEqualUnstable namespace: type type: CppTypeNotEqualUnstableStruct @@ -1429,6 +1598,30 @@ commands: api_version: "1" reply_type: OkReply + commandSerializerNotEqualUnstable: + description: "command fails because its type has a bson_serialization_type + that contains 'any' and the serializers are not equal and the + old type field is unstable" + command_name: commandSerializerNotEqualUnstable + namespace: type + type: SerializerNotEqualUnstableStruct + cpp_name: commandSerializerNotEqualUnstable + strict: true + api_version: "1" + reply_type: OkReply + + commandDeserializerNotEqualUnstable: + description: "command fails because its type has a bson_serialization_type + that contains 'any' and the deserializers are not equal and the + old type field is unstable" + command_name: commandDeserializerNotEqualUnstable + namespace: type + type: DeserializerNotEqualUnstableStruct + cpp_name: commandDeserializerNotEqualUnstable + strict: true + api_version: "1" + reply_type: OkReply + commandTypeBsonAnyWithVariantUnstable: description: "command fails when its variant types have bson_serialization_type 'any' that is not compatible with each other and the old type field is unstable" @@ -1581,7 +1774,7 @@ commands: strict: true api_version: "1" reply_type: NewVariantTypeReply - + newReplyFieldVariantNotSubset: description: "new command fails because its reply field type is a variant type that is not a subset of the old reply field variant types" @@ -1661,7 +1854,7 @@ commands: strict: true api_version: "1" reply_type: NewVariantStructNotSubsetReplyWithArray - + replyFieldVariantStructRecursive: description: "new command fails because its reply field type has a variant struct type that is not compatible with the old reply field variant @@ -1672,7 +1865,7 @@ commands: strict: true api_version: "1" reply_type: VariantStructRecursiveReply - + replyFieldVariantStructRecursiveWithArray: description: "new command fails because its reply field type has a variant struct type that is not compatible with the old reply field variant @@ -1695,7 +1888,7 @@ commands: reply_type: OkReply fields: variantNotSupersetParam: - type: + type: variant: [int, bool] newParamVariantNotSupersetWithArray: @@ -1709,7 +1902,7 @@ commands: reply_type: OkReply fields: variantNotSupersetParam: - type: + type: variant: [array<int>, array<bool>] newParamVariantNotSupersetTwo: @@ -1723,7 +1916,7 @@ commands: reply_type: OkReply fields: variantNotSupersetParamTwo: - type: + type: variant: [int, string] newParamVariantNotSupersetTwoWithArray: @@ -1737,7 +1930,7 @@ commands: reply_type: OkReply fields: variantNotSupersetParamTwo: - type: + type: variant: [array<int>, array<string>] newParamTypeNotVariant: @@ -1764,7 +1957,7 @@ commands: reply_type: OkReply fields: variantRecursiveParam: - type: + type: variant: [int, intStringBoolToIntString] newParamVariantRecursiveWithArray: @@ -1778,7 +1971,7 @@ commands: reply_type: OkReply fields: variantRecursiveParam: - type: + type: variant: [array<int>, array<intStringBoolToIntString>] newParamVariantStructNotSuperset: @@ -1792,7 +1985,7 @@ commands: reply_type: OkReply fields: variantStructNotSupersetParam: - type: + type: variant: [int, string] newParamVariantStructNotSupersetWithArray: @@ -1806,7 +1999,7 @@ commands: reply_type: OkReply fields: variantStructNotSupersetParam: - type: + type: variant: [array<int>, array<string>] newParamVariantStructRecursive: @@ -2120,7 +2313,7 @@ commands: none: true complexChecksNotSubset: - description: "new command fails because the complex checks are not a subset of the + description: "new command fails because the complex checks are not a subset of the old complex checks" command_name: complexChecksNotSubset namespace: ignored @@ -2134,7 +2327,7 @@ commands: - check: checkOne complexChecksNotSubsetTwo: - description: "new command fails because the complex checks are not a subset of the + description: "new command fails because the complex checks are not a subset of the old complex checks" command_name: complexChecksNotSubsetTwo namespace: ignored @@ -2289,7 +2482,8 @@ commands: replyFieldCppTypeNotEqualUnstable: description: "command fails because its reply field type has a bson_serialization_type - that contains 'any', and the cpp_types are not equal and the old reply field is unstable" + that contains 'any', and the cpp_types are not equal and + the old reply field is unstable" command_name: replyFieldCppTypeNotEqualUnstable namespace: ignored cpp_name: replyFieldCppTypeNotEqualUnstable @@ -2297,6 +2491,28 @@ commands: api_version: "1" reply_type: CppTypeNotEqualUnstableReply + replyFieldSerializerNotEqualUnstable: + description: "command fails because its reply field type has a bson_serialization_type + that contains 'any', and the serializers are not equal and + the old reply field is unstable" + command_name: replyFieldSerializerNotEqualUnstable + namespace: ignored + cpp_name: replyFieldSerializerNotEqualUnstable + strict: true + api_version: "1" + reply_type: SerializerNotEqualUnstableReply + + replyFieldDeserializerNotEqualUnstable: + description: "command fails because its reply field type has a bson_serialization_type + that contains 'any', and the deserializers are not equal and + the old reply field is unstable" + command_name: replyFieldDeserializerNotEqualUnstable + namespace: ignored + cpp_name: replyFieldDeserializerNotEqualUnstable + strict: true + api_version: "1" + reply_type: DeserializerNotEqualUnstableReply + newlyAddedReplyFieldTypeBsonAnyNotAllowed: description: "command fails because it has a newly added reply field type has a bson_serialization_type that contains 'any' that is not explicitly allowed" diff --git a/buildscripts/idl/tests/compatibility_test_fail/old/compatibility_test_fail_old.idl b/buildscripts/idl/tests/compatibility_test_fail/old/compatibility_test_fail_old.idl index 4d29cdfe451..dabaeccbddc 100644 --- a/buildscripts/idl/tests/compatibility_test_fail/old/compatibility_test_fail_old.idl +++ b/buildscripts/idl/tests/compatibility_test_fail/old/compatibility_test_fail_old.idl @@ -61,7 +61,7 @@ types: - int description: "The new bson_serialization_type contains 'any'" cpp_type: "std::int32_t" - + bsonSerializationTypeAny: bson_serialization_type: - int @@ -76,6 +76,24 @@ types: description: "The old and new bson_serialization_type contains 'any'" cpp_type: "std::int64_t" + bsonSerializationTypeAnySerializerNotEqual: + bson_serialization_type: + - int + - any + description: "The old and new bson_serialization_type contains 'any'. The 'serializer' + field value here is different from the one defined in new." + cpp_type: "std::int64_t" + serializer: ::mongo::oldSerializer + + bsonSerializationTypeAnyDeserializerNotEqual: + bson_serialization_type: + - int + - any + description: "The old and new bson_serialization_type contains 'any'. The 'deserializer' + field value here is different from the one defined in new." + cpp_type: "std::int64_t" + deserializer: ::mongo::oldDeserializer + intStringBoolToIntString: bson_serialization_type: - int @@ -96,13 +114,13 @@ types: enums: NewReplyFieldEnumNotSubset: - description: "The new reply type is an enum that is not a subset of the old reply type's + description: "The new reply type is an enum that is not a subset of the old reply type's enum values" type: string values: valueOne: "one" valueTwo: "two" - + EnumNotSuperset: description: "The new enum is not a superset of the old enum values" type: string @@ -128,7 +146,7 @@ structs: fields: optionalNewField: type: string - + RequiredNewField: description: "This struct contains a field that is optional in the old command but is required in the new command." @@ -136,7 +154,7 @@ structs: requiredNewField: type: string optional: true - + MissingNewFieldReply: description: "This reply contains a field that exists in the old command but is missing in the new command." @@ -204,15 +222,15 @@ structs: type: newBsonSerializationTypeAny BsonSerializationTypeAnyReply: - description: "This reply contains a field whose old and new type have a bson_serialization_type - that contains 'any' that is not explicitly allowed" + description: "This reply contains a field whose old and new type have a + bson_serialization_type that contains 'any' that is not explicitly allowed" fields: bsonSerializationTypeAnyReplyField: type: bsonSerializationTypeAny NewlyAddedBsonSerializationTypeAnyReply: - description: "This reply contains a newly added field whose type has a bson_serialization_type - that contains 'any' that is not explicitly allowed" + description: "This reply contains a newly added field whose type has a + bson_serialization_type that contains 'any' that is not explicitly allowed" OldBsonSerializationTypeAnyUnstableReply: description: "This reply contains a field that is unstable in the old version @@ -242,8 +260,9 @@ structs: unstable: true BsonSerializationTypeWithVariantAnyUnstableReply: - description: "This reply contains a field whose old and new variant types have a bson_serialization_type - that contains 'any' that is not compatible and where the old field is unstable" + description: "This reply contains a field whose old and new variant types have a + bson_serialization_type that contains 'any' that is not compatible + and where the old field is unstable" fields: bsonSerializationTypeWithVariantAnyUnstableReplyField: type: @@ -251,17 +270,35 @@ structs: unstable: true CppTypeNotEqualUnstableReply: - description: "This reply contains a field whose old and new type have a bson_serialization_type - that contains 'any' and the cpp_types are not equal and where the old field - is unstable" + description: "This reply contains a field whose old and new type have a + bson_serialization_type that contains 'any' and the cpp_types are + not equal and where the old field is unstable" fields: cppTypeNotEqualReplyUnstableField: type: bsonSerializationTypeAnyCppTypeNotEqual unstable: true + SerializerNotEqualUnstableReply: + description: "This reply contains a field whose old and new type have a + bson_serialization_type that contains 'any' and the serializers are + not equal and where the old field is unstable" + fields: + serializerNotEqualReplyUnstableField: + type: bsonSerializationTypeAnySerializerNotEqual + unstable: true + + DeserializerNotEqualUnstableReply: + description: "This reply contains a field whose old and new type have a + bson_serialization_type that contains 'any' and the deserializers are + not equal and where the old field is unstable" + fields: + deserializerNotEqualReplyUnstableField: + type: bsonSerializationTypeAnyDeserializerNotEqual + unstable: true + NewlyAddedBsonSerializationTypeAnyStruct: - description: "This struct contains a newly added field whose type has a bson_serialization_type - that contains 'any' that is not explicitly allowed" + description: "This struct contains a newly added field whose type has a + bson_serialization_type that contains 'any' that is not explicitly allowed" fields: newlyAddedBsonSerializationTypeAnyStructField: unstable: true @@ -305,17 +342,35 @@ structs: variant: [oldBsonSerializationTypeAny, newBsonSerializationTypeAny] CppTypeNotEqualUnstableStruct: - description: "This struct contains a field whose old and new type have a bson_serialization_type - that contains 'any' and the cpp_types are not equal and where the old field - is unstable" + description: "This struct contains a field whose old and new type have a + bson_serialization_type that contains 'any' and the cpp_types are + not equal and where the old field is unstable" fields: cppTypeNotEqualStructUnstableField: unstable: true type: bsonSerializationTypeAnyCppTypeNotEqual + SerializerNotEqualUnstableStruct: + description: "This struct contains a field whose old and new type have a + bson_serialization_type that contains 'any' and the serializers are + not equal and where the old field is unstable" + fields: + serializerNotEqualStructUnstableField: + unstable: true + type: bsonSerializationTypeAnySerializerNotEqual + + DeserializerNotEqualUnstableStruct: + description: "This struct contains a field whose old and new type have a + bson_serialization_type that contains 'any' and the deserializers are + not equal and where the old field is unstable" + fields: + deserializerNotEqualStructUnstableField: + unstable: true + type: bsonSerializationTypeAnyDeserializerNotEqual + BsonSerializationTypeWithVariantAnyStruct: - description: "This struct contains a field whose old and new variant types have a bson_serialization_type - that contains 'any' that is not compatible" + description: "This struct contains a field whose old and new variant types have a + bson_serialization_type that contains 'any' that is not compatible" fields: bsonSerializationTypeAnyStructField: type: @@ -331,28 +386,44 @@ structs: array<newBsonSerializationTypeAny>] CppTypeNotEqualReply: - description: "This reply contains a field whose old and new type have a bson_serialization_type - that contains 'any' and the cpp_types are not equal" + description: "This reply contains a field whose old and new type have a + bson_serialization_type that contains 'any' and the cpp_types are not equal" fields: cppTypeNotEqualReplyField: type: bsonSerializationTypeAnyCppTypeNotEqual + SerializerNotEqualReply: + description: "This reply contains a field whose old and new type have a + bson_serialization_type that contains 'any' and + the serializers are not equal" + fields: + serializerNotEqualReplyField: + type: bsonSerializationTypeAnySerializerNotEqual + + DeserializerNotEqualReply: + description: "This reply contains a field whose old and new type have a + bson_serialization_type that contains 'any' and + the deserializers are not equal" + fields: + deserializerNotEqualReplyField: + type: bsonSerializationTypeAnyDeserializerNotEqual + StructFieldTypeRecursiveReplyOne: - description: "This reply contains a field whose new type is a struct that is not + description: "This reply contains a field whose new type is a struct that is not compatible with the old field type" fields: structReplyField: type: UnstableNewFieldReply - + StructFieldTypeRecursiveReplyTwo: - description: "This reply contains a field whose new type is a struct that is not + description: "This reply contains a field whose new type is a struct that is not compatible with the old field type" fields: structReplyField: type: StructType StructType: - description: "This struct contains a field whose new type is incompatible with the + description: "This struct contains a field whose new type is incompatible with the old field type" fields: fieldOne: @@ -370,23 +441,23 @@ structs: of the old variant types" fields: variantNotSubsetReplyField: - type: + type: variant: [int, string] - + NewVariantNotSubsetReplyWithArray: description: "This reply contains a field whose new variant types are not a subset of the old variant types" fields: variantNotSubsetReplyField: - type: + type: variant: [array<int>, array<string>] - + NewVariantNotSubsetReplyTwo: description: "This reply contains a field whose new variant types are not a subset of the old variant types" fields: variantNotSubsetReplyFieldTwo: - type: + type: variant: [int, string] NewVariantNotSubsetReplyTwoWithArray: @@ -394,7 +465,7 @@ structs: of the old variant types" fields: variantNotSubsetReplyFieldTwo: - type: + type: variant: [array<int>, array<string>] VariantRecursiveReply: @@ -402,15 +473,15 @@ structs: compatible with the old variant type" fields: variantRecursiveReplyField: - type: + type: variant: [int, intStringToIntStringBool] - + VariantRecursiveReplyWithArray: description: "This reply contains a field that has a new variant type that is not compatible with the old variant type" fields: variantRecursiveReplyField: - type: + type: variant: [array<int>, array<intStringToIntStringBool>] NewVariantStructNotSubsetReply: @@ -418,7 +489,7 @@ structs: of the old variant types" fields: variantStructNotSubsetReplyField: - type: + type: variant: [int, string] NewVariantStructNotSubsetReplyWithArray: @@ -426,7 +497,7 @@ structs: of the old variant types" fields: variantStructNotSubsetReplyField: - type: + type: variant: [array<int>, array<string>] VariantStructRecursiveReply: @@ -434,7 +505,7 @@ structs: compatible with the old variant struct type" fields: variantStructRecursiveReplyField: - type: + type: variant: [int, StructFieldTypeRecursiveReplyTwo] VariantStructRecursiveReplyWithArray: @@ -442,7 +513,7 @@ structs: compatible with the old variant struct type" fields: variantStructRecursiveReplyField: - type: + type: variant: [array<int>, array<StructFieldTypeRecursiveReplyTwo>] CommandParamStructRecursiveOne: @@ -501,7 +572,7 @@ structs: of the old variant types" fields: variantNotSupersetField: - type: + type: variant: [int, bool, string] VariantNotSupersetStructWithArray: @@ -509,7 +580,7 @@ structs: of the old variant types" fields: variantNotSupersetField: - type: + type: variant: [array<int>, array<bool>, array<string>] VariantNotSupersetStructTwo: @@ -517,7 +588,7 @@ structs: of the old variant types" fields: variantNotSupersetFieldTwo: - type: + type: variant: [int, bool, string, double] VariantNotSupersetStructTwoWithArray: @@ -525,7 +596,7 @@ structs: of the old variant types" fields: variantNotSupersetFieldTwo: - type: + type: variant: [array<int>, array<bool>, array<string>, array<double>] NewTypeNotVariantStruct: @@ -533,7 +604,7 @@ structs: old one is" fields: variantField: - type: + type: variant: [int, bool] VariantRecursiveStruct: @@ -541,7 +612,7 @@ structs: compatible with the old variant types" fields: variantRecursiveField: - type: + type: variant: [int, intStringBoolToIntString] VariantRecursiveStructWithArray: @@ -549,7 +620,7 @@ structs: compatible with the old variant types" fields: variantRecursiveField: - type: + type: variant: [array<int>, array<intStringBoolToIntString>] VariantStructNotSupersetStruct: @@ -557,7 +628,7 @@ structs: while the new one does not" fields: variantStructNotSupersetField: - type: + type: variant: [int, string, StructCommandParameterType] VariantStructNotSupersetStructWithArray: @@ -565,7 +636,7 @@ structs: while the new one does not" fields: variantStructNotSupersetField: - type: + type: variant: [array<int>, array<string>, array<StructCommandParameterType>] VariantStructRecursiveStruct: @@ -611,7 +682,7 @@ commands: reply_type: OkReply removedCommand: - description: "command will be removed from compatibility_test_fail/new which results + description: "command will be removed from compatibility_test_fail/new which results in an error" command_name: removedCommand namespace: ignored @@ -775,6 +846,34 @@ commands: cppTypeNotEqualParam: type: bsonSerializationTypeAnyCppTypeNotEqual + commandParameterSerializerNotEqual: + description: "command fails because it has a parameter type that has a + bson_serialization_type that contains 'any' and where the serializers + are not equal" + command_name: commandParameterSerializerNotEqual + namespace: ignored + cpp_name: commandParameterSerializerNotEqual + strict: true + api_version: "1" + reply_type: OkReply + fields: + serializerNotEqualParam: + type: bsonSerializationTypeAnySerializerNotEqual + + commandParameterDeserializerNotEqual: + description: "command fails because it has a parameter type that has a + bson_serialization_type that contains 'any' and where the deserializers + are not equal" + command_name: commandParameterDeserializerNotEqual + namespace: ignored + cpp_name: commandParameterDeserializerNotEqual + strict: true + api_version: "1" + reply_type: OkReply + fields: + deserializerNotEqualParam: + type: bsonSerializationTypeAnyDeserializerNotEqual + oldCommandParamTypeBsonAnyUnstable: description: "old command fails because it has a parameter type that has a bson_serialization_type that contains 'any' and the old param is unstable" @@ -833,6 +932,36 @@ commands: type: bsonSerializationTypeAnyCppTypeNotEqual unstable: true + commandParameterSerializerNotEqualUnstable: + description: "command fails because it has a parameter type that has a + bson_serialization_type that contains 'any' and where the serializers + are not equal" + command_name: commandParameterSerializerNotEqualUnstable + namespace: ignored + cpp_name: commandParameterSerializerNotEqualUnstable + strict: true + api_version: "1" + reply_type: OkReply + fields: + serializerNotEqualParam: + type: bsonSerializationTypeAnySerializerNotEqual + unstable: true + + commandParameterDeserializerNotEqualUnstable: + description: "command fails because it has a parameter type that has a + bson_serialization_type that contains 'any' and where the deserializers + are not equal" + command_name: commandParameterDeserializerNotEqualUnstable + namespace: ignored + cpp_name: commandParameterDeserializerNotEqualUnstable + strict: true + api_version: "1" + reply_type: OkReply + fields: + deserializerNotEqualParam: + type: bsonSerializationTypeAnyDeserializerNotEqual + unstable: true + parameterFieldTypeBsonAnyWithVariantUnstable: description: "command fails when its paramter field variant types have bson_serialization_type 'any' that is not compatible with each other" @@ -895,7 +1024,7 @@ commands: fields: newParamNotStruct: type: StructCommandParameterType - + newCommandParameterTypeEnumOrStructOne: description: "new command fails because its parameter type is an enum while the parameter type in the old command is an non-enum or non-struct" @@ -1025,7 +1154,7 @@ commands: strict: true api_version: "1" reply_type: UnstableNewFieldReply - + newReplyFieldOptional: description: "new command fails because it contains an optional reply field that is required in the corresponding old command" @@ -1045,7 +1174,7 @@ commands: strict: true api_version: "1" reply_type: MissingNewFieldReply - + importedReplyCommand: description: "reply is imported and should fail" command_name: importedReplyCommand @@ -1196,8 +1325,8 @@ commands: strict: true api_version: "1" reply_type: OkReply - fields: - variantAnyField: + fields: + variantAnyField: type: BsonSerializationTypeWithVariantAnyStruct parameterFieldTypeBsonAnyWithVariantWithArray: @@ -1209,8 +1338,8 @@ commands: strict: true api_version: "1" reply_type: OkReply - fields: - variantAnyField: + fields: + variantAnyField: type: BsonSerializationTypeWithVariantAnyStructWithArray commandTypeBsonAnyWithVariant: @@ -1234,7 +1363,7 @@ commands: strict: true api_version: "1" reply_type: OkReply - + replyFieldCppTypeNotEqual: description: "command fails because its reply field type has a bson_serialization_type that contains 'any', and the cpp_types are not equal" @@ -1245,6 +1374,26 @@ commands: api_version: "1" reply_type: CppTypeNotEqualReply + replyFieldSerializerNotEqual: + description: "command fails because its reply field type has a bson_serialization_type + that contains 'any', and the serializers are not equal" + command_name: replyFieldSerializerNotEqual + namespace: ignored + cpp_name: replyFieldSerializerNotEqual + strict: true + api_version: "1" + reply_type: SerializerNotEqualReply + + replyFieldDeserializerNotEqual: + description: "command fails because its reply field type has a bson_serialization_type + that contains 'any', and the deserializers are not equal" + command_name: replyFieldDeserializerNotEqual + namespace: ignored + cpp_name: replyFieldDeserializerNotEqual + strict: true + api_version: "1" + reply_type: DeserializerNotEqualReply + oldReplyFieldTypeBsonAnyUnstable: description: "old command fails when its reply field type has a bson_serialization_type that contains 'any' and the old reply field is unstable" @@ -1287,7 +1436,8 @@ commands: replyFieldCppTypeNotEqualUnstable: description: "command fails because its reply field type has a bson_serialization_type - that contains 'any', and the cpp_types are not equal and the old reply field is unstable" + that contains 'any', and the cpp_types are not equal and + the old reply field is unstable" command_name: replyFieldCppTypeNotEqualUnstable namespace: ignored cpp_name: replyFieldCppTypeNotEqualUnstable @@ -1295,9 +1445,31 @@ commands: api_version: "1" reply_type: CppTypeNotEqualUnstableReply + replyFieldSerializerNotEqualUnstable: + description: "command fails because its reply field type has a bson_serialization_type + that contains 'any', and the serializers are not equal and + the old reply field is unstable" + command_name: replyFieldSerializerNotEqualUnstable + namespace: ignored + cpp_name: replyFieldSerializerNotEqualUnstable + strict: true + api_version: "1" + reply_type: SerializerNotEqualUnstableReply + + replyFieldDeserializerNotEqualUnstable: + description: "command fails because its reply field type has a bson_serialization_type + that contains 'any', and the deserializers are not equal and + the old reply field is unstable" + command_name: replyFieldDeserializerNotEqualUnstable + namespace: ignored + cpp_name: replyFieldDeserializerNotEqualUnstable + strict: true + api_version: "1" + reply_type: DeserializerNotEqualUnstableReply + newlyAddedReplyFieldTypeBsonAnyNotAllowed: - description: "command fails because it has a newly added reply field type has a bson_serialization_type - that contains 'any' that is not explicitly allowed" + description: "command fails because it has a newly added reply field type has a + bson_serialization_type that contains 'any' that is not explicitly allowed" command_name: newlyAddedReplyFieldTypeBsonAnyNotAllowed namespace: ignored cpp_name: newlyAddedReplyFieldTypeBsonAnyNotAllowed @@ -1430,6 +1602,28 @@ commands: api_version: "1" reply_type: OkReply + commandSerializerNotEqual: + description: "command fails because its type has a bson_serialization_type + that contains 'any' and the serializers are not equal" + command_name: commandSerializerNotEqual + namespace: type + type: bsonSerializationTypeAnySerializerNotEqual + cpp_name: commandSerializerNotEqual + strict: true + api_version: "1" + reply_type: OkReply + + commandDeserializerNotEqual: + description: "command fails because its type has a bson_serialization_type + that contains 'any' and the deserializers are not equal" + command_name: commandDeserializerNotEqual + namespace: type + type: bsonSerializationTypeAnyDeserializerNotEqual + cpp_name: commandDeserializerNotEqual + strict: true + api_version: "1" + reply_type: OkReply + oldTypeBsonAnyUnstable: description: "old command fails because its type has a bson_serialization_type that contains 'any' and the old type field is unstable" @@ -1465,7 +1659,8 @@ commands: commandCppTypeNotEqualUnstable: description: "command fails because its type has a bson_serialization_type - that contains 'any' and the cpp_types are not equal and the old type field is unstable" + that contains 'any' and the cpp_types are not equal and + the old type field is unstable" command_name: commandCppTypeNotEqualUnstable namespace: type type: CppTypeNotEqualUnstableStruct @@ -1474,9 +1669,34 @@ commands: api_version: "1" reply_type: OkReply + commandSerializerNotEqualUnstable: + description: "command fails because its type has a bson_serialization_type + that contains 'any' and the serializers are not equal and + the old type field is unstable" + command_name: commandSerializerNotEqualUnstable + namespace: type + type: SerializerNotEqualUnstableStruct + cpp_name: commandSerializerNotEqualUnstable + strict: true + api_version: "1" + reply_type: OkReply + + commandDeserializerNotEqualUnstable: + description: "command fails because its type has a bson_serialization_type + that contains 'any' and the deserializers are not equal and + the old type field is unstable" + command_name: commandDeserializerNotEqualUnstable + namespace: type + type: DeserializerNotEqualUnstableStruct + cpp_name: commandDeserializerNotEqualUnstable + strict: true + api_version: "1" + reply_type: OkReply + commandTypeBsonAnyWithVariantUnstable: description: "command fails when its variant types have bson_serialization_type - 'any' that is not compatible with each other and the old type field is unstable" + 'any' that is not compatible with each other and + the old type field is unstable" command_name: commandTypeBsonAnyWithVariantUnstable namespace: type type: BsonSerializationTypeWithVariantAnyUnstableStruct @@ -1594,7 +1814,7 @@ commands: strict: true api_version: "1" reply_type: OkReply - + newTypeFieldAddedRequired: description: "new command fails because it has an added type field that is required when it should be optional" @@ -1626,7 +1846,7 @@ commands: strict: true api_version: "1" reply_type: NewVariantTypeReply - + newReplyFieldVariantNotSubset: description: "new command fails because its reply field type is a variant type that is not a subset of the old reply field variant types" @@ -1740,7 +1960,7 @@ commands: reply_type: OkReply fields: variantNotSupersetParam: - type: + type: variant: [int, bool, string] newParamVariantNotSupersetWithArray: @@ -1754,7 +1974,7 @@ commands: reply_type: OkReply fields: variantNotSupersetParam: - type: + type: variant: [array<int>, array<bool>, array<string>] newParamVariantNotSupersetTwo: @@ -1768,7 +1988,7 @@ commands: reply_type: OkReply fields: variantNotSupersetParamTwo: - type: + type: variant: [int, bool, string, double] newParamVariantNotSupersetTwoWithArray: @@ -1782,7 +2002,7 @@ commands: reply_type: OkReply fields: variantNotSupersetParamTwo: - type: + type: variant: [array<int>, array<bool>, array<string>, array<double>] newParamTypeNotVariant: @@ -1796,7 +2016,7 @@ commands: reply_type: OkReply fields: variantParam: - type: + type: variant: [int, bool] newParamVariantRecursive: @@ -1810,7 +2030,7 @@ commands: reply_type: OkReply fields: variantRecursiveParam: - type: + type: variant: [int, intStringBoolToIntString] newParamVariantRecursiveWithArray: @@ -1824,7 +2044,7 @@ commands: reply_type: OkReply fields: variantRecursiveParam: - type: + type: variant: [array<int>, array<intStringBoolToIntString>] newParamVariantStructNotSuperset: @@ -1838,7 +2058,7 @@ commands: reply_type: OkReply fields: variantStructNotSupersetParam: - type: + type: variant: [int, string, StructCommandParameterType] newParamVariantStructNotSupersetWithArray: @@ -1852,7 +2072,7 @@ commands: reply_type: OkReply fields: variantStructNotSupersetParam: - type: + type: variant: [array<int>, array<string>, array<StructCommandParameterType>] newParamVariantStructRecursive: @@ -2167,7 +2387,7 @@ commands: - check: checkOne complexChecksNotSubset: - description: "new command fails because the complex checks are not a subset of the + description: "new command fails because the complex checks are not a subset of the old complex checks" command_name: complexChecksNotSubset namespace: ignored @@ -2181,7 +2401,7 @@ commands: - check: checkTwo complexChecksNotSubsetTwo: - description: "new command fails because the complex checks are not a subset of the + description: "new command fails because the complex checks are not a subset of the old complex checks" command_name: complexChecksNotSubsetTwo namespace: ignored diff --git a/buildscripts/idl/tests/test_compatibility.py b/buildscripts/idl/tests/test_compatibility.py index 89a4e6130c6..56cf3e68408 100644 --- a/buildscripts/idl/tests/test_compatibility.py +++ b/buildscripts/idl/tests/test_compatibility.py @@ -92,7 +92,7 @@ class TestIDLCompatibilityChecker(unittest.TestCase): path.join(dir_path, "compatibility_test_fail/new"), ["src"]) self.assertTrue(error_collection.has_errors()) - self.assertTrue(error_collection.count() == 164) + self.assertEqual(error_collection.count(), 170) invalid_api_version_new_error = error_collection.get_error_by_command_name( "invalidAPIVersionNew") @@ -212,6 +212,21 @@ class TestIDLCompatibilityChecker(unittest.TestCase): self.assertRegex( str(command_parameter_cpp_type_not_equal_error), "commandParameterCppTypeNotEqual") + command_parameter_serializer_not_equal_error = error_collection.get_error_by_command_name( + "commandParameterSerializerNotEqual") + self.assertEqual(command_parameter_serializer_not_equal_error.error_id, + idl_compatibility_errors.ERROR_ID_COMMAND_PARAMETER_SERIALIZER_NOT_EQUAL) + self.assertRegex( + str(command_parameter_serializer_not_equal_error), "commandParameterSerializerNotEqual") + + command_parameter_deserializer_not_equal_error = error_collection.get_error_by_command_name( + "commandParameterDeserializerNotEqual") + self.assertTrue(command_parameter_deserializer_not_equal_error.error_id == + idl_compatibility_errors.ERROR_ID_COMMAND_PARAMETER_DESERIALIZER_NOT_EQUAL) + self.assertRegex( + str(command_parameter_deserializer_not_equal_error), + "commandParameterDeserializerNotEqual") + old_command_parameter_type_bson_any_unstable_error = error_collection.get_error_by_command_name( "oldCommandParamTypeBsonAnyUnstable") self.assertTrue( @@ -612,6 +627,20 @@ class TestIDLCompatibilityChecker(unittest.TestCase): idl_compatibility_errors.ERROR_ID_REPLY_FIELD_CPP_TYPE_NOT_EQUAL) self.assertRegex(str(reply_field_cpp_type_not_equal_error), "replyFieldCppTypeNotEqual") + reply_field_serializer_not_equal_error = error_collection.get_error_by_command_name( + "replyFieldSerializerNotEqual") + self.assertTrue(reply_field_serializer_not_equal_error.error_id == + idl_compatibility_errors.ERROR_ID_REPLY_FIELD_SERIALIZER_NOT_EQUAL) + self.assertRegex( + str(reply_field_serializer_not_equal_error), "replyFieldSerializerNotEqual") + + reply_field_deserializer_not_equal_error = error_collection.get_error_by_command_name( + "replyFieldDeserializerNotEqual") + self.assertTrue(reply_field_deserializer_not_equal_error.error_id == + idl_compatibility_errors.ERROR_ID_REPLY_FIELD_DESERIALIZER_NOT_EQUAL) + self.assertRegex( + str(reply_field_deserializer_not_equal_error), "replyFieldDeserializerNotEqual") + new_reply_field_type_struct_one_error = error_collection.get_error_by_command_name( "newReplyFieldTypeStructRecursiveOne") self.assertTrue(new_reply_field_type_struct_one_error.error_id == @@ -687,6 +716,18 @@ class TestIDLCompatibilityChecker(unittest.TestCase): idl_compatibility_errors.ERROR_ID_COMMAND_CPP_TYPE_NOT_EQUAL) self.assertRegex(str(command_cpp_type_not_equal_error), "commandCppTypeNotEqual") + command_serializer_not_equal_error = error_collection.get_error_by_command_name( + "commandSerializerNotEqual") + self.assertTrue(command_serializer_not_equal_error.error_id == + idl_compatibility_errors.ERROR_ID_COMMAND_SERIALIZER_NOT_EQUAL) + self.assertRegex(str(command_serializer_not_equal_error), "commandSerializerNotEqual") + + command_deserializer_not_equal_error = error_collection.get_error_by_command_name( + "commandDeserializerNotEqual") + self.assertTrue(command_deserializer_not_equal_error.error_id == + idl_compatibility_errors.ERROR_ID_COMMAND_DESERIALIZER_NOT_EQUAL) + self.assertRegex(str(command_deserializer_not_equal_error), "commandDeserializerNotEqual") + old_type_bson_any_unstable_error = error_collection.get_error_by_command_name( "oldTypeBsonAnyUnstable") self.assertTrue(old_type_bson_any_unstable_error.error_id == idl_compatibility_errors. diff --git a/src/mongo/db/ops/write_ops.cpp b/src/mongo/db/ops/write_ops.cpp index 8e00f19713a..f69ad8844bb 100644 --- a/src/mongo/db/ops/write_ops.cpp +++ b/src/mongo/db/ops/write_ops.cpp @@ -79,6 +79,10 @@ void checkOpCountForCommand(const T& op, size_t numOps) { namespace write_ops { +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ bool readMultiDeleteProperty(const BSONElement& limitElement) { // Using a double to avoid throwing away illegal fractional portion. Don't want to accept 0.5 // here @@ -90,6 +94,10 @@ bool readMultiDeleteProperty(const BSONElement& limitElement) { return limit == 0; } +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ void writeMultiDeleteProperty(bool isMulti, StringData fieldName, BSONObjBuilder* builder) { builder->append(fieldName, isMulti ? 0 : 1); } @@ -328,6 +336,10 @@ write_ops::UpdateModification::UpdateModification(const BSONObj& update, Classic write_ops::UpdateModification::UpdateModification(std::vector<BSONObj> pipeline) : _update{PipelineUpdate{std::move(pipeline)}} {} +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ write_ops::UpdateModification write_ops::UpdateModification::parseFromBSON(BSONElement elem) { return UpdateModification(elem); } @@ -363,6 +375,10 @@ write_ops::UpdateModification::Type write_ops::UpdateModification::type() const _update); } +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ void write_ops::UpdateModification::serializeToBSON(StringData fieldName, BSONObjBuilder* bob) const { diff --git a/src/mongo/db/ops/write_ops_parsers.h b/src/mongo/db/ops/write_ops_parsers.h index 20b9f543bc7..900740b271b 100644 --- a/src/mongo/db/ops/write_ops_parsers.h +++ b/src/mongo/db/ops/write_ops_parsers.h @@ -51,11 +51,17 @@ constexpr int kRetryableAndTxnBatchWriteBSONSizeOverhead = /** * Parses the 'limit' property of a delete entry, which has inverted meaning from the 'multi' * property of an update. + * + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. */ bool readMultiDeleteProperty(const BSONElement& limitElement); /** * Writes the 'isMulti' value as a limit property. + * + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. */ void writeMultiDeleteProperty(bool isMulti, StringData fieldName, BSONObjBuilder* builder); @@ -100,8 +106,16 @@ public: /** * These methods support IDL parsing of the "u" field from the update command and OP_UPDATE. + * + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. */ static UpdateModification parseFromBSON(BSONElement elem); + + /** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ void serializeToBSON(StringData fieldName, BSONObjBuilder* bob) const; // When parsing from legacy OP_UPDATE messages, we receive the "u" field as an object. When an diff --git a/src/mongo/db/pipeline/aggregation_request_helper.cpp b/src/mongo/db/pipeline/aggregation_request_helper.cpp index 133e151dae6..5bfa4b7c2a3 100644 --- a/src/mongo/db/pipeline/aggregation_request_helper.cpp +++ b/src/mongo/db/pipeline/aggregation_request_helper.cpp @@ -241,6 +241,10 @@ PlanExecutorPipeline::ResumableScanType getResumableScanType(const AggregateComm // Custom serializers/deserializers for AggregateCommandRequest. +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ boost::optional<mongo::ExplainOptions::Verbosity> parseExplainModeFromBSON( const BSONElement& explainElem) { uassert(ErrorCodes::TypeMismatch, @@ -254,6 +258,10 @@ boost::optional<mongo::ExplainOptions::Verbosity> parseExplainModeFromBSON( return boost::none; } +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ void serializeExplainToBSON(const mongo::ExplainOptions::Verbosity& explain, StringData fieldName, BSONObjBuilder* builder) { @@ -264,6 +272,10 @@ void serializeExplainToBSON(const mongo::ExplainOptions::Verbosity& explain, return; } +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ mongo::SimpleCursorOptions parseAggregateCursorFromBSON(const BSONElement& cursorElem) { if (cursorElem.eoo()) { SimpleCursorOptions cursor; @@ -284,6 +296,10 @@ mongo::SimpleCursorOptions parseAggregateCursorFromBSON(const BSONElement& curso return cursor; } +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ void serializeAggregateCursorToBSON(const mongo::SimpleCursorOptions& cursor, StringData fieldName, BSONObjBuilder* builder) { diff --git a/src/mongo/db/pipeline/aggregation_request_helper.h b/src/mongo/db/pipeline/aggregation_request_helper.h index 631fd87a278..bb447712f7f 100644 --- a/src/mongo/db/pipeline/aggregation_request_helper.h +++ b/src/mongo/db/pipeline/aggregation_request_helper.h @@ -131,23 +131,40 @@ PlanExecutorPipeline::ResumableScanType getResumableScanType(const AggregateComm /** * Custom serializers/deserializers for AggregateCommandRequest. + * + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. */ - boost::optional<mongo::ExplainOptions::Verbosity> parseExplainModeFromBSON( const BSONElement& explainElem); +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ void serializeExplainToBSON(const mongo::ExplainOptions::Verbosity& explain, StringData fieldName, BSONObjBuilder* builder); +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ mongo::SimpleCursorOptions parseAggregateCursorFromBSON(const BSONElement& cursorElem); +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ void serializeAggregateCursorToBSON(const SimpleCursorOptions& cursor, StringData fieldName, BSONObjBuilder* builder); /** * Parse an aggregation pipeline definition from 'pipelineElem'. + * + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. */ static std::vector<BSONObj> parsePipelineFromBSON(const BSONElement& pipelineElem) { std::vector<BSONObj> pipeline; diff --git a/src/mongo/db/pipeline/aggregation_request_test.cpp b/src/mongo/db/pipeline/aggregation_request_test.cpp index 66bac44423c..947764892b7 100644 --- a/src/mongo/db/pipeline/aggregation_request_test.cpp +++ b/src/mongo/db/pipeline/aggregation_request_test.cpp @@ -554,6 +554,23 @@ TEST(AggregationRequestTest, ShouldRejectNoCursorNoExplain) { aggregation_request_helper::parseFromBSONForTests(nss, cursorRequest.done()).getStatus()); } +TEST(AggregationRequestTest, ShouldRejectNonObjectCursor) { + NamespaceString nss("a.collection"); + const BSONObj validRequest = fromjson( + "{aggregate: 'collection'," + "pipeline: [{$match: {a: 'abc'}}]," + "cursor: {}," + "isMapReduceCommand: true," + "$db: 'a'}"); + const BSONObj nonObjCursorCommand = fromjson("{cursor: 1}"); + aggregationRequestParseFailureHelper( + nss, validRequest, nonObjCursorCommand, ErrorCodes::TypeMismatch); + + const BSONObj arrayCursorCommand = fromjson("{cursor: []}"); + aggregationRequestParseFailureHelper( + nss, validRequest, arrayCursorCommand, ErrorCodes::TypeMismatch); +} + TEST(AggregationRequestTest, ShouldRejectExplainTrueWithSeparateExplainArg) { NamespaceString nss("a.collection"); const BSONObj validRequest = fromjson( diff --git a/src/mongo/db/query/hint_parser.cpp b/src/mongo/db/query/hint_parser.cpp index d1372d86f55..1de75b84f82 100644 --- a/src/mongo/db/query/hint_parser.cpp +++ b/src/mongo/db/query/hint_parser.cpp @@ -33,6 +33,10 @@ namespace mongo { +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ BSONObj parseHint(const BSONElement& element) { if (element.type() == BSONType::String) { return BSON("$hint" << element.valueStringData()); @@ -44,6 +48,10 @@ BSONObj parseHint(const BSONElement& element) { MONGO_UNREACHABLE; } +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ void serializeHintToBSON(const BSONObj& hint, StringData fieldName, BSONObjBuilder* builder) { if (hint.isEmpty()) return; diff --git a/src/mongo/db/query/max_time_ms_parser.cpp b/src/mongo/db/query/max_time_ms_parser.cpp index 7f2c84f07ad..054b2b76ead 100644 --- a/src/mongo/db/query/max_time_ms_parser.cpp +++ b/src/mongo/db/query/max_time_ms_parser.cpp @@ -62,6 +62,10 @@ StatusWith<int> parseMaxTimeMS(BSONElement maxTimeMSElt) { return StatusWith<int>(static_cast<int>(maxTimeMSLongLong)); } +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ int32_t parseMaxTimeMSForIDL(BSONElement maxTimeMSElt) { return static_cast<int32_t>(uassertStatusOK(parseMaxTimeMS(maxTimeMSElt))); } diff --git a/src/mongo/db/query/max_time_ms_parser.h b/src/mongo/db/query/max_time_ms_parser.h index 1e5ec985c77..d111b480599 100644 --- a/src/mongo/db/query/max_time_ms_parser.h +++ b/src/mongo/db/query/max_time_ms_parser.h @@ -56,6 +56,10 @@ static constexpr auto kMaxTimeMSOpOnlyMaxPadding = 100LL; */ StatusWith<int> parseMaxTimeMS(BSONElement maxTimeMSElt); +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ int32_t parseMaxTimeMSForIDL(BSONElement maxTimeMSElt); } // namespace mongo diff --git a/src/mongo/db/query/query_request_test.cpp b/src/mongo/db/query/query_request_test.cpp index e60a04ff79e..8518c0e4661 100644 --- a/src/mongo/db/query/query_request_test.cpp +++ b/src/mongo/db/query/query_request_test.cpp @@ -1194,36 +1194,74 @@ TEST(QueryRequestTest, ParseFromCommandForbidExtraOption) { TEST(QueryRequestTest, ParseMaxTimeMSStringValueFails) { BSONObj maxTimeObj = BSON(query_request_helper::cmdOptionMaxTimeMS << "foo"); - ASSERT_NOT_OK(parseMaxTimeMS(maxTimeObj[query_request_helper::cmdOptionMaxTimeMS])); + ASSERT_THROWS_CODE(parseMaxTimeMSForIDL(maxTimeObj[query_request_helper::cmdOptionMaxTimeMS]), + DBException, + ErrorCodes::BadValue); +} + +TEST(QueryRequestTest, ParseMaxTimeMSBoolValueFails) { + BSONObj maxTimeObj = BSON(query_request_helper::cmdOptionMaxTimeMS << true); + ASSERT_THROWS_CODE(parseMaxTimeMSForIDL(maxTimeObj[query_request_helper::cmdOptionMaxTimeMS]), + DBException, + ErrorCodes::BadValue); +} + +TEST(QueryRequestTest, ParseMaxTimeMSNullValueFails) { + BSONObj maxTimeObj = BSON(query_request_helper::cmdOptionMaxTimeMS << BSONNULL); + ASSERT_THROWS_CODE(parseMaxTimeMSForIDL(maxTimeObj[query_request_helper::cmdOptionMaxTimeMS]), + DBException, + ErrorCodes::BadValue); +} + +TEST(QueryRequestTest, ParseMaxTimeMSUndefinedValueFails) { + BSONObj maxTimeObj = BSON(query_request_helper::cmdOptionMaxTimeMS << BSONUndefined); + ASSERT_THROWS_CODE(parseMaxTimeMSForIDL(maxTimeObj[query_request_helper::cmdOptionMaxTimeMS]), + DBException, + ErrorCodes::BadValue); +} + +TEST(QueryRequestTest, ParseMaxTimeMSEmptyObjectValueFails) { + const auto emptyObj = BSONObjBuilder().obj(); + BSONObj maxTimeObj = BSON(query_request_helper::cmdOptionMaxTimeMS << emptyObj); + ASSERT_THROWS_CODE(parseMaxTimeMSForIDL(maxTimeObj[query_request_helper::cmdOptionMaxTimeMS]), + DBException, + ErrorCodes::BadValue); } TEST(QueryRequestTest, ParseMaxTimeMSNonIntegralValueFails) { BSONObj maxTimeObj = BSON(query_request_helper::cmdOptionMaxTimeMS << 100.3); - ASSERT_NOT_OK(parseMaxTimeMS(maxTimeObj[query_request_helper::cmdOptionMaxTimeMS])); + ASSERT_THROWS_CODE(parseMaxTimeMSForIDL(maxTimeObj[query_request_helper::cmdOptionMaxTimeMS]), + DBException, + ErrorCodes::BadValue); } TEST(QueryRequestTest, ParseMaxTimeMSOutOfRangeDoubleFails) { BSONObj maxTimeObj = BSON(query_request_helper::cmdOptionMaxTimeMS << 1e200); - ASSERT_NOT_OK(parseMaxTimeMS(maxTimeObj[query_request_helper::cmdOptionMaxTimeMS])); + ASSERT_THROWS_CODE(parseMaxTimeMSForIDL(maxTimeObj[query_request_helper::cmdOptionMaxTimeMS]), + DBException, + ErrorCodes::BadValue); } TEST(QueryRequestTest, ParseMaxTimeMSNegativeValueFails) { BSONObj maxTimeObj = BSON(query_request_helper::cmdOptionMaxTimeMS << -400); - ASSERT_NOT_OK(parseMaxTimeMS(maxTimeObj[query_request_helper::cmdOptionMaxTimeMS])); + ASSERT_THROWS_CODE(parseMaxTimeMSForIDL(maxTimeObj[query_request_helper::cmdOptionMaxTimeMS]), + DBException, + ErrorCodes::BadValue); } TEST(QueryRequestTest, ParseMaxTimeMSZeroSucceeds) { BSONObj maxTimeObj = BSON(query_request_helper::cmdOptionMaxTimeMS << 0); - auto maxTime = parseMaxTimeMS(maxTimeObj[query_request_helper::cmdOptionMaxTimeMS]); - ASSERT_OK(maxTime); - ASSERT_EQ(maxTime.getValue(), 0); + ASSERT_EQ(parseMaxTimeMSForIDL(maxTimeObj[query_request_helper::cmdOptionMaxTimeMS]), 0); +} + +TEST(QueryRequestTest, ParseMaxTimeMSEmptyElementSucceeds) { + const auto emptyElem = BSONElement(); + ASSERT_EQ(parseMaxTimeMSForIDL(emptyElem), 0); } TEST(QueryRequestTest, ParseMaxTimeMSPositiveInRangeSucceeds) { BSONObj maxTimeObj = BSON(query_request_helper::cmdOptionMaxTimeMS << 300); - auto maxTime = parseMaxTimeMS(maxTimeObj[query_request_helper::cmdOptionMaxTimeMS]); - ASSERT_OK(maxTime); - ASSERT_EQ(maxTime.getValue(), 300); + ASSERT_EQ(parseMaxTimeMSForIDL(maxTimeObj[query_request_helper::cmdOptionMaxTimeMS]), 300); } TEST(QueryRequestTest, ConvertToAggregationSucceeds) { diff --git a/src/mongo/idl/basic_types.h b/src/mongo/idl/basic_types.h index c02366d3c5f..62e191a9bf5 100644 --- a/src/mongo/idl/basic_types.h +++ b/src/mongo/idl/basic_types.h @@ -47,6 +47,10 @@ namespace mongo { */ class OptionalBool { public: + /** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ static OptionalBool parseFromBSON(BSONElement element) { uassert(ErrorCodes::TypeMismatch, str::stream() << "Field '" << element.fieldNameStringData() @@ -76,6 +80,9 @@ public: /** * Serialize this object as a field in a document. If _value is empty, omit the field. + * + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. */ void serializeToBSON(StringData fieldName, BSONObjBuilder* builder) const { if (_value) { @@ -85,6 +92,9 @@ public: /** * Serialize this object as an element of a BSON array. If _value is empty, omit the entry. + * + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. */ void serializeToBSON(BSONArrayBuilder* builder) const { if (_value) { @@ -112,6 +122,10 @@ private: */ class IDLAnyType { public: + /** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ static IDLAnyType parseFromBSON(const BSONElement& element) { return IDLAnyType(element); } @@ -119,10 +133,18 @@ public: IDLAnyType() = default; IDLAnyType(const BSONElement& element) : _element(element) {} + /** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ void serializeToBSON(StringData fieldName, BSONObjBuilder* builder) const { builder->appendAs(_element, fieldName); } + /** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ void serializeToBSON(BSONArrayBuilder* builder) const { builder->append(_element); } @@ -141,6 +163,10 @@ protected: */ class IDLAnyTypeOwned : public IDLAnyType { public: + /** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ static IDLAnyTypeOwned parseFromBSON(const BSONElement& element) { return IDLAnyTypeOwned(element); } diff --git a/src/mongo/idl/idl_parser.cpp b/src/mongo/idl/idl_parser.cpp index 9cad14bffca..de0ffd40852 100644 --- a/src/mongo/idl/idl_parser.cpp +++ b/src/mongo/idl/idl_parser.cpp @@ -341,14 +341,26 @@ std::vector<std::vector<std::uint8_t>> transformVector(const std::vector<ConstDa return output; } +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ void noOpSerializer(bool, StringData fieldName, BSONObjBuilder* bob) {} +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ void serializeBSONWhenNotEmpty(BSONObj obj, StringData fieldName, BSONObjBuilder* bob) { if (!obj.isEmpty()) { bob->append(fieldName, obj); } } +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ BSONObj parseOwnedBSON(BSONElement element) { uassert(ErrorCodes::TypeMismatch, str::stream() << "Expected field " << element.fieldNameStringData() @@ -357,6 +369,10 @@ BSONObj parseOwnedBSON(BSONElement element) { return element.Obj().getOwned(); } +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ bool parseBoolean(BSONElement element) { uassert(ErrorCodes::TypeMismatch, str::stream() << "Expected field " << element.fieldNameStringData() diff --git a/src/mongo/idl/idl_parser.h b/src/mongo/idl/idl_parser.h index 47096c0d117..316ccd06c7e 100644 --- a/src/mongo/idl/idl_parser.h +++ b/src/mongo/idl/idl_parser.h @@ -289,12 +289,28 @@ std::vector<std::string> transformVector(const std::vector<StringData>& input); std::vector<ConstDataRange> transformVector(const std::vector<std::vector<std::uint8_t>>& input); std::vector<std::vector<std::uint8_t>> transformVector(const std::vector<ConstDataRange>& input); +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ void noOpSerializer(bool, StringData fieldName, BSONObjBuilder* bob); +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ void serializeBSONWhenNotEmpty(BSONObj obj, StringData fieldName, BSONObjBuilder* bob); +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ BSONObj parseOwnedBSON(BSONElement element); +/** + * IMPORTANT: The method should not be modified, as API version input/output guarantees could + * break because of it. + */ bool parseBoolean(BSONElement element); } // namespace mongo |