mirror of
https://github.com/zulip/zulip.git
synced 2025-11-02 13:03:29 +00:00
checks-schemas: Remove checks related to API docs.
When we move away from `data_types.py` in favor of using `pydantic` to describe the shape of our event objects in the events test (hopefully coming soon), then the code I deleted here will no longer work. The consequence of this change is that API docs may diverge from the actual event types that we use, but I believe there are better ways to manage this. Also, the deleted code was particularly hard to debug (and I say that as the original author). It probably also causes friction for folks who want to update the docs but who don't necessarily grok how the event tests work under the legacy `data_types.py` regime. Once we get pydantic types working, we can probably just write a separate tool to validate against them against the API docs using the `openapi-schema-pydantic` package or something similar.
This commit is contained in:
@@ -10,7 +10,6 @@
|
||||
# We compare the Python and OpenAPI schemas by converting the OpenAPI data
|
||||
# into the event_schema style of types and the diffing the schemas.
|
||||
import argparse
|
||||
import difflib
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
@@ -53,36 +52,7 @@ os.environ["DJANGO_SETTINGS_MODULE"] = "zproject.test_settings"
|
||||
django.setup()
|
||||
|
||||
from zerver.lib import event_schema
|
||||
from zerver.lib.data_types import (
|
||||
DictType,
|
||||
EnumType,
|
||||
ListType,
|
||||
NumberType,
|
||||
StringDictType,
|
||||
UnionType,
|
||||
make_checker,
|
||||
schema,
|
||||
)
|
||||
from zerver.openapi.openapi import openapi_spec
|
||||
|
||||
# This list of exemptions represents details we should fix in Zulip's
|
||||
# API structure and/or validators.
|
||||
EXEMPT_OPENAPI_NAMES = [
|
||||
# Additional keys(push_users_notify) due to bug in API.
|
||||
"message_event",
|
||||
# tuple handling
|
||||
"muted_topics_event",
|
||||
# bots, delivery_email, profile_data
|
||||
"realm_user_add_event",
|
||||
# OpenAPI is incomplete
|
||||
"realm_update_dict_event",
|
||||
]
|
||||
|
||||
# This is a list of events still documented in the OpenAPI that
|
||||
# are deprecated and no longer checked in event_schema.py.
|
||||
DEPRECATED_EVENTS = [
|
||||
"realm_filters_event",
|
||||
]
|
||||
from zerver.lib.data_types import make_checker
|
||||
|
||||
|
||||
def get_event_checker(event: dict[str, Any]) -> Callable[[str, dict[str, Any]], None] | None:
|
||||
@@ -133,100 +103,11 @@ def verify_fixtures_are_sorted(names: list[str]) -> None:
|
||||
)
|
||||
|
||||
|
||||
def from_openapi(node: dict[str, Any]) -> Any:
|
||||
"""Converts the OpenAPI data into event_schema.py style type
|
||||
definitions for convenient comparison with the types used for backend
|
||||
tests declared there."""
|
||||
if "oneOf" in node:
|
||||
return UnionType([from_openapi(n) for n in node["oneOf"]])
|
||||
|
||||
if node["type"] == "object":
|
||||
if (
|
||||
"additionalProperties" in node
|
||||
# this might be a glitch in our current spec? or
|
||||
# maybe I just understand it yet
|
||||
and isinstance(node["additionalProperties"], dict)
|
||||
):
|
||||
return StringDictType(from_openapi(node["additionalProperties"]))
|
||||
|
||||
if "properties" not in node:
|
||||
return dict
|
||||
|
||||
required_keys = []
|
||||
for key, sub_node in node["properties"].items():
|
||||
required_keys.append((key, from_openapi(sub_node)))
|
||||
return DictType(required_keys)
|
||||
|
||||
if node["type"] == "boolean":
|
||||
return bool
|
||||
|
||||
if node["type"] == "integer":
|
||||
if "enum" in node:
|
||||
return EnumType(node["enum"])
|
||||
return int
|
||||
|
||||
if node["type"] == "number":
|
||||
return NumberType()
|
||||
|
||||
if node["type"] == "string":
|
||||
if "enum" in node:
|
||||
return EnumType(node["enum"])
|
||||
return str
|
||||
|
||||
if node["type"] == "array":
|
||||
return ListType(from_openapi(node["items"]))
|
||||
|
||||
raise AssertionError("cannot handle node")
|
||||
|
||||
|
||||
def validate_openapi_against_event_schema() -> None:
|
||||
node = openapi_spec.openapi()["paths"]["/events"]["get"]["responses"]["200"]["content"][
|
||||
"application/json"
|
||||
]["schema"]["properties"]["events"]["items"]["oneOf"]
|
||||
|
||||
for sub_node in node:
|
||||
name = sub_node["properties"]["type"]["enum"][0]
|
||||
if "op" in sub_node["properties"]:
|
||||
name += "_" + sub_node["properties"]["op"]["enum"][0]
|
||||
|
||||
name += "_event"
|
||||
|
||||
if not hasattr(event_schema, name):
|
||||
if name not in DEPRECATED_EVENTS:
|
||||
print("WARNING - NEED SCHEMA to match OpenAPI", name)
|
||||
continue
|
||||
|
||||
openapi_type = from_openapi(sub_node)
|
||||
openapi_schema = schema(name, openapi_type)
|
||||
|
||||
py_type = getattr(event_schema, name)
|
||||
py_schema = schema(name, py_type)
|
||||
|
||||
if name in EXEMPT_OPENAPI_NAMES:
|
||||
if openapi_schema == py_schema:
|
||||
raise AssertionError(f"unnecessary exemption for {name}")
|
||||
continue
|
||||
|
||||
if openapi_schema != py_schema:
|
||||
print(f"py\n{py_schema}\n")
|
||||
print(f"openapi\n{openapi_schema}\n")
|
||||
|
||||
for line in difflib.unified_diff(
|
||||
py_schema.split("\n"),
|
||||
openapi_schema.split("\n"),
|
||||
fromfile="py",
|
||||
tofile="openapi",
|
||||
):
|
||||
print(line)
|
||||
raise AssertionError("openapi schemas disagree")
|
||||
|
||||
|
||||
def run() -> None:
|
||||
fixtures = read_fixtures()
|
||||
verify_fixtures_are_sorted(list(fixtures.keys()))
|
||||
for name, event in fixtures.items():
|
||||
check_event(name, event)
|
||||
validate_openapi_against_event_schema()
|
||||
print("Successful check. All tests passed.")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user