Ejemplo n.º 1
0
 def test_attributes(self) -> None:
     """
     Checks:
     * All endpoints have `operationId` and `tag` attributes.
     * All example responses match their schema.
     * That no opaque object exists.
     """
     EXCLUDE = ["/real-time", "/register", "/events"]
     VALID_TAGS = [
         "users", "server_and_organizations", "authentication",
         "real_time_events", "streams", "messages", "users", "webhooks"
     ]
     paths = OpenAPISpec(OPENAPI_SPEC_PATH).openapi()["paths"]
     for path, path_item in paths.items():
         if path in EXCLUDE:
             continue
         for method, operation in path_item.items():
             # Check if every file has an operationId
             assert ("operationId" in operation)
             assert ("tags" in operation)
             tag = operation["tags"][0]
             assert (tag in VALID_TAGS)
             for status_code, response in operation['responses'].items():
                 schema = response['content']['application/json']['schema']
                 if 'oneOf' in schema:
                     for subschema_index, subschema in enumerate(
                             schema['oneOf']):
                         validate_schema(subschema)
                         assert (validate_against_openapi_schema(
                             subschema['example'], path, method,
                             status_code + '_' + str(subschema_index)))
                     continue
                 validate_schema(schema)
                 assert (validate_against_openapi_schema(
                     schema['example'], path, method, status_code))
Ejemplo n.º 2
0
 def test_attributes(self) -> None:
     """
     Checks:
     * All endpoints have `operationId` and `tag` attributes.
     * All example responses match their schema.
     * That no opaque object exists.
     """
     EXCLUDE = ["/real-time"]
     VALID_TAGS = [
         "users",
         "server_and_organizations",
         "authentication",
         "real_time_events",
         "streams",
         "messages",
         "drafts",
         "webhooks",
     ]
     paths = OpenAPISpec(OPENAPI_SPEC_PATH).openapi()["paths"]
     for path, path_item in paths.items():
         if path in EXCLUDE:
             continue
         for method, operation in path_item.items():
             # Check if every file has an operationId
             assert "operationId" in operation
             assert "tags" in operation
             tag = operation["tags"][0]
             assert tag in VALID_TAGS
             for status_code, response in operation["responses"].items():
                 schema = response["content"]["application/json"]["schema"]
                 if "oneOf" in schema:
                     for subschema_index, subschema in enumerate(
                             schema["oneOf"]):
                         validate_schema(subschema)
                         assert validate_against_openapi_schema(
                             subschema["example"],
                             path,
                             method,
                             status_code + "_" + str(subschema_index),
                         )
                     continue
                 validate_schema(schema)
                 assert validate_against_openapi_schema(
                     schema["example"], path, method, status_code)
Ejemplo n.º 3
0
 def test_attributes(self) -> None:
     """
     Checks:
     * All endpoints have `operationId` and `tag` attributes.
     * All example responses match their schema.
     * That no opaque object exists.
     """
     EXCLUDE = ["/real-time", "/register", "/events"]
     VALID_TAGS = [
         "users", "server_and_organizations", "authentication",
         "real_time_events", "streams", "messages", "users", "webhooks"
     ]
     openapi_spec = OpenAPISpec(OPENAPI_SPEC_PATH).spec()["paths"]
     for path in openapi_spec:
         if path in EXCLUDE:
             continue
         for method in openapi_spec[path]:
             # Check if every file has an operationId
             assert ("operationId" in openapi_spec[path][method])
             assert ("tags" in openapi_spec[path][method])
             tag = openapi_spec[path][method]["tags"][0]
             assert (tag in VALID_TAGS)
             for response in openapi_spec[path][method]['responses']:
                 response_schema = (
                     openapi_spec[path][method]['responses'][response]
                     ['content']['application/json']['schema'])
                 if 'oneOf' in response_schema:
                     cnt = 0
                     for entry in response_schema['oneOf']:
                         validate_schema(entry)
                         assert (validate_against_openapi_schema(
                             entry['example'], path, method,
                             response + '_' + str(cnt)))
                         cnt += 1
                     continue
                 validate_schema(response_schema)
                 assert (validate_against_openapi_schema(
                     response_schema['example'], path, method, response))
