mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-08-15 05:04:27 +08:00
fix(dify): guard retrieval argument error behavior (#14169)
## What problem does this PR solve?
The Dify-compatible `/dify/retrieval` endpoint recently gained stricter
parsing and validation for its request payload, including:
- Normalized `retrieval_setting.top_k` and
`retrieval_setting.score_threshold` types.
- Clear separation between malformed arguments vs missing required
fields.
Previously, there was no unit test explicitly guarding the exact error
code and message contract for these cases.
## What does this PR change?
- **Add guard-style unit test** in `test_dify_retrieval_routes_unit.py`:
- `test_retrieval_argument_error_messages`:
- Sends a request with malformed numeric options:
- `retrieval_setting = {"top_k": "not-int", "score_threshold":
"not-float"}`
- Asserts `code == RetCode.ARGUMENT_ERROR` and message contains
`"invalid or malformed arguments:"`.
- Sends a request with required fields missing:
- Empty payload (`{}`)
- Asserts `code == RetCode.ARGUMENT_ERROR` and message contains
`"required arguments are missing:"`.
This test encodes the intended behavior of the Dify retrieval API so
future refactors cannot silently regress error handling.
## Type of change
- [x] Tests (add coverage and guardrails for existing behavior)
Co-authored-by: Kevin Hu <kevinhu.sh@gmail.com>
This commit is contained in:
@@ -352,3 +352,82 @@ def test_retrieval_generic_exception_mapping(monkeypatch):
|
||||
res = _run(inspect.unwrap(module.retrieval)("tenant-1"))
|
||||
assert res["code"] == module.RetCode.SERVER_ERROR, res
|
||||
assert "boom" in res["message"], res
|
||||
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_read_retrieval_request_from_get_args(monkeypatch):
|
||||
module = _load_dify_retrieval_module(monkeypatch)
|
||||
monkeypatch.setattr(
|
||||
module,
|
||||
"request",
|
||||
SimpleNamespace(
|
||||
method="GET",
|
||||
args={
|
||||
"knowledge_id": "kb-1",
|
||||
"query": "hello",
|
||||
"use_kg": "true",
|
||||
"top_k": "12",
|
||||
"score_threshold": "0.66",
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
req = _run(module._read_retrieval_request())
|
||||
assert req["knowledge_id"] == "kb-1", req
|
||||
assert req["query"] == "hello", req
|
||||
assert req["use_kg"] is True, req
|
||||
assert req["retrieval_setting"]["top_k"] == 12, req
|
||||
assert req["retrieval_setting"]["score_threshold"] == 0.66, req
|
||||
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_read_retrieval_request_from_post_json(monkeypatch):
|
||||
module = _load_dify_retrieval_module(monkeypatch)
|
||||
payload = {"knowledge_id": "kb-1", "query": "hello"}
|
||||
monkeypatch.setattr(module, "request", SimpleNamespace(method="POST", args={}))
|
||||
monkeypatch.setattr(module, "get_request_json", lambda: _AwaitableValue(payload))
|
||||
|
||||
req = _run(module._read_retrieval_request())
|
||||
assert req == payload, req
|
||||
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_retrieval_argument_error_messages(monkeypatch):
|
||||
"""Guard: distinguish malformed vs missing argument errors."""
|
||||
module = _load_dify_retrieval_module(monkeypatch)
|
||||
|
||||
# Case 1: malformed numeric options in retrieval_setting
|
||||
_set_request_json(
|
||||
monkeypatch,
|
||||
module,
|
||||
{
|
||||
"knowledge_id": "kb-1",
|
||||
"query": "hello",
|
||||
"retrieval_setting": {"top_k": "not-int", "score_threshold": "not-float"},
|
||||
},
|
||||
)
|
||||
res = _run(inspect.unwrap(module.retrieval)("tenant-1"))
|
||||
assert res["code"] == module.RetCode.ARGUMENT_ERROR, res
|
||||
assert "invalid or malformed arguments:" in res["message"], res
|
||||
|
||||
# Case 2: missing required fields (knowledge_id, query)
|
||||
_set_request_json(monkeypatch, module, {})
|
||||
res_missing = _run(inspect.unwrap(module.retrieval)("tenant-1"))
|
||||
assert res_missing["code"] == module.RetCode.ARGUMENT_ERROR, res_missing
|
||||
assert "required arguments are missing:" in res_missing["message"], res_missing
|
||||
|
||||
# Case 3: partially missing required field (query)
|
||||
_set_request_json(monkeypatch, module, {"knowledge_id": "kb-1"})
|
||||
res_missing_query = _run(inspect.unwrap(module.retrieval)("tenant-1"))
|
||||
assert res_missing_query["code"] == module.RetCode.ARGUMENT_ERROR, res_missing_query
|
||||
assert "query" in res_missing_query["message"], res_missing_query
|
||||
|
||||
# Case 4: retrieval_setting wrong type
|
||||
_set_request_json(
|
||||
monkeypatch,
|
||||
module,
|
||||
{"knowledge_id": "kb-1", "query": "hello", "retrieval_setting": "bad-type"},
|
||||
)
|
||||
res_wrong_type = _run(inspect.unwrap(module.retrieval)("tenant-1"))
|
||||
assert res_wrong_type["code"] == module.RetCode.ARGUMENT_ERROR, res_wrong_type
|
||||
assert "retrieval_setting must be an object" in res_wrong_type["message"], res_wrong_type
|
||||
|
||||
Reference in New Issue
Block a user