mirror of
https://github.com/langgenius/dify.git
synced 2026-05-23 18:38:26 +08:00
add test for openapi registration
This commit is contained in:
@ -0,0 +1,92 @@
|
||||
"""Verifies the OPENAPI_ENABLED gate in `extensions.ext_blueprints.init_app`.
|
||||
|
||||
Contract:
|
||||
- When `dify_config.OPENAPI_ENABLED` is True, the `/openapi/v1/*` blueprint
|
||||
must be registered on the Flask app AND have CORS configured (signalled
|
||||
by the idempotent `_dify_cors_applied` marker that `_apply_cors_once`
|
||||
sets after wiring `flask_cors.CORS`).
|
||||
- When False, the openapi blueprint must NOT be registered and CORS must
|
||||
NOT be wired for it. The cross-origin posture is otherwise undefined for
|
||||
the disabled feature.
|
||||
|
||||
The openapi blueprint is a module-level singleton; tests reset its
|
||||
`_dify_cors_applied` flag so each case re-evaluates the branching logic.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Iterator
|
||||
|
||||
import pytest
|
||||
|
||||
from configs import dify_config
|
||||
from controllers.openapi import bp as openapi_bp
|
||||
from dify_app import DifyApp
|
||||
from extensions import ext_blueprints
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fresh_openapi_cors_state() -> Iterator[None]:
|
||||
"""Reset the one-shot CORS marker on the openapi blueprint.
|
||||
|
||||
`_apply_cors_once` short-circuits when this flag is truthy, so we
|
||||
must clear it before each case to actually exercise the True branch.
|
||||
"""
|
||||
had_flag = hasattr(openapi_bp, "_dify_cors_applied")
|
||||
if had_flag:
|
||||
delattr(openapi_bp, "_dify_cors_applied")
|
||||
yield
|
||||
# Leave the blueprint in a clean state regardless of branch taken,
|
||||
# so unrelated tests that import the production blueprint do not
|
||||
# observe leaked state from this module.
|
||||
if hasattr(openapi_bp, "_dify_cors_applied"):
|
||||
delattr(openapi_bp, "_dify_cors_applied")
|
||||
|
||||
|
||||
def _build_app() -> DifyApp:
|
||||
app = DifyApp(__name__)
|
||||
app.config["TESTING"] = True
|
||||
return app
|
||||
|
||||
|
||||
def test_openapi_blueprint_registered_with_cors_when_enabled(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
fresh_openapi_cors_state: None,
|
||||
) -> None:
|
||||
"""Enabled gate: blueprint mounted, CORS wired, `/openapi/v1/*` rules live.
|
||||
|
||||
Combined into one case because `flask_cors.CORS(bp, ...)` calls
|
||||
`bp.after_request(...)`, which Flask rejects after the singleton
|
||||
blueprint has been registered to any app once. So this branch is
|
||||
only safe to exercise a single time per test process.
|
||||
"""
|
||||
monkeypatch.setattr(dify_config, "OPENAPI_ENABLED", True)
|
||||
|
||||
app = _build_app()
|
||||
ext_blueprints.init_app(app)
|
||||
|
||||
assert "openapi" in app.blueprints
|
||||
assert app.blueprints["openapi"] is openapi_bp
|
||||
# `_apply_cors_once` only sets this after wiring flask_cors.CORS, so
|
||||
# it is a faithful proxy for "CORS was applied to this blueprint".
|
||||
assert getattr(openapi_bp, "_dify_cors_applied", False) is True
|
||||
|
||||
openapi_rules = [r for r in app.url_map.iter_rules() if r.rule.startswith("/openapi/v1")]
|
||||
assert openapi_rules, "expected at least one /openapi/v1/* route once enabled"
|
||||
|
||||
|
||||
def test_openapi_blueprint_absent_when_disabled(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
fresh_openapi_cors_state: None,
|
||||
) -> None:
|
||||
"""Disabled gate: no blueprint, no CORS, no `/openapi/v1/*` URL rules."""
|
||||
monkeypatch.setattr(dify_config, "OPENAPI_ENABLED", False)
|
||||
|
||||
app = _build_app()
|
||||
ext_blueprints.init_app(app)
|
||||
|
||||
assert "openapi" not in app.blueprints
|
||||
# No CORS wiring should have run for the openapi blueprint.
|
||||
assert not hasattr(openapi_bp, "_dify_cors_applied")
|
||||
openapi_rules = [r for r in app.url_map.iter_rules() if r.rule.startswith("/openapi/v1")]
|
||||
assert openapi_rules == []
|
||||
Reference in New Issue
Block a user