Ejemplo n.º 4
0
    def test_validate_against_openapi_schema(self) -> None:
        with self.assertRaises(
                ValidationError,
                msg=
                "Additional properties are not allowed ('foo' was unexpected)"
        ):
            bad_content: Dict[str, object] = {
                "msg": "",
                "result": "success",
                "foo": "bar",
            }
            validate_against_openapi_schema(bad_content, TEST_ENDPOINT,
                                            TEST_METHOD, TEST_RESPONSE_SUCCESS)

        with self.assertRaises(ValidationError,
                               msg=("42 is not of type string")):
            bad_content = {
                "msg": 42,
                "result": "success",
            }
            validate_against_openapi_schema(bad_content, TEST_ENDPOINT,
                                            TEST_METHOD, TEST_RESPONSE_SUCCESS)

        with self.assertRaises(ValidationError,
                               msg='Expected to find the "msg" required key'):
            bad_content = {
                "result": "success",
            }
            validate_against_openapi_schema(bad_content, TEST_ENDPOINT,
                                            TEST_METHOD, TEST_RESPONSE_SUCCESS)

        # No exceptions should be raised here.
        good_content = {
            "msg": "",
            "result": "success",
        }
        validate_against_openapi_schema(good_content, TEST_ENDPOINT,
                                        TEST_METHOD, TEST_RESPONSE_SUCCESS)

        # Overwrite the exception list with a mocked one
        test_dict: Dict[str, Any] = {}

        # Check that validate_against_openapi_schema correctly
        # descends into 'deep' objects and arrays.  Test 1 should
        # pass, Test 2 has a 'deep' extraneous key and Test 3 has a
        # 'deep' opaque object. Also the parameters are a heterogeneous
        # mix of arrays and objects to verify that our descent logic
        # correctly gets to the the deeply nested objects.
        with open(
                os.path.join(os.path.dirname(OPENAPI_SPEC_PATH),
                             "testing.yaml")) as test_file:
            test_dict = yaml.safe_load(test_file)
        openapi_spec.openapi()["paths"]["testing"] = test_dict
        try:
            validate_against_openapi_schema(
                (test_dict["test1"]["responses"]["200"]["content"]
                 ["application/json"]["example"]),
                "testing",
                "test1",
                "200",
            )
            with self.assertRaises(
                    ValidationError,
                    msg='Extraneous key "str4" in response\'s content'):
                validate_against_openapi_schema(
                    (test_dict["test2"]["responses"]["200"]["content"]
                     ["application/json"]["example"]),
                    "testing",
                    "test2",
                    "200",
                )
            with self.assertRaises(SchemaError, msg='Opaque object "obj"'):
                # Checks for opaque objects
                validate_schema(test_dict["test3"]["responses"]["200"]
                                ["content"]["application/json"]["schema"])
        finally:
            openapi_spec.openapi()["paths"].pop("testing", None)
Ejemplo n.º 5
0
    def test_validate_against_openapi_schema(self) -> None:
        with self.assertRaisesRegex(
                SchemaError,
                r"Additional properties are not allowed \('foo' was unexpected\)"
        ):
            bad_content: Dict[str, object] = {
                "msg": "",
                "result": "success",
                "foo": "bar",
            }
            validate_against_openapi_schema(bad_content, TEST_ENDPOINT,
                                            TEST_METHOD, TEST_RESPONSE_SUCCESS)

        with self.assertRaisesRegex(SchemaError, r"42 is not of type string"):
            bad_content = {
                "msg": 42,
                "result": "success",
            }
            validate_against_openapi_schema(bad_content, TEST_ENDPOINT,
                                            TEST_METHOD, TEST_RESPONSE_SUCCESS)

        with self.assertRaisesRegex(SchemaError,
                                    r"'msg' is a required property"):
            bad_content = {
                "result": "success",
            }
            validate_against_openapi_schema(bad_content, TEST_ENDPOINT,
                                            TEST_METHOD, TEST_RESPONSE_SUCCESS)

        # No exceptions should be raised here.
        good_content = {
            "msg": "",
            "result": "success",
        }
        validate_against_openapi_schema(good_content, TEST_ENDPOINT,
                                        TEST_METHOD, TEST_RESPONSE_SUCCESS)

        # Overwrite the exception list with a mocked one
        test_dict: Dict[str, Any] = {}

        # Check that validate_against_openapi_schema correctly
        # descends into 'deep' objects and arrays.  Test 1 should
        # pass, Test 2 has a 'deep' extraneous key and Test 3 has a
        # 'deep' opaque object. Also the parameters are a heterogeneous
        # mix of arrays and objects to verify that our descent logic
        # correctly gets to the the deeply nested objects.
        test_filename = os.path.join(os.path.dirname(OPENAPI_SPEC_PATH),
                                     "testing.yaml")
        with open(test_filename) as test_file:
            test_dict = yaml.safe_load(test_file)
        with patch("zerver.openapi.openapi.openapi_spec",
                   OpenAPISpec(test_filename)):
            validate_against_openapi_schema(
                {
                    "top_array": [
                        {
                            "obj": {
                                "str3": "test"
                            }
                        },
                        [{
                            "str1": "success",
                            "str2": "success"
                        }],
                    ],
                },
                "/test1",
                "get",
                "200",
            )
            with self.assertRaisesRegex(
                    SchemaError,
                    r"\{'obj': \{'str3': 'test', 'str4': 'extraneous'\}\} is not valid under any of the given schemas",
            ):
                validate_against_openapi_schema(
                    {
                        "top_array": [
                            {
                                "obj": {
                                    "str3": "test",
                                    "str4": "extraneous"
                                }
                            },
                            [{
                                "str1": "success",
                                "str2": "success"
                            }],
                        ],
                    },
                    "/test2",
                    "get",
                    "200",
                )
            with self.assertRaisesRegex(
                    SchemaError,
                    r"additionalProperties needs to be defined for objects to makesure they have no additional properties left to be documented\.",
            ):
                # Checks for opaque objects
                validate_schema(
                    test_dict["paths"]["/test3"]["get"]["responses"]["200"]
                    ["content"]["application/json"]["schema"])
