summaryrefslogtreecommitdiff
path: root/buildscripts/idl
diff options
context:
space:
mode:
authorAli Mir <ali.mir@mongodb.com>2021-03-30 14:52:45 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-04-06 21:08:15 +0000
commit6aaad044a819a50a690b932afeda9aa278ba0f2e (patch)
treecca2a96f43f41e396e8a30c715c813cb97b007a0 /buildscripts/idl
parent3b46d7c55ad4c0c9eb9135a0ac04c0990fae2f75 (diff)
downloadmongo-6aaad044a819a50a690b932afeda9aa278ba0f2e.tar.gz
SERVER-53211 Check for incompatible changes in generic_argument.idl in IDL compatibility checker script
Diffstat (limited to 'buildscripts/idl')
-rw-r--r--buildscripts/idl/idl/syntax.py16
-rw-r--r--buildscripts/idl/idl_check_compatibility.py58
-rw-r--r--buildscripts/idl/idl_compatibility_errors.py17
-rw-r--r--buildscripts/idl/tests/compatibility_test_fail/new_generic_argument/generic_argument.idl55
-rw-r--r--buildscripts/idl/tests/compatibility_test_fail/old_generic_argument/generic_argument.idl59
-rw-r--r--buildscripts/idl/tests/compatibility_test_pass/new_generic_argument/generic_argument.idl61
-rw-r--r--buildscripts/idl/tests/compatibility_test_pass/old_generic_argument/generic_argument.idl62
-rw-r--r--buildscripts/idl/tests/test_compatibility.py35
8 files changed, 361 insertions, 2 deletions
diff --git a/buildscripts/idl/idl/syntax.py b/buildscripts/idl/idl/syntax.py
index 13ebcb272b1..dbc02937631 100644
--- a/buildscripts/idl/idl/syntax.py
+++ b/buildscripts/idl/idl/syntax.py
@@ -208,6 +208,22 @@ class SymbolTable(object):
return struct
return None
+ def get_generic_argument_list(self, name):
+ # type: (str) -> GenericArgumentList
+ """Get a generic argument list from the SymbolTable based on the list name."""
+ for gen_arg_list in self.generic_argument_lists:
+ if gen_arg_list.name == name:
+ return gen_arg_list
+ return None
+
+ def get_generic_reply_field_list(self, name):
+ # type: (str) -> GenericReplyFieldList
+ """Get a generic reply field list from the SymbolTable based on the list name."""
+ for gen_reply_field_list in self.generic_reply_field_lists:
+ if gen_reply_field_list.name == name:
+ return gen_reply_field_list
+ return None
+
def resolve_type_from_name(self, ctxt, location, field_name, field_type_name):
# type: (errors.ParserContext, common.SourceLocation, str, str) -> Optional[Union[Enum, Struct, Type]]
"""Find the type or struct a field refers to or log an error."""
diff --git a/buildscripts/idl/idl_check_compatibility.py b/buildscripts/idl/idl_check_compatibility.py
index 4b9d1c5138d..120a42d5a4f 100644
--- a/buildscripts/idl/idl_check_compatibility.py
+++ b/buildscripts/idl/idl_check_compatibility.py
@@ -24,6 +24,8 @@
# delete this exception statement from your version. If you delete this
# exception statement from all source files in the program, then also delete
# it in the license file.
+#
+# pylint: disable=too-many-lines
"""Checks compatibility of old and new IDL files.
In order to support user-selectable API versions for the server, server commands are now
@@ -35,14 +37,13 @@ This script accepts two directories as arguments, the "old" and the "new" IDL di
Before running this script, run checkout_idl_files_from_past_releases.py to find and create
directories containing the old IDL files from previous releases.
"""
-# pylint: disable=too-many-lines
import argparse
import os
import sys
from dataclasses import dataclass
from enum import Enum
-from typing import Dict, List, Optional, Tuple, Union
+from typing import Dict, List, Set, Optional, Tuple, Union
from idl import parser, syntax, errors, common
from idl.compiler import CompilerImportResolver
@@ -995,6 +996,52 @@ def check_compatibility(old_idl_dir: str, new_idl_dir: str,
return ctxt.errors
+def get_generic_arguments(gen_args_file_path: str) -> Tuple[Set[str], Set[str]]:
+ """Get arguments and reply fields from generic_argument.idl and check validity."""
+ arguments: Set[str] = set()
+ reply_fields: Set[str] = set()
+
+ with open(gen_args_file_path) as gen_args_file:
+ parsed_idl_file = parser.parse(gen_args_file, gen_args_file_path,
+ CompilerImportResolver([]))
+ if parsed_idl_file.errors:
+ parsed_idl_file.errors.dump_errors()
+ raise ValueError(f"Cannot parse {gen_args_file_path}")
+ for argument in parsed_idl_file.spec.symbols.get_generic_argument_list(
+ "generic_args_api_v1").fields:
+ arguments.add(argument.name)
+
+ for reply_field in parsed_idl_file.spec.symbols.get_generic_reply_field_list(
+ "generic_reply_fields_api_v1").fields:
+ reply_fields.add(reply_field.name)
+
+ return arguments, reply_fields
+
+
+def check_generic_arguments_compatibility(old_gen_args_file_path: str, new_gen_args_file_path: str
+ ) -> IDLCompatibilityErrorCollection:
+ """Check IDL compatibility between old and new generic_argument.idl files."""
+ # IDLCompatibilityContext takes in both 'old_idl_dir' and 'new_idl_dir',
+ # but for generic_argument.idl, the parent directories aren't helpful for logging purposes.
+ # Instead, we pass in "old generic_argument.idl" and "new generic_argument.idl"
+ # to make error messages clearer.
+ ctxt = IDLCompatibilityContext("old generic_argument.idl", "new generic_argument.idl",
+ IDLCompatibilityErrorCollection())
+
+ old_arguments, old_reply_fields = get_generic_arguments(old_gen_args_file_path)
+ new_arguments, new_reply_fields = get_generic_arguments(new_gen_args_file_path)
+
+ for old_argument in old_arguments:
+ if old_argument not in new_arguments:
+ ctxt.add_generic_argument_removed(old_argument, new_gen_args_file_path)
+
+ for old_reply_field in old_reply_fields:
+ if old_reply_field not in new_reply_fields:
+ ctxt.add_generic_argument_removed_reply_field(old_reply_field, new_gen_args_file_path)
+
+ return ctxt.errors
+
+
def main():
"""Run the script."""
arg_parser = argparse.ArgumentParser(description=__doc__)
@@ -1017,6 +1064,13 @@ def main():
if error_reply_coll.has_errors():
sys.exit(1)
+ old_generic_args_path = os.path.join(args.old_idl_dir, "mongo/idl/generic_argument.idl")
+ new_generic_args_path = os.path.join(args.new_idl_dir, "mongo/idl/generic_argument.idl")
+ error_gen_args_coll = check_generic_arguments_compatibility(old_generic_args_path,
+ new_generic_args_path)
+ if error_gen_args_coll.has_errors():
+ sys.exit(1)
+
if __name__ == "__main__":
main()
diff --git a/buildscripts/idl/idl_compatibility_errors.py b/buildscripts/idl/idl_compatibility_errors.py
index 935e5e1703f..dc5c30a2105 100644
--- a/buildscripts/idl/idl_compatibility_errors.py
+++ b/buildscripts/idl/idl_compatibility_errors.py
@@ -25,6 +25,7 @@
# exception statement from all source files in the program, then also delete
# it in the license file.
#
+# pylint: disable=too-many-lines
"""
Common error handling code for IDL compatibility checker.
@@ -109,6 +110,8 @@ ERROR_ID_NEW_ADDITIONAL_COMPLEX_ACCESS_CHECK = "ID0065"
ERROR_ID_REMOVED_ACCESS_CHECK_FIELD = "ID0066"
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"
# 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
@@ -971,6 +974,20 @@ class IDLCompatibilityContext(object):
"'%s' has added the access_check field in the new command when it did not exist in the "
"old command and the api_version is '1'") % (command_name), file)
+ def add_generic_argument_removed(self, field_name: str, file: str) -> None:
+ """Add an error about a generic argument that was removed."""
+ self._add_error(
+ ERROR_ID_GENERIC_ARGUMENT_REMOVED, field_name,
+ ("The generic argument '%s' was removed from the new generic_argument.idl file") %
+ (field_name), file)
+
+ def add_generic_argument_removed_reply_field(self, field_name: str, file: str) -> None:
+ """Add an error about a generic reply field that was removed."""
+ self._add_error(
+ ERROR_ID_GENERIC_ARGUMENT_REMOVED_REPLY_FIELD, field_name,
+ ("The generic reply field '%s' was removed from the new generic_argument.idl file") %
+ (field_name), file)
+
def _assert_unique_error_messages() -> None:
"""Assert that error codes are unique."""
diff --git a/buildscripts/idl/tests/compatibility_test_fail/new_generic_argument/generic_argument.idl b/buildscripts/idl/tests/compatibility_test_fail/new_generic_argument/generic_argument.idl
new file mode 100644
index 00000000000..157ba6cb002
--- /dev/null
+++ b/buildscripts/idl/tests/compatibility_test_fail/new_generic_argument/generic_argument.idl
@@ -0,0 +1,55 @@
+# Copyright (C) 2020-present MongoDB, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the Server Side Public License, version 1,
+# as published by MongoDB, Inc.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# Server Side Public License for more details.
+#
+# You should have received a copy of the Server Side Public License
+# along with this program. If not, see
+# <http://www.mongodb.com/licensing/server-side-public-license>.
+#
+# As a special exception, the copyright holders give permission to link the
+# code of portions of this program with the OpenSSL library under certain
+# conditions as described in each individual source file and distribute
+# linked combinations including the program with the OpenSSL library. You
+# must comply with the Server Side Public License in all respects for
+# all of the code used other than as permitted herein. If you modify file(s)
+# with this exception, you may extend this exception to your version of the
+# file(s), but you are not obligated to do so. If you do not wish to do so,
+# delete this exception statement from your version. If you delete this
+# exception statement from all source files in the program, then also delete
+# it in the license file.
+#
+global:
+ cpp_namespace: "mongo"
+
+generic_argument_lists:
+ generic_args_api_v1:
+ description: "Validation fails due to a removed argument"
+ fields:
+ genericArgument:
+ forward_to_shards: false
+
+ generic_args_unstable_v1:
+ description: "IDL checker provides no guarantees about unstable generic arguments"
+ fields:
+ unstableGenericArgument:
+ forward_to_shards: false
+
+generic_reply_field_lists:
+ generic_reply_fields_api_v1:
+ description: "Validation fails due to a removed reply field"
+ fields:
+ genericReplyField:
+ forward_from_shards: false
+
+ generic_reply_fields_unstable_v1:
+ description: "IDL checker provides no guarantees about unstable generic reply fields"
+ fields:
+ unstableGenericReplyField:
+ forward_from_shards: false \ No newline at end of file
diff --git a/buildscripts/idl/tests/compatibility_test_fail/old_generic_argument/generic_argument.idl b/buildscripts/idl/tests/compatibility_test_fail/old_generic_argument/generic_argument.idl
new file mode 100644
index 00000000000..8220162ccfa
--- /dev/null
+++ b/buildscripts/idl/tests/compatibility_test_fail/old_generic_argument/generic_argument.idl
@@ -0,0 +1,59 @@
+# Copyright (C) 2020-present MongoDB, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the Server Side Public License, version 1,
+# as published by MongoDB, Inc.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# Server Side Public License for more details.
+#
+# You should have received a copy of the Server Side Public License
+# along with this program. If not, see
+# <http://www.mongodb.com/licensing/server-side-public-license>.
+#
+# As a special exception, the copyright holders give permission to link the
+# code of portions of this program with the OpenSSL library under certain
+# conditions as described in each individual source file and distribute
+# linked combinations including the program with the OpenSSL library. You
+# must comply with the Server Side Public License in all respects for
+# all of the code used other than as permitted herein. If you modify file(s)
+# with this exception, you may extend this exception to your version of the
+# file(s), but you are not obligated to do so. If you do not wish to do so,
+# delete this exception statement from your version. If you delete this
+# exception statement from all source files in the program, then also delete
+# it in the license file.
+#
+global:
+ cpp_namespace: "mongo"
+
+generic_argument_lists:
+ generic_args_api_v1:
+ description: "Validation fails due to a removed argument"
+ fields:
+ genericArgument:
+ forward_to_shards: false
+ removedGenericArgument:
+ forward_to_shards: false
+
+ generic_args_unstable_v1:
+ description: "IDL checker provides no guarantees about unstable generic arguments"
+ fields:
+ unstableGenericArgument:
+ forward_to_shards: false
+
+generic_reply_field_lists:
+ generic_reply_fields_api_v1:
+ description: "Validation fails due to a removed reply field"
+ fields:
+ genericReplyField:
+ forward_from_shards: false
+ removedGenericReplyField:
+ forward_from_shards: false
+
+ generic_reply_fields_unstable_v1:
+ description: "IDL checker provides no guarantees about unstable generic reply fields"
+ fields:
+ unstableGenericReplyField:
+ forward_from_shards: false \ No newline at end of file
diff --git a/buildscripts/idl/tests/compatibility_test_pass/new_generic_argument/generic_argument.idl b/buildscripts/idl/tests/compatibility_test_pass/new_generic_argument/generic_argument.idl
new file mode 100644
index 00000000000..8aceb008004
--- /dev/null
+++ b/buildscripts/idl/tests/compatibility_test_pass/new_generic_argument/generic_argument.idl
@@ -0,0 +1,61 @@
+# Copyright (C) 2020-present MongoDB, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the Server Side Public License, version 1,
+# as published by MongoDB, Inc.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# Server Side Public License for more details.
+#
+# You should have received a copy of the Server Side Public License
+# along with this program. If not, see
+# <http://www.mongodb.com/licensing/server-side-public-license>.
+#
+# As a special exception, the copyright holders give permission to link the
+# code of portions of this program with the OpenSSL library under certain
+# conditions as described in each individual source file and distribute
+# linked combinations including the program with the OpenSSL library. You
+# must comply with the Server Side Public License in all respects for
+# all of the code used other than as permitted herein. If you modify file(s)
+# with this exception, you may extend this exception to your version of the
+# file(s), but you are not obligated to do so. If you do not wish to do so,
+# delete this exception statement from your version. If you delete this
+# exception statement from all source files in the program, then also delete
+# it in the license file.
+#
+global:
+ cpp_namespace: "mongo"
+
+generic_argument_lists:
+ generic_args_api_v1:
+ description: "Add a new generic argument and should still pass"
+ fields:
+ genericArgument:
+ forward_to_shards: false
+ addedGenericArgument:
+ forward_to_shards: false
+
+ generic_args_unstable_v1:
+ description: "IDL checker provides no guarantees about unstable generic arguments.
+ Removing an unstable argument should still pass"
+ fields:
+ unstableGenericArgument:
+ forward_to_shards: false
+
+generic_reply_field_lists:
+ generic_reply_fields_api_v1:
+ description: "Add a new generic reply field and should still pass"
+ fields:
+ genericReplyField:
+ forward_from_shards: false
+ addedGenericReplyField:
+ forward_from_shards: false
+
+ generic_reply_fields_unstable_v1:
+ description: "IDL checker provides no guarantees about unstable generic reply fields.
+ Removing an unstable reply field should still pass"
+ fields:
+ unstableGenericReplyField:
+ forward_from_shards: false \ No newline at end of file
diff --git a/buildscripts/idl/tests/compatibility_test_pass/old_generic_argument/generic_argument.idl b/buildscripts/idl/tests/compatibility_test_pass/old_generic_argument/generic_argument.idl
new file mode 100644
index 00000000000..6f4b37df168
--- /dev/null
+++ b/buildscripts/idl/tests/compatibility_test_pass/old_generic_argument/generic_argument.idl
@@ -0,0 +1,62 @@
+# Copyright (C) 2020-present MongoDB, Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the Server Side Public License, version 1,
+# as published by MongoDB, Inc.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# Server Side Public License for more details.
+#
+# You should have received a copy of the Server Side Public License
+# along with this program. If not, see
+# <http://www.mongodb.com/licensing/server-side-public-license>.
+#
+# As a special exception, the copyright holders give permission to link the
+# code of portions of this program with the OpenSSL library under certain
+# conditions as described in each individual source file and distribute
+# linked combinations including the program with the OpenSSL library. You
+# must comply with the Server Side Public License in all respects for
+# all of the code used other than as permitted herein. If you modify file(s)
+# with this exception, you may extend this exception to your version of the
+# file(s), but you are not obligated to do so. If you do not wish to do so,
+# delete this exception statement from your version. If you delete this
+# exception statement from all source files in the program, then also delete
+# it in the license file.
+#
+global:
+ cpp_namespace: "mongo"
+
+generic_argument_lists:
+ generic_args_api_v1:
+ description: "Add a new generic argument and should still pass"
+ fields:
+ genericArgument:
+ forward_to_shards: false
+
+ generic_args_unstable_v1:
+ description: "IDL checker provides no guarantees about unstable generic arguments.
+ Removing an unstable argument should still pass"
+ fields:
+ unstableGenericArgument:
+ forward_to_shards: false
+ removedUnstableGenericArgument:
+ forward_to_shards: false
+
+
+generic_reply_field_lists:
+ generic_reply_fields_api_v1:
+ description: "Add a new generic reply field and should still pass"
+ fields:
+ genericReplyField:
+ forward_from_shards: false
+
+ generic_reply_fields_unstable_v1:
+ description: "IDL checker provides no guarantees about unstable generic reply fields.
+ Removing an unstable reply field should still pass"
+ fields:
+ unstableGenericReplyField:
+ forward_from_shards: false
+ removedUnstableGenericReplyField:
+ forward_from_shards: false \ No newline at end of file
diff --git a/buildscripts/idl/tests/test_compatibility.py b/buildscripts/idl/tests/test_compatibility.py
index 45e429ba002..89a4e6130c6 100644
--- a/buildscripts/idl/tests/test_compatibility.py
+++ b/buildscripts/idl/tests/test_compatibility.py
@@ -1207,6 +1207,41 @@ class TestIDLCompatibilityChecker(unittest.TestCase):
idl_compatibility_errors.ERROR_ID_TYPE_NOT_ARRAY)
self.assertRegex(str(missing_array_command_parameter_new_error), "array<ArrayTypeStruct>")
+ def test_generic_argument_compatibility_pass(self):
+ """Tests that compatible old and new generic_argument.idl files should pass."""
+ dir_path = path.dirname(path.realpath(__file__))
+ self.assertFalse(
+ idl_check_compatibility.check_generic_arguments_compatibility(
+ path.join(dir_path,
+ "compatibility_test_pass/old_generic_argument/generic_argument.idl"),
+ path.join(dir_path,
+ "compatibility_test_pass/new_generic_argument/generic_argument.idl")).
+ has_errors())
+
+ def test_generic_argument_compatibility_fail(self):
+ """Tests that incompatible old and new generic_argument.idl files should fail."""
+ dir_path = path.dirname(path.realpath(__file__))
+ error_collection = idl_check_compatibility.check_generic_arguments_compatibility(
+ path.join(dir_path,
+ "compatibility_test_fail/old_generic_argument/generic_argument.idl"),
+ path.join(dir_path,
+ "compatibility_test_fail/new_generic_argument/generic_argument.idl"))
+
+ self.assertTrue(error_collection.has_errors())
+ self.assertTrue(error_collection.count() == 2)
+
+ removed_generic_argument_error = error_collection.get_error_by_command_name(
+ "removedGenericArgument")
+ self.assertTrue(removed_generic_argument_error.error_id ==
+ idl_compatibility_errors.ERROR_ID_GENERIC_ARGUMENT_REMOVED)
+ self.assertRegex(str(removed_generic_argument_error), "removedGenericArgument")
+
+ removed_generic_reply_field_error = error_collection.get_error_by_command_name(
+ "removedGenericReplyField")
+ self.assertTrue(removed_generic_reply_field_error.error_id ==
+ idl_compatibility_errors.ERROR_ID_GENERIC_ARGUMENT_REMOVED_REPLY_FIELD)
+ self.assertRegex(str(removed_generic_reply_field_error), "removedGenericReplyField")
+
def test_error_reply(self):
"""Tests the compatibility checker with the ErrorReply struct."""
dir_path = path.dirname(path.realpath(__file__))