mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-04-23 04:06:21 +08:00
Refa: Searches /search API to RESTFul (#13770)
### What problem does this PR solve? Searches /search API to RESTFul ### Type of change - [x] Documentation Update - [x] Refactoring Co-authored-by: Jin Hai <haijin.chn@gmail.com> Co-authored-by: Yingfeng <yingfeng.zhang@gmail.com>
This commit is contained in:
@ -39,7 +39,7 @@ API_APP_URL = f"/{VERSION}/api"
|
||||
SYSTEM_APP_URL = f"/{VERSION}/system"
|
||||
LLM_APP_URL = f"/{VERSION}/llm"
|
||||
PLUGIN_APP_URL = f"/{VERSION}/plugin"
|
||||
SEARCH_APP_URL = f"/{VERSION}/search"
|
||||
SEARCHES_URL = f"/api/{VERSION}/searches"
|
||||
|
||||
|
||||
def _http_debug_enabled():
|
||||
@ -142,29 +142,27 @@ def plugin_llm_tools(auth, params=None, *, headers=HEADERS):
|
||||
|
||||
# SEARCH APP
|
||||
def search_create(auth, payload=None, *, headers=HEADERS, data=None):
|
||||
res = requests.post(url=f"{HOST_ADDRESS}{SEARCH_APP_URL}/create", headers=headers, auth=auth, json=payload, data=data)
|
||||
res = requests.post(url=f"{HOST_ADDRESS}{SEARCHES_URL}", headers=headers, auth=auth, json=payload, data=data)
|
||||
return res.json()
|
||||
|
||||
|
||||
def search_update(auth, payload=None, *, headers=HEADERS, data=None):
|
||||
res = requests.post(url=f"{HOST_ADDRESS}{SEARCH_APP_URL}/update", headers=headers, auth=auth, json=payload, data=data)
|
||||
def search_update(auth, search_id, payload=None, *, headers=HEADERS, data=None):
|
||||
res = requests.put(url=f"{HOST_ADDRESS}{SEARCHES_URL}/{search_id}", headers=headers, auth=auth, json=payload, data=data)
|
||||
return res.json()
|
||||
|
||||
|
||||
def search_detail(auth, params=None, *, headers=HEADERS):
|
||||
res = requests.get(url=f"{HOST_ADDRESS}{SEARCH_APP_URL}/detail", headers=headers, auth=auth, params=params)
|
||||
def search_detail(auth, search_id, *, headers=HEADERS):
|
||||
res = requests.get(url=f"{HOST_ADDRESS}{SEARCHES_URL}/{search_id}", headers=headers, auth=auth)
|
||||
return res.json()
|
||||
|
||||
|
||||
def search_list(auth, params=None, payload=None, *, headers=HEADERS, data=None):
|
||||
if payload is None:
|
||||
payload = {}
|
||||
res = requests.post(url=f"{HOST_ADDRESS}{SEARCH_APP_URL}/list", headers=headers, auth=auth, params=params, json=payload, data=data)
|
||||
def search_list(auth, params=None, *, headers=HEADERS):
|
||||
res = requests.get(url=f"{HOST_ADDRESS}{SEARCHES_URL}", headers=headers, auth=auth, params=params)
|
||||
return res.json()
|
||||
|
||||
|
||||
def search_rm(auth, payload=None, *, headers=HEADERS, data=None):
|
||||
res = requests.post(url=f"{HOST_ADDRESS}{SEARCH_APP_URL}/rm", headers=headers, auth=auth, json=payload, data=data)
|
||||
def search_rm(auth, search_id, *, headers=HEADERS):
|
||||
res = requests.delete(url=f"{HOST_ADDRESS}{SEARCHES_URL}/{search_id}", headers=headers, auth=auth)
|
||||
return res.json()
|
||||
|
||||
|
||||
|
||||
@ -31,15 +31,6 @@ def _search_name(prefix="search"):
|
||||
return f"{prefix}_{uuid.uuid4().hex[:8]}"
|
||||
|
||||
|
||||
def _find_tenant_id(WebApiAuth, search_id):
|
||||
res = search_list(WebApiAuth, payload={})
|
||||
assert res["code"] == 0, res
|
||||
for search_app in res["data"]["search_apps"]:
|
||||
if search_app.get("id") == search_id:
|
||||
return search_app.get("tenant_id")
|
||||
assert False, res
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def search_app(WebApiAuth):
|
||||
name = _search_name()
|
||||
@ -47,7 +38,7 @@ def search_app(WebApiAuth):
|
||||
assert create_res["code"] == 0, create_res
|
||||
search_id = create_res["data"]["search_id"]
|
||||
yield search_id
|
||||
rm_res = search_rm(WebApiAuth, {"search_id": search_id})
|
||||
rm_res = search_rm(WebApiAuth, search_id)
|
||||
assert rm_res["code"] == 0, rm_res
|
||||
assert rm_res["data"] is True, rm_res
|
||||
|
||||
@ -63,28 +54,28 @@ class TestAuthorization:
|
||||
@pytest.mark.p2
|
||||
@pytest.mark.parametrize("invalid_auth, expected_code, expected_fragment", INVALID_AUTH_CASES)
|
||||
def test_auth_invalid_list(self, invalid_auth, expected_code, expected_fragment):
|
||||
res = search_list(invalid_auth, payload={})
|
||||
res = search_list(invalid_auth)
|
||||
assert res["code"] == expected_code, res
|
||||
assert expected_fragment in res["message"], res
|
||||
|
||||
@pytest.mark.p2
|
||||
@pytest.mark.parametrize("invalid_auth, expected_code, expected_fragment", INVALID_AUTH_CASES)
|
||||
def test_auth_invalid_detail(self, invalid_auth, expected_code, expected_fragment):
|
||||
res = search_detail(invalid_auth, {"search_id": "dummy_search_id"})
|
||||
res = search_detail(invalid_auth, "dummy_search_id")
|
||||
assert res["code"] == expected_code, res
|
||||
assert expected_fragment in res["message"], res
|
||||
|
||||
@pytest.mark.p2
|
||||
@pytest.mark.parametrize("invalid_auth, expected_code, expected_fragment", INVALID_AUTH_CASES)
|
||||
def test_auth_invalid_update(self, invalid_auth, expected_code, expected_fragment):
|
||||
res = search_update(invalid_auth, {"search_id": "dummy", "name": "dummy", "search_config": {}, "tenant_id": "dummy"})
|
||||
res = search_update(invalid_auth, "dummy", {"name": "dummy", "search_config": {}})
|
||||
assert res["code"] == expected_code, res
|
||||
assert expected_fragment in res["message"], res
|
||||
|
||||
@pytest.mark.p2
|
||||
@pytest.mark.parametrize("invalid_auth, expected_code, expected_fragment", INVALID_AUTH_CASES)
|
||||
def test_auth_invalid_rm(self, invalid_auth, expected_code, expected_fragment):
|
||||
res = search_rm(invalid_auth, {"search_id": "dummy_search_id"})
|
||||
res = search_rm(invalid_auth, "dummy_search_id")
|
||||
assert res["code"] == expected_code, res
|
||||
assert expected_fragment in res["message"], res
|
||||
|
||||
@ -97,33 +88,26 @@ class TestSearchCrud:
|
||||
assert create_res["code"] == 0, create_res
|
||||
search_id = create_res["data"]["search_id"]
|
||||
|
||||
rm_res = search_rm(WebApiAuth, {"search_id": search_id})
|
||||
rm_res = search_rm(WebApiAuth, search_id)
|
||||
assert rm_res["code"] == 0, rm_res
|
||||
assert rm_res["data"] is True, rm_res
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_list(self, WebApiAuth, search_app):
|
||||
res = search_list(WebApiAuth, payload={})
|
||||
res = search_list(WebApiAuth)
|
||||
assert res["code"] == 0, res
|
||||
assert any(app.get("id") == search_app for app in res["data"]["search_apps"]), res
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_detail(self, WebApiAuth, search_app):
|
||||
res = search_detail(WebApiAuth, {"search_id": search_app})
|
||||
res = search_detail(WebApiAuth, search_app)
|
||||
assert res["code"] == 0, res
|
||||
assert res["data"].get("id") == search_app, res
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_update(self, WebApiAuth, search_app):
|
||||
tenant_id = _find_tenant_id(WebApiAuth, search_app)
|
||||
new_name = _search_name("updated")
|
||||
payload = {
|
||||
"search_id": search_app,
|
||||
"name": new_name,
|
||||
"search_config": {"top_k": 3},
|
||||
"tenant_id": tenant_id,
|
||||
}
|
||||
res = search_update(WebApiAuth, payload)
|
||||
res = search_update(WebApiAuth, search_app, {"name": new_name, "search_config": {"top_k": 3}})
|
||||
assert res["code"] == 0, res
|
||||
assert res["data"].get("name") == new_name, res
|
||||
|
||||
@ -138,17 +122,10 @@ class TestSearchCrud:
|
||||
create_res = search_create(WebApiAuth, {"name": _search_name("invalid"), "description": "test search"})
|
||||
assert create_res["code"] == 0, create_res
|
||||
search_id = create_res["data"]["search_id"]
|
||||
tenant_id = _find_tenant_id(WebApiAuth, search_id)
|
||||
try:
|
||||
payload = {
|
||||
"search_id": "invalid_search_id",
|
||||
"name": "invalid",
|
||||
"search_config": {},
|
||||
"tenant_id": tenant_id,
|
||||
}
|
||||
res = search_update(WebApiAuth, payload)
|
||||
res = search_update(WebApiAuth, "invalid_search_id", {"name": "invalid", "search_config": {}})
|
||||
assert res["code"] == 109, res
|
||||
assert "No authorization" in res["message"], res
|
||||
finally:
|
||||
rm_res = search_rm(WebApiAuth, {"search_id": search_id})
|
||||
rm_res = search_rm(WebApiAuth, search_id)
|
||||
assert rm_res["code"] == 0, rm_res
|
||||
|
||||
@ -44,6 +44,14 @@ class _Args(dict):
|
||||
def get(self, key, default=None):
|
||||
return super().get(key, default)
|
||||
|
||||
def getlist(self, key):
|
||||
val = self.get(key)
|
||||
if val is None:
|
||||
return []
|
||||
if isinstance(val, list):
|
||||
return val
|
||||
return [val]
|
||||
|
||||
|
||||
class _EnumValue:
|
||||
def __init__(self, value):
|
||||
@ -98,7 +106,7 @@ def set_tenant_info():
|
||||
return None
|
||||
|
||||
|
||||
def _load_search_app(monkeypatch):
|
||||
def _load_search_api(monkeypatch):
|
||||
repo_root = Path(__file__).resolve().parents[4]
|
||||
|
||||
quart_mod = ModuleType("quart")
|
||||
@ -233,23 +241,16 @@ def _load_search_app(monkeypatch):
|
||||
|
||||
return _decorator
|
||||
|
||||
def _not_allowed_parameters(*_params):
|
||||
def _decorator(func):
|
||||
return func
|
||||
|
||||
return _decorator
|
||||
|
||||
api_utils_mod.get_request_json = _default_request_json
|
||||
api_utils_mod.get_data_error_result = _get_data_error_result
|
||||
api_utils_mod.get_json_result = _get_json_result
|
||||
api_utils_mod.server_error_response = _server_error_response
|
||||
api_utils_mod.validate_request = _validate_request
|
||||
api_utils_mod.not_allowed_parameters = _not_allowed_parameters
|
||||
monkeypatch.setitem(sys.modules, "api.utils.api_utils", api_utils_mod)
|
||||
utils_pkg.api_utils = api_utils_mod
|
||||
|
||||
module_name = "test_search_routes_unit_module"
|
||||
module_path = repo_root / "api" / "apps" / "search_app.py"
|
||||
module_name = "test_search_api_unit_module"
|
||||
module_path = repo_root / "api" / "apps" / "restful_apis" / "search_api.py"
|
||||
spec = importlib.util.spec_from_file_location(module_name, module_path)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
module.manager = _DummyManager()
|
||||
@ -260,7 +261,7 @@ def _load_search_app(monkeypatch):
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_create_route_matrix_unit(monkeypatch):
|
||||
module = _load_search_app(monkeypatch)
|
||||
module = _load_search_api(monkeypatch)
|
||||
|
||||
_set_request_json(monkeypatch, module, {"name": 1})
|
||||
res = _run(module.create())
|
||||
@ -308,40 +309,46 @@ def test_create_route_matrix_unit(monkeypatch):
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_update_and_detail_route_matrix_unit(monkeypatch):
|
||||
module = _load_search_app(monkeypatch)
|
||||
module = _load_search_api(monkeypatch)
|
||||
|
||||
_set_request_json(monkeypatch, module, {"search_id": "s1", "name": 1, "search_config": {}, "tenant_id": "tenant-1"})
|
||||
res = _run(module.update())
|
||||
# update: name not string
|
||||
_set_request_json(monkeypatch, module, {"name": 1, "search_config": {}})
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "must be string" in res["message"]
|
||||
|
||||
_set_request_json(monkeypatch, module, {"search_id": "s1", "name": " ", "search_config": {}, "tenant_id": "tenant-1"})
|
||||
res = _run(module.update())
|
||||
# update: empty name
|
||||
_set_request_json(monkeypatch, module, {"name": " ", "search_config": {}})
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "empty" in res["message"].lower()
|
||||
|
||||
_set_request_json(monkeypatch, module, {"search_id": "s1", "name": "a" * 256, "search_config": {}, "tenant_id": "tenant-1"})
|
||||
res = _run(module.update())
|
||||
# update: name too long
|
||||
_set_request_json(monkeypatch, module, {"name": "a" * 256, "search_config": {}})
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "large than" in res["message"]
|
||||
|
||||
_set_request_json(monkeypatch, module, {"search_id": "s1", "name": "ok", "search_config": {}, "tenant_id": "tenant-1"})
|
||||
# update: tenant not found
|
||||
_set_request_json(monkeypatch, module, {"name": "ok", "search_config": {}})
|
||||
monkeypatch.setattr(module.TenantService, "get_by_id", lambda _tenant_id: (False, None))
|
||||
res = _run(module.update())
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "authorized identity" in res["message"].lower()
|
||||
|
||||
# update: no access
|
||||
monkeypatch.setattr(module.TenantService, "get_by_id", lambda _tenant_id: (True, SimpleNamespace(id=_tenant_id)))
|
||||
monkeypatch.setattr(module.SearchService, "accessible4deletion", lambda _search_id, _user_id: False)
|
||||
_set_request_json(monkeypatch, module, {"search_id": "s1", "name": "ok", "search_config": {}, "tenant_id": "tenant-1"})
|
||||
res = _run(module.update())
|
||||
_set_request_json(monkeypatch, module, {"name": "ok", "search_config": {}})
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == module.RetCode.AUTHENTICATION_ERROR
|
||||
assert "authorization" in res["message"].lower()
|
||||
|
||||
# update: search not found (query returns [None])
|
||||
monkeypatch.setattr(module.SearchService, "accessible4deletion", lambda _search_id, _user_id: True)
|
||||
monkeypatch.setattr(module.SearchService, "query", lambda **_kwargs: [None])
|
||||
_set_request_json(monkeypatch, module, {"search_id": "s1", "name": "ok", "search_config": {}, "tenant_id": "tenant-1"})
|
||||
res = _run(module.update())
|
||||
_set_request_json(monkeypatch, module, {"name": "ok", "search_config": {}})
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "cannot find search" in res["message"].lower()
|
||||
|
||||
@ -354,18 +361,21 @@ def test_update_and_detail_route_matrix_unit(monkeypatch):
|
||||
return [SimpleNamespace(id="dup")]
|
||||
return []
|
||||
|
||||
# update: duplicate name
|
||||
monkeypatch.setattr(module.SearchService, "query", _query_duplicate)
|
||||
_set_request_json(monkeypatch, module, {"search_id": "s1", "name": "new-name", "search_config": {}, "tenant_id": "tenant-1"})
|
||||
res = _run(module.update())
|
||||
_set_request_json(monkeypatch, module, {"name": "new-name", "search_config": {}})
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "duplicated" in res["message"].lower()
|
||||
|
||||
# update: search_config not a dict
|
||||
monkeypatch.setattr(module.SearchService, "query", lambda **_kwargs: [existing])
|
||||
_set_request_json(monkeypatch, module, {"search_id": "s1", "name": "old-name", "search_config": [], "tenant_id": "tenant-1"})
|
||||
res = _run(module.update())
|
||||
_set_request_json(monkeypatch, module, {"name": "old-name", "search_config": []})
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "json object" in res["message"].lower()
|
||||
|
||||
# update: update_by_id fails, verifies config merge and field exclusion
|
||||
captured = {}
|
||||
|
||||
def _update_fail(search_id, req):
|
||||
@ -374,92 +384,96 @@ def test_update_and_detail_route_matrix_unit(monkeypatch):
|
||||
return False
|
||||
|
||||
monkeypatch.setattr(module.SearchService, "update_by_id", _update_fail)
|
||||
_set_request_json(monkeypatch, module, {"search_id": "s1", "name": "old-name", "search_config": {"top_k": 3}, "tenant_id": "tenant-1"})
|
||||
res = _run(module.update())
|
||||
_set_request_json(monkeypatch, module, {"name": "old-name", "search_config": {"top_k": 3}})
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "failed to update" in res["message"].lower()
|
||||
assert captured["search_id"] == "s1"
|
||||
assert "search_id" not in captured["req"]
|
||||
assert "tenant_id" not in captured["req"]
|
||||
assert captured["req"]["search_config"] == {"existing": 1, "top_k": 3}
|
||||
|
||||
# update: get_by_id fails after successful update
|
||||
monkeypatch.setattr(module.SearchService, "update_by_id", lambda _search_id, _req: True)
|
||||
monkeypatch.setattr(module.SearchService, "get_by_id", lambda _search_id: (False, None))
|
||||
res = _run(module.update())
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "failed to fetch" in res["message"].lower()
|
||||
|
||||
# update: success
|
||||
monkeypatch.setattr(
|
||||
module.SearchService,
|
||||
"get_by_id",
|
||||
lambda _search_id: (True, _SearchRecord(search_id=_search_id, name="old-name", search_config={"existing": 1, "top_k": 3})),
|
||||
)
|
||||
res = _run(module.update())
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == 0
|
||||
assert res["data"]["id"] == "s1"
|
||||
|
||||
# update: exception
|
||||
def _raise_query(**_kwargs):
|
||||
raise RuntimeError("update boom")
|
||||
|
||||
monkeypatch.setattr(module.SearchService, "query", _raise_query)
|
||||
_set_request_json(monkeypatch, module, {"search_id": "s1", "name": "old-name", "search_config": {"top_k": 3}, "tenant_id": "tenant-1"})
|
||||
res = _run(module.update())
|
||||
_set_request_json(monkeypatch, module, {"name": "old-name", "search_config": {"top_k": 3}})
|
||||
res = _run(module.update(search_id="s1"))
|
||||
assert res["code"] == module.RetCode.EXCEPTION_ERROR
|
||||
assert "update boom" in res["message"]
|
||||
|
||||
_set_request_args(monkeypatch, module, {"search_id": "s1"})
|
||||
# detail: no permission
|
||||
monkeypatch.setattr(module.UserTenantService, "query", lambda **_kwargs: [SimpleNamespace(tenant_id="tenant-a")])
|
||||
monkeypatch.setattr(module.SearchService, "query", lambda **_kwargs: [])
|
||||
res = module.detail()
|
||||
res = module.detail(search_id="s1")
|
||||
assert res["code"] == module.RetCode.OPERATING_ERROR
|
||||
assert "permission" in res["message"].lower()
|
||||
|
||||
# detail: search not found
|
||||
monkeypatch.setattr(module.SearchService, "query", lambda **_kwargs: [SimpleNamespace(id="s1")])
|
||||
monkeypatch.setattr(module.SearchService, "get_detail", lambda _search_id: None)
|
||||
res = module.detail()
|
||||
res = module.detail(search_id="s1")
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "can't find" in res["message"].lower()
|
||||
|
||||
# detail: success
|
||||
monkeypatch.setattr(module.SearchService, "get_detail", lambda _search_id: {"id": _search_id, "name": "detail-name"})
|
||||
res = module.detail()
|
||||
res = module.detail(search_id="s1")
|
||||
assert res["code"] == 0
|
||||
assert res["data"]["id"] == "s1"
|
||||
|
||||
# detail: exception
|
||||
def _raise_detail(_search_id):
|
||||
raise RuntimeError("detail boom")
|
||||
|
||||
monkeypatch.setattr(module.SearchService, "get_detail", _raise_detail)
|
||||
res = module.detail()
|
||||
res = module.detail(search_id="s1")
|
||||
assert res["code"] == module.RetCode.EXCEPTION_ERROR
|
||||
assert "detail boom" in res["message"]
|
||||
|
||||
|
||||
@pytest.mark.p2
|
||||
def test_list_and_rm_route_matrix_unit(monkeypatch):
|
||||
module = _load_search_app(monkeypatch)
|
||||
def test_list_and_delete_route_matrix_unit(monkeypatch):
|
||||
module = _load_search_api(monkeypatch)
|
||||
|
||||
# list: no owner_ids, with pagination
|
||||
_set_request_args(
|
||||
monkeypatch,
|
||||
module,
|
||||
{"keywords": "k", "page": "1", "page_size": "2", "orderby": "create_time", "desc": "false"},
|
||||
)
|
||||
_set_request_json(monkeypatch, module, {"owner_ids": []})
|
||||
monkeypatch.setattr(
|
||||
module.SearchService,
|
||||
"get_by_tenant_ids",
|
||||
lambda _tenants, _uid, _page, _size, _orderby, _desc, _keywords: ([{"id": "a", "tenant_id": "tenant-1"}], 1),
|
||||
)
|
||||
res = _run(module.list_search_app())
|
||||
res = module.list_searches()
|
||||
assert res["code"] == 0
|
||||
assert res["data"]["total"] == 1
|
||||
assert res["data"]["search_apps"][0]["id"] == "a"
|
||||
|
||||
# list: with owner_ids filter and pagination
|
||||
_set_request_args(
|
||||
monkeypatch,
|
||||
module,
|
||||
{"keywords": "k", "page": "1", "page_size": "1", "orderby": "create_time", "desc": "true"},
|
||||
{"keywords": "k", "page": "1", "page_size": "1", "orderby": "create_time", "desc": "true", "owner_ids": ["tenant-1"]},
|
||||
)
|
||||
_set_request_json(monkeypatch, module, {"owner_ids": ["tenant-1"]})
|
||||
monkeypatch.setattr(
|
||||
module.SearchService,
|
||||
"get_by_tenant_ids",
|
||||
@ -468,42 +482,46 @@ def test_list_and_rm_route_matrix_unit(monkeypatch):
|
||||
2,
|
||||
),
|
||||
)
|
||||
res = _run(module.list_search_app())
|
||||
res = module.list_searches()
|
||||
assert res["code"] == 0
|
||||
assert res["data"]["total"] == 1
|
||||
assert len(res["data"]["search_apps"]) == 1
|
||||
assert res["data"]["search_apps"][0]["tenant_id"] == "tenant-1"
|
||||
|
||||
# list: exception
|
||||
def _raise_list(*_args, **_kwargs):
|
||||
raise RuntimeError("list boom")
|
||||
|
||||
monkeypatch.setattr(module.SearchService, "get_by_tenant_ids", _raise_list)
|
||||
_set_request_json(monkeypatch, module, {"owner_ids": []})
|
||||
res = _run(module.list_search_app())
|
||||
_set_request_args(monkeypatch, module, {})
|
||||
res = module.list_searches()
|
||||
assert res["code"] == module.RetCode.EXCEPTION_ERROR
|
||||
assert "list boom" in res["message"]
|
||||
|
||||
_set_request_json(monkeypatch, module, {"search_id": "search-1"})
|
||||
# delete: no authorization
|
||||
monkeypatch.setattr(module.SearchService, "accessible4deletion", lambda _search_id, _user_id: False)
|
||||
res = _run(module.rm())
|
||||
res = module.delete_search(search_id="search-1")
|
||||
assert res["code"] == module.RetCode.AUTHENTICATION_ERROR
|
||||
assert "authorization" in res["message"].lower()
|
||||
|
||||
# delete: delete_by_id fails
|
||||
monkeypatch.setattr(module.SearchService, "accessible4deletion", lambda _search_id, _user_id: True)
|
||||
monkeypatch.setattr(module.SearchService, "delete_by_id", lambda _search_id: False)
|
||||
res = _run(module.rm())
|
||||
res = module.delete_search(search_id="search-1")
|
||||
assert res["code"] == module.RetCode.DATA_ERROR
|
||||
assert "failed to delete" in res["message"].lower()
|
||||
|
||||
# delete: success
|
||||
monkeypatch.setattr(module.SearchService, "delete_by_id", lambda _search_id: True)
|
||||
res = _run(module.rm())
|
||||
res = module.delete_search(search_id="search-1")
|
||||
assert res["code"] == 0
|
||||
assert res["data"] is True
|
||||
|
||||
# delete: exception
|
||||
def _raise_delete(_search_id):
|
||||
raise RuntimeError("rm boom")
|
||||
|
||||
monkeypatch.setattr(module.SearchService, "delete_by_id", _raise_delete)
|
||||
res = _run(module.rm())
|
||||
res = module.delete_search(search_id="search-1")
|
||||
assert res["code"] == module.RetCode.EXCEPTION_ERROR
|
||||
assert "rm boom" in res["message"]
|
||||
|
||||
Reference in New Issue
Block a user