Ejemplo n.º 6
0
    def test_validate_against_openapi_schema(self) -> None:
        with self.assertRaises(ValidationError,
                               msg=("Additional properties are not" +
                                    " allowed ('foo' was unexpected)")):
            bad_content: Dict[str, object] = {
                'msg': '',
                'result': 'success',
                'foo': 'bar',
            }
            validate_against_openapi_schema(bad_content, TEST_ENDPOINT,
                                            TEST_METHOD, TEST_RESPONSE_SUCCESS)

        with self.assertRaises(ValidationError,
                               msg=("42 is not of type string")):
            bad_content = {
                'msg': 42,
                'result': 'success',
            }
            validate_against_openapi_schema(bad_content, TEST_ENDPOINT,
                                            TEST_METHOD, TEST_RESPONSE_SUCCESS)

        with self.assertRaises(ValidationError,
                               msg='Expected to find the "msg" required key'):
            bad_content = {
                'result': 'success',
            }
            validate_against_openapi_schema(bad_content, TEST_ENDPOINT,
                                            TEST_METHOD, TEST_RESPONSE_SUCCESS)

        # No exceptions should be raised here.
        good_content = {
            'msg': '',
            'result': 'success',
        }
        validate_against_openapi_schema(good_content, TEST_ENDPOINT,
                                        TEST_METHOD, TEST_RESPONSE_SUCCESS)

        # Overwrite the exception list with a mocked one
        test_dict: Dict[str, Any] = {}

        # Check that validate_against_openapi_schema correctly
        # descends into 'deep' objects and arrays.  Test 1 should
        # pass, Test 2 has a 'deep' extraneous key and Test 3 has a
        # 'deep' opaque object. Also the parameters are a heterogenous
        # mix of arrays and objects to verify that our descent logic
        # correctly gets to the the deeply nested objects.
        with open(
                os.path.join(os.path.dirname(OPENAPI_SPEC_PATH),
                             "testing.yaml")) as test_file:
            test_dict = yaml.safe_load(test_file)
        openapi_spec.spec()['paths']['testing'] = test_dict
        try:
            validate_against_openapi_schema(
                (test_dict['test1']['responses']['200']['content']
                 ['application/json']['example']), 'testing', 'test1', '200')
            with self.assertRaises(
                    ValidationError,
                    msg='Extraneous key "str4" in response\'s content'):
                validate_against_openapi_schema(
                    (test_dict['test2']['responses']['200']['content']
                     ['application/json']['example']), 'testing', 'test2',
                    '200')
            with self.assertRaises(SchemaError, msg='Opaque object "obj"'):
                # Checks for opaque objects
                validate_schema((test_dict['test3']['responses']['200']
                                 ['content']['application/json']['schema']))
        finally:
            openapi_spec.spec()['paths'].pop('testing', None)