mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
Refa: Move HTTP API tests to top-level test directory (#8042)
### What problem does this PR solve? Move test cases only - CI still runs tests under sdk/python ### Type of change - [x] Refactoring
This commit is contained in:
@ -0,0 +1,53 @@
|
||||
#
|
||||
# Copyright 2025 The InfiniFlow Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
import pytest
|
||||
from common import create_session_with_chat_assistant, delete_session_with_chat_assistants
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def add_sessions_with_chat_assistant(request, api_key, add_chat_assistants):
|
||||
_, _, chat_assistant_ids = add_chat_assistants
|
||||
|
||||
def cleanup():
|
||||
for chat_assistant_id in chat_assistant_ids:
|
||||
delete_session_with_chat_assistants(api_key, chat_assistant_id)
|
||||
|
||||
request.addfinalizer(cleanup)
|
||||
|
||||
session_ids = []
|
||||
for i in range(5):
|
||||
res = create_session_with_chat_assistant(api_key, chat_assistant_ids[0], {"name": f"session_with_chat_assistant_{i}"})
|
||||
session_ids.append(res["data"]["id"])
|
||||
|
||||
return chat_assistant_ids[0], session_ids
|
||||
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def add_sessions_with_chat_assistant_func(request, api_key, add_chat_assistants):
|
||||
_, _, chat_assistant_ids = add_chat_assistants
|
||||
|
||||
def cleanup():
|
||||
for chat_assistant_id in chat_assistant_ids:
|
||||
delete_session_with_chat_assistants(api_key, chat_assistant_id)
|
||||
|
||||
request.addfinalizer(cleanup)
|
||||
|
||||
session_ids = []
|
||||
for i in range(5):
|
||||
res = create_session_with_chat_assistant(api_key, chat_assistant_ids[0], {"name": f"session_with_chat_assistant_{i}"})
|
||||
session_ids.append(res["data"]["id"])
|
||||
|
||||
return chat_assistant_ids[0], session_ids
|
||||
@ -0,0 +1,117 @@
|
||||
#
|
||||
# Copyright 2025 The InfiniFlow Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
import pytest
|
||||
from common import INVALID_API_TOKEN, SESSION_WITH_CHAT_NAME_LIMIT, create_session_with_chat_assistant, delete_chat_assistants, list_session_with_chat_assistants
|
||||
from libs.auth import RAGFlowHttpApiAuth
|
||||
|
||||
|
||||
@pytest.mark.p1
|
||||
class TestAuthorization:
|
||||
@pytest.mark.parametrize(
|
||||
"invalid_auth, expected_code, expected_message",
|
||||
[
|
||||
(None, 0, "`Authorization` can't be empty"),
|
||||
(
|
||||
RAGFlowHttpApiAuth(INVALID_API_TOKEN),
|
||||
109,
|
||||
"Authentication error: API key is invalid!",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_invalid_auth(self, invalid_auth, expected_code, expected_message):
|
||||
res = create_session_with_chat_assistant(invalid_auth, "chat_assistant_id")
|
||||
assert res["code"] == expected_code
|
||||
assert res["message"] == expected_message
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("clear_session_with_chat_assistants")
|
||||
class TestSessionWithChatAssistantCreate:
|
||||
@pytest.mark.p1
|
||||
@pytest.mark.parametrize(
|
||||
"payload, expected_code, expected_message",
|
||||
[
|
||||
({"name": "valid_name"}, 0, ""),
|
||||
pytest.param({"name": "a" * (SESSION_WITH_CHAT_NAME_LIMIT + 1)}, 102, "", marks=pytest.mark.skip(reason="issues/")),
|
||||
pytest.param({"name": 1}, 100, "", marks=pytest.mark.skip(reason="issues/")),
|
||||
({"name": ""}, 102, "`name` can not be empty."),
|
||||
({"name": "duplicated_name"}, 0, ""),
|
||||
({"name": "case insensitive"}, 0, ""),
|
||||
],
|
||||
)
|
||||
def test_name(self, api_key, add_chat_assistants, payload, expected_code, expected_message):
|
||||
_, _, chat_assistant_ids = add_chat_assistants
|
||||
if payload["name"] == "duplicated_name":
|
||||
create_session_with_chat_assistant(api_key, chat_assistant_ids[0], payload)
|
||||
elif payload["name"] == "case insensitive":
|
||||
create_session_with_chat_assistant(api_key, chat_assistant_ids[0], {"name": payload["name"].upper()})
|
||||
|
||||
res = create_session_with_chat_assistant(api_key, chat_assistant_ids[0], payload)
|
||||
assert res["code"] == expected_code, res
|
||||
if expected_code == 0:
|
||||
assert res["data"]["name"] == payload["name"]
|
||||
assert res["data"]["chat_id"] == chat_assistant_ids[0]
|
||||
else:
|
||||
assert res["message"] == expected_message
|
||||
|
||||
@pytest.mark.p3
|
||||
@pytest.mark.parametrize(
|
||||
"chat_assistant_id, expected_code, expected_message",
|
||||
[
|
||||
("", 100, "<MethodNotAllowed '405: Method Not Allowed'>"),
|
||||
("invalid_chat_assistant_id", 102, "You do not own the assistant."),
|
||||
],
|
||||
)
|
||||
def test_invalid_chat_assistant_id(self, api_key, chat_assistant_id, expected_code, expected_message):
|
||||
res = create_session_with_chat_assistant(api_key, chat_assistant_id, {"name": "valid_name"})
|
||||
assert res["code"] == expected_code
|
||||
assert res["message"] == expected_message
|
||||
|
||||
@pytest.mark.p3
|
||||
def test_concurrent_create_session(self, api_key, add_chat_assistants):
|
||||
chunk_num = 1000
|
||||
_, _, chat_assistant_ids = add_chat_assistants
|
||||
res = list_session_with_chat_assistants(api_key, chat_assistant_ids[0])
|
||||
if res["code"] != 0:
|
||||
assert False, res
|
||||
chunks_count = len(res["data"])
|
||||
|
||||
with ThreadPoolExecutor(max_workers=5) as executor:
|
||||
futures = [
|
||||
executor.submit(
|
||||
create_session_with_chat_assistant,
|
||||
api_key,
|
||||
chat_assistant_ids[0],
|
||||
{"name": f"session with chat assistant test {i}"},
|
||||
)
|
||||
for i in range(chunk_num)
|
||||
]
|
||||
responses = [f.result() for f in futures]
|
||||
assert all(r["code"] == 0 for r in responses)
|
||||
res = list_session_with_chat_assistants(api_key, chat_assistant_ids[0], {"page_size": chunk_num})
|
||||
if res["code"] != 0:
|
||||
assert False, res
|
||||
assert len(res["data"]) == chunks_count + chunk_num
|
||||
|
||||
@pytest.mark.p3
|
||||
def test_add_session_to_deleted_chat_assistant(self, api_key, add_chat_assistants):
|
||||
_, _, chat_assistant_ids = add_chat_assistants
|
||||
res = delete_chat_assistants(api_key, {"ids": [chat_assistant_ids[0]]})
|
||||
assert res["code"] == 0
|
||||
res = create_session_with_chat_assistant(api_key, chat_assistant_ids[0], {"name": "valid_name"})
|
||||
assert res["code"] == 102
|
||||
assert res["message"] == "You do not own the assistant."
|
||||
@ -0,0 +1,170 @@
|
||||
#
|
||||
# Copyright 2025 The InfiniFlow Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
import pytest
|
||||
from common import INVALID_API_TOKEN, batch_add_sessions_with_chat_assistant, delete_session_with_chat_assistants, list_session_with_chat_assistants
|
||||
from libs.auth import RAGFlowHttpApiAuth
|
||||
|
||||
|
||||
@pytest.mark.p1
|
||||
class TestAuthorization:
|
||||
@pytest.mark.parametrize(
|
||||
"invalid_auth, expected_code, expected_message",
|
||||
[
|
||||
(None, 0, "`Authorization` can't be empty"),
|
||||
(
|
||||
RAGFlowHttpApiAuth(INVALID_API_TOKEN),
|
||||
109,
|
||||
"Authentication error: API key is invalid!",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_invalid_auth(self, invalid_auth, expected_code, expected_message):
|
||||
res = delete_session_with_chat_assistants(invalid_auth, "chat_assistant_id")
|
||||
assert res["code"] == expected_code
|
||||
assert res["message"] == expected_message
|
||||
|
||||
|
||||
class TestSessionWithChatAssistantDelete:
|
||||
@pytest.mark.p3
|
||||
@pytest.mark.parametrize(
|
||||
"chat_assistant_id, expected_code, expected_message",
|
||||
[
|
||||
("", 100, "<MethodNotAllowed '405: Method Not Allowed'>"),
|
||||
(
|
||||
"invalid_chat_assistant_id",
|
||||
102,
|
||||
"You don't own the chat",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_invalid_chat_assistant_id(self, api_key, add_sessions_with_chat_assistant_func, chat_assistant_id, expected_code, expected_message):
|
||||
_, session_ids = add_sessions_with_chat_assistant_func
|
||||
res = delete_session_with_chat_assistants(api_key, chat_assistant_id, {"ids": session_ids})
|
||||
assert res["code"] == expected_code
|
||||
assert res["message"] == expected_message
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"payload",
|
||||
[
|
||||
pytest.param(lambda r: {"ids": ["invalid_id"] + r}, marks=pytest.mark.p3),
|
||||
pytest.param(lambda r: {"ids": r[:1] + ["invalid_id"] + r[1:5]}, marks=pytest.mark.p1),
|
||||
pytest.param(lambda r: {"ids": r + ["invalid_id"]}, marks=pytest.mark.p3),
|
||||
],
|
||||
)
|
||||
def test_delete_partial_invalid_id(self, api_key, add_sessions_with_chat_assistant_func, payload):
|
||||
chat_assistant_id, session_ids = add_sessions_with_chat_assistant_func
|
||||
if callable(payload):
|
||||
payload = payload(session_ids)
|
||||
res = delete_session_with_chat_assistants(api_key, chat_assistant_id, payload)
|
||||
assert res["code"] == 0
|
||||
assert res["data"]["errors"][0] == "The chat doesn't own the session invalid_id"
|
||||
|
||||
res = list_session_with_chat_assistants(api_key, chat_assistant_id)
|
||||
if res["code"] != 0:
|
||||
assert False, res
|
||||
assert len(res["data"]) == 0
|
||||
|
||||
@pytest.mark.p3
|
||||
def test_repeated_deletion(self, api_key, add_sessions_with_chat_assistant_func):
|
||||
chat_assistant_id, session_ids = add_sessions_with_chat_assistant_func
|
||||
payload = {"ids": session_ids}
|
||||
res = delete_session_with_chat_assistants(api_key, chat_assistant_id, payload)
|
||||
assert res["code"] == 0
|
||||
|
||||
res = delete_session_with_chat_assistants(api_key, chat_assistant_id, payload)
|
||||
assert res["code"] == 102
|
||||
assert "The chat doesn't own the session" in res["message"]
|
||||
|
||||
@pytest.mark.p3
|
||||
def test_duplicate_deletion(self, api_key, add_sessions_with_chat_assistant_func):
|
||||
chat_assistant_id, session_ids = add_sessions_with_chat_assistant_func
|
||||
res = delete_session_with_chat_assistants(api_key, chat_assistant_id, {"ids": session_ids * 2})
|
||||
assert res["code"] == 0
|
||||
assert "Duplicate session ids" in res["data"]["errors"][0]
|
||||
assert res["data"]["success_count"] == 5
|
||||
|
||||
res = list_session_with_chat_assistants(api_key, chat_assistant_id)
|
||||
if res["code"] != 0:
|
||||
assert False, res
|
||||
assert len(res["data"]) == 0
|
||||
|
||||
@pytest.mark.p3
|
||||
def test_concurrent_deletion(self, api_key, add_chat_assistants):
|
||||
sessions_num = 100
|
||||
_, _, chat_assistant_ids = add_chat_assistants
|
||||
session_ids = batch_add_sessions_with_chat_assistant(api_key, chat_assistant_ids[0], sessions_num)
|
||||
|
||||
with ThreadPoolExecutor(max_workers=5) as executor:
|
||||
futures = [
|
||||
executor.submit(
|
||||
delete_session_with_chat_assistants,
|
||||
api_key,
|
||||
chat_assistant_ids[0],
|
||||
{"ids": session_ids[i : i + 1]},
|
||||
)
|
||||
for i in range(sessions_num)
|
||||
]
|
||||
responses = [f.result() for f in futures]
|
||||
assert all(r["code"] == 0 for r in responses)
|
||||
|
||||
@pytest.mark.p3
|
||||
def test_delete_1k(self, api_key, add_chat_assistants):
|
||||
sessions_num = 1_000
|
||||
_, _, chat_assistant_ids = add_chat_assistants
|
||||
session_ids = batch_add_sessions_with_chat_assistant(api_key, chat_assistant_ids[0], sessions_num)
|
||||
|
||||
res = delete_session_with_chat_assistants(api_key, chat_assistant_ids[0], {"ids": session_ids})
|
||||
assert res["code"] == 0
|
||||
|
||||
res = list_session_with_chat_assistants(api_key, chat_assistant_ids[0])
|
||||
if res["code"] != 0:
|
||||
assert False, res
|
||||
assert len(res["data"]) == 0
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"payload, expected_code, expected_message, remaining",
|
||||
[
|
||||
pytest.param(None, 0, """TypeError("argument of type \'NoneType\' is not iterable")""", 0, marks=pytest.mark.skip),
|
||||
pytest.param({"ids": ["invalid_id"]}, 102, "The chat doesn't own the session invalid_id", 5, marks=pytest.mark.p3),
|
||||
pytest.param("not json", 100, """AttributeError("\'str\' object has no attribute \'get\'")""", 5, marks=pytest.mark.skip),
|
||||
pytest.param(lambda r: {"ids": r[:1]}, 0, "", 4, marks=pytest.mark.p3),
|
||||
pytest.param(lambda r: {"ids": r}, 0, "", 0, marks=pytest.mark.p1),
|
||||
pytest.param({"ids": []}, 0, "", 0, marks=pytest.mark.p3),
|
||||
],
|
||||
)
|
||||
def test_basic_scenarios(
|
||||
self,
|
||||
api_key,
|
||||
add_sessions_with_chat_assistant_func,
|
||||
payload,
|
||||
expected_code,
|
||||
expected_message,
|
||||
remaining,
|
||||
):
|
||||
chat_assistant_id, session_ids = add_sessions_with_chat_assistant_func
|
||||
if callable(payload):
|
||||
payload = payload(session_ids)
|
||||
res = delete_session_with_chat_assistants(api_key, chat_assistant_id, payload)
|
||||
assert res["code"] == expected_code
|
||||
if res["code"] != 0:
|
||||
assert res["message"] == expected_message
|
||||
|
||||
res = list_session_with_chat_assistants(api_key, chat_assistant_id)
|
||||
if res["code"] != 0:
|
||||
assert False, res
|
||||
assert len(res["data"]) == remaining
|
||||
@ -0,0 +1,247 @@
|
||||
#
|
||||
# Copyright 2025 The InfiniFlow Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
import pytest
|
||||
from common import INVALID_API_TOKEN, delete_chat_assistants, list_session_with_chat_assistants
|
||||
from libs.auth import RAGFlowHttpApiAuth
|
||||
from utils import is_sorted
|
||||
|
||||
|
||||
@pytest.mark.p1
|
||||
class TestAuthorization:
|
||||
@pytest.mark.parametrize(
|
||||
"invalid_auth, expected_code, expected_message",
|
||||
[
|
||||
(None, 0, "`Authorization` can't be empty"),
|
||||
(
|
||||
RAGFlowHttpApiAuth(INVALID_API_TOKEN),
|
||||
109,
|
||||
"Authentication error: API key is invalid!",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_invalid_auth(self, invalid_auth, expected_code, expected_message):
|
||||
res = list_session_with_chat_assistants(invalid_auth, "chat_assistant_id")
|
||||
assert res["code"] == expected_code
|
||||
assert res["message"] == expected_message
|
||||
|
||||
|
||||
class TestSessionsWithChatAssistantList:
|
||||
@pytest.mark.p1
|
||||
@pytest.mark.parametrize(
|
||||
"params, expected_code, expected_page_size, expected_message",
|
||||
[
|
||||
({"page": None, "page_size": 2}, 0, 2, ""),
|
||||
pytest.param({"page": 0, "page_size": 2}, 100, 0, "ValueError('Search does not support negative slicing.')", marks=pytest.mark.skip),
|
||||
({"page": 2, "page_size": 2}, 0, 2, ""),
|
||||
({"page": 3, "page_size": 2}, 0, 1, ""),
|
||||
({"page": "3", "page_size": 2}, 0, 1, ""),
|
||||
pytest.param({"page": -1, "page_size": 2}, 100, 0, "ValueError('Search does not support negative slicing.')", marks=pytest.mark.skip),
|
||||
pytest.param({"page": "a", "page_size": 2}, 100, 0, """ValueError("invalid literal for int() with base 10: \'a\'")""", marks=pytest.mark.skip),
|
||||
],
|
||||
)
|
||||
def test_page(self, api_key, add_sessions_with_chat_assistant, params, expected_code, expected_page_size, expected_message):
|
||||
chat_assistant_id, _ = add_sessions_with_chat_assistant
|
||||
res = list_session_with_chat_assistants(api_key, chat_assistant_id, params=params)
|
||||
assert res["code"] == expected_code
|
||||
if expected_code == 0:
|
||||
assert len(res["data"]) == expected_page_size
|
||||
else:
|
||||
assert res["message"] == expected_message
|
||||
|
||||
@pytest.mark.p1
|
||||
@pytest.mark.parametrize(
|
||||
"params, expected_code, expected_page_size, expected_message",
|
||||
[
|
||||
({"page_size": None}, 0, 5, ""),
|
||||
({"page_size": 0}, 0, 0, ""),
|
||||
({"page_size": 1}, 0, 1, ""),
|
||||
({"page_size": 6}, 0, 5, ""),
|
||||
({"page_size": "1"}, 0, 1, ""),
|
||||
pytest.param({"page_size": -1}, 0, 5, "", marks=pytest.mark.skip),
|
||||
pytest.param({"page_size": "a"}, 100, 0, """ValueError("invalid literal for int() with base 10: \'a\'")""", marks=pytest.mark.skip),
|
||||
],
|
||||
)
|
||||
def test_page_size(self, api_key, add_sessions_with_chat_assistant, params, expected_code, expected_page_size, expected_message):
|
||||
chat_assistant_id, _ = add_sessions_with_chat_assistant
|
||||
res = list_session_with_chat_assistants(api_key, chat_assistant_id, params=params)
|
||||
assert res["code"] == expected_code
|
||||
if expected_code == 0:
|
||||
assert len(res["data"]) == expected_page_size
|
||||
else:
|
||||
assert res["message"] == expected_message
|
||||
|
||||
@pytest.mark.p3
|
||||
@pytest.mark.parametrize(
|
||||
"params, expected_code, assertions, expected_message",
|
||||
[
|
||||
({"orderby": None}, 0, lambda r: (is_sorted(r["data"], "create_time", True)), ""),
|
||||
({"orderby": "create_time"}, 0, lambda r: (is_sorted(r["data"], "create_time", True)), ""),
|
||||
({"orderby": "update_time"}, 0, lambda r: (is_sorted(r["data"], "update_time", True)), ""),
|
||||
({"orderby": "name", "desc": "False"}, 0, lambda r: (is_sorted(r["data"], "name", False)), ""),
|
||||
pytest.param({"orderby": "unknown"}, 102, 0, "orderby should be create_time or update_time", marks=pytest.mark.skip(reason="issues/")),
|
||||
],
|
||||
)
|
||||
def test_orderby(
|
||||
self,
|
||||
api_key,
|
||||
add_sessions_with_chat_assistant,
|
||||
params,
|
||||
expected_code,
|
||||
assertions,
|
||||
expected_message,
|
||||
):
|
||||
chat_assistant_id, _ = add_sessions_with_chat_assistant
|
||||
res = list_session_with_chat_assistants(api_key, chat_assistant_id, params=params)
|
||||
assert res["code"] == expected_code
|
||||
if expected_code == 0:
|
||||
if callable(assertions):
|
||||
assert assertions(res)
|
||||
else:
|
||||
assert res["message"] == expected_message
|
||||
|
||||
@pytest.mark.p3
|
||||
@pytest.mark.parametrize(
|
||||
"params, expected_code, assertions, expected_message",
|
||||
[
|
||||
({"desc": None}, 0, lambda r: (is_sorted(r["data"], "create_time", True)), ""),
|
||||
({"desc": "true"}, 0, lambda r: (is_sorted(r["data"], "create_time", True)), ""),
|
||||
({"desc": "True"}, 0, lambda r: (is_sorted(r["data"], "create_time", True)), ""),
|
||||
({"desc": True}, 0, lambda r: (is_sorted(r["data"], "create_time", True)), ""),
|
||||
({"desc": "false"}, 0, lambda r: (is_sorted(r["data"], "create_time", False)), ""),
|
||||
({"desc": "False"}, 0, lambda r: (is_sorted(r["data"], "create_time", False)), ""),
|
||||
({"desc": False}, 0, lambda r: (is_sorted(r["data"], "create_time", False)), ""),
|
||||
({"desc": "False", "orderby": "update_time"}, 0, lambda r: (is_sorted(r["data"], "update_time", False)), ""),
|
||||
pytest.param({"desc": "unknown"}, 102, 0, "desc should be true or false", marks=pytest.mark.skip(reason="issues/")),
|
||||
],
|
||||
)
|
||||
def test_desc(
|
||||
self,
|
||||
api_key,
|
||||
add_sessions_with_chat_assistant,
|
||||
params,
|
||||
expected_code,
|
||||
assertions,
|
||||
expected_message,
|
||||
):
|
||||
chat_assistant_id, _ = add_sessions_with_chat_assistant
|
||||
res = list_session_with_chat_assistants(api_key, chat_assistant_id, params=params)
|
||||
assert res["code"] == expected_code
|
||||
if expected_code == 0:
|
||||
if callable(assertions):
|
||||
assert assertions(res)
|
||||
else:
|
||||
assert res["message"] == expected_message
|
||||
|
||||
@pytest.mark.p1
|
||||
@pytest.mark.parametrize(
|
||||
"params, expected_code, expected_num, expected_message",
|
||||
[
|
||||
({"name": None}, 0, 5, ""),
|
||||
({"name": ""}, 0, 5, ""),
|
||||
({"name": "session_with_chat_assistant_1"}, 0, 1, ""),
|
||||
({"name": "unknown"}, 0, 0, ""),
|
||||
],
|
||||
)
|
||||
def test_name(self, api_key, add_sessions_with_chat_assistant, params, expected_code, expected_num, expected_message):
|
||||
chat_assistant_id, _ = add_sessions_with_chat_assistant
|
||||
res = list_session_with_chat_assistants(api_key, chat_assistant_id, params=params)
|
||||
assert res["code"] == expected_code
|
||||
if expected_code == 0:
|
||||
if params["name"] != "session_with_chat_assistant_1":
|
||||
assert len(res["data"]) == expected_num
|
||||
else:
|
||||
assert res["data"][0]["name"] == params["name"]
|
||||
else:
|
||||
assert res["message"] == expected_message
|
||||
|
||||
@pytest.mark.p1
|
||||
@pytest.mark.parametrize(
|
||||
"session_id, expected_code, expected_num, expected_message",
|
||||
[
|
||||
(None, 0, 5, ""),
|
||||
("", 0, 5, ""),
|
||||
(lambda r: r[0], 0, 1, ""),
|
||||
("unknown", 0, 0, "The chat doesn't exist"),
|
||||
],
|
||||
)
|
||||
def test_id(self, api_key, add_sessions_with_chat_assistant, session_id, expected_code, expected_num, expected_message):
|
||||
chat_assistant_id, session_ids = add_sessions_with_chat_assistant
|
||||
if callable(session_id):
|
||||
params = {"id": session_id(session_ids)}
|
||||
else:
|
||||
params = {"id": session_id}
|
||||
|
||||
res = list_session_with_chat_assistants(api_key, chat_assistant_id, params=params)
|
||||
assert res["code"] == expected_code
|
||||
if expected_code == 0:
|
||||
if params["id"] != session_ids[0]:
|
||||
assert len(res["data"]) == expected_num
|
||||
else:
|
||||
assert res["data"][0]["id"] == params["id"]
|
||||
else:
|
||||
assert res["message"] == expected_message
|
||||
|
||||
@pytest.mark.p3
|
||||
@pytest.mark.parametrize(
|
||||
"session_id, name, expected_code, expected_num, expected_message",
|
||||
[
|
||||
(lambda r: r[0], "session_with_chat_assistant_0", 0, 1, ""),
|
||||
(lambda r: r[0], "session_with_chat_assistant_100", 0, 0, ""),
|
||||
(lambda r: r[0], "unknown", 0, 0, ""),
|
||||
("id", "session_with_chat_assistant_0", 0, 0, ""),
|
||||
],
|
||||
)
|
||||
def test_name_and_id(self, api_key, add_sessions_with_chat_assistant, session_id, name, expected_code, expected_num, expected_message):
|
||||
chat_assistant_id, session_ids = add_sessions_with_chat_assistant
|
||||
if callable(session_id):
|
||||
params = {"id": session_id(session_ids), "name": name}
|
||||
else:
|
||||
params = {"id": session_id, "name": name}
|
||||
|
||||
res = list_session_with_chat_assistants(api_key, chat_assistant_id, params=params)
|
||||
assert res["code"] == expected_code
|
||||
if expected_code == 0:
|
||||
assert len(res["data"]) == expected_num
|
||||
else:
|
||||
assert res["message"] == expected_message
|
||||
|
||||
@pytest.mark.p3
|
||||
def test_concurrent_list(self, api_key, add_sessions_with_chat_assistant):
|
||||
chat_assistant_id, _ = add_sessions_with_chat_assistant
|
||||
with ThreadPoolExecutor(max_workers=5) as executor:
|
||||
futures = [executor.submit(list_session_with_chat_assistants, api_key, chat_assistant_id) for i in range(100)]
|
||||
responses = [f.result() for f in futures]
|
||||
assert all(r["code"] == 0 for r in responses)
|
||||
|
||||
@pytest.mark.p3
|
||||
def test_invalid_params(self, api_key, add_sessions_with_chat_assistant):
|
||||
chat_assistant_id, _ = add_sessions_with_chat_assistant
|
||||
params = {"a": "b"}
|
||||
res = list_session_with_chat_assistants(api_key, chat_assistant_id, params=params)
|
||||
assert res["code"] == 0
|
||||
assert len(res["data"]) == 5
|
||||
|
||||
@pytest.mark.p3
|
||||
def test_list_chats_after_deleting_associated_chat_assistant(self, api_key, add_sessions_with_chat_assistant):
|
||||
chat_assistant_id, _ = add_sessions_with_chat_assistant
|
||||
res = delete_chat_assistants(api_key, {"ids": [chat_assistant_id]})
|
||||
assert res["code"] == 0
|
||||
|
||||
res = list_session_with_chat_assistants(api_key, chat_assistant_id)
|
||||
assert res["code"] == 102
|
||||
assert "You don't own the assistant" in res["message"]
|
||||
@ -0,0 +1,148 @@
|
||||
#
|
||||
# Copyright 2025 The InfiniFlow Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from random import randint
|
||||
|
||||
import pytest
|
||||
from common import INVALID_API_TOKEN, SESSION_WITH_CHAT_NAME_LIMIT, delete_chat_assistants, list_session_with_chat_assistants, update_session_with_chat_assistant
|
||||
from libs.auth import RAGFlowHttpApiAuth
|
||||
|
||||
|
||||
@pytest.mark.p1
|
||||
class TestAuthorization:
|
||||
@pytest.mark.parametrize(
|
||||
"invalid_auth, expected_code, expected_message",
|
||||
[
|
||||
(None, 0, "`Authorization` can't be empty"),
|
||||
(
|
||||
RAGFlowHttpApiAuth(INVALID_API_TOKEN),
|
||||
109,
|
||||
"Authentication error: API key is invalid!",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_invalid_auth(self, invalid_auth, expected_code, expected_message):
|
||||
res = update_session_with_chat_assistant(invalid_auth, "chat_assistant_id", "session_id")
|
||||
assert res["code"] == expected_code
|
||||
assert res["message"] == expected_message
|
||||
|
||||
|
||||
class TestSessionWithChatAssistantUpdate:
|
||||
@pytest.mark.parametrize(
|
||||
"payload, expected_code, expected_message",
|
||||
[
|
||||
pytest.param({"name": "valid_name"}, 0, "", marks=pytest.mark.p1),
|
||||
pytest.param({"name": "a" * (SESSION_WITH_CHAT_NAME_LIMIT + 1)}, 102, "", marks=pytest.mark.skip(reason="issues/")),
|
||||
pytest.param({"name": 1}, 100, "", marks=pytest.mark.skip(reason="issues/")),
|
||||
pytest.param({"name": ""}, 102, "`name` can not be empty.", marks=pytest.mark.p3),
|
||||
pytest.param({"name": "duplicated_name"}, 0, "", marks=pytest.mark.p3),
|
||||
pytest.param({"name": "case insensitive"}, 0, "", marks=pytest.mark.p3),
|
||||
],
|
||||
)
|
||||
def test_name(self, api_key, add_sessions_with_chat_assistant_func, payload, expected_code, expected_message):
|
||||
chat_assistant_id, session_ids = add_sessions_with_chat_assistant_func
|
||||
if payload["name"] == "duplicated_name":
|
||||
update_session_with_chat_assistant(api_key, chat_assistant_id, session_ids[0], payload)
|
||||
elif payload["name"] == "case insensitive":
|
||||
update_session_with_chat_assistant(api_key, chat_assistant_id, session_ids[0], {"name": payload["name"].upper()})
|
||||
|
||||
res = update_session_with_chat_assistant(api_key, chat_assistant_id, session_ids[0], payload)
|
||||
assert res["code"] == expected_code, res
|
||||
if expected_code == 0:
|
||||
res = list_session_with_chat_assistants(api_key, chat_assistant_id, {"id": session_ids[0]})
|
||||
assert res["data"][0]["name"] == payload["name"]
|
||||
else:
|
||||
assert res["message"] == expected_message
|
||||
|
||||
@pytest.mark.p3
|
||||
@pytest.mark.parametrize(
|
||||
"chat_assistant_id, expected_code, expected_message",
|
||||
[
|
||||
("", 100, "<NotFound '404: Not Found'>"),
|
||||
pytest.param("invalid_chat_assistant_id", 102, "Session does not exist", marks=pytest.mark.skip(reason="issues/")),
|
||||
],
|
||||
)
|
||||
def test_invalid_chat_assistant_id(self, api_key, add_sessions_with_chat_assistant_func, chat_assistant_id, expected_code, expected_message):
|
||||
_, session_ids = add_sessions_with_chat_assistant_func
|
||||
res = update_session_with_chat_assistant(api_key, chat_assistant_id, session_ids[0], {"name": "valid_name"})
|
||||
assert res["code"] == expected_code
|
||||
assert res["message"] == expected_message
|
||||
|
||||
@pytest.mark.p3
|
||||
@pytest.mark.parametrize(
|
||||
"session_id, expected_code, expected_message",
|
||||
[
|
||||
("", 100, "<MethodNotAllowed '405: Method Not Allowed'>"),
|
||||
("invalid_session_id", 102, "Session does not exist"),
|
||||
],
|
||||
)
|
||||
def test_invalid_session_id(self, api_key, add_sessions_with_chat_assistant_func, session_id, expected_code, expected_message):
|
||||
chat_assistant_id, _ = add_sessions_with_chat_assistant_func
|
||||
res = update_session_with_chat_assistant(api_key, chat_assistant_id, session_id, {"name": "valid_name"})
|
||||
assert res["code"] == expected_code
|
||||
assert res["message"] == expected_message
|
||||
|
||||
@pytest.mark.p3
|
||||
def test_repeated_update_session(self, api_key, add_sessions_with_chat_assistant_func):
|
||||
chat_assistant_id, session_ids = add_sessions_with_chat_assistant_func
|
||||
res = update_session_with_chat_assistant(api_key, chat_assistant_id, session_ids[0], {"name": "valid_name_1"})
|
||||
assert res["code"] == 0
|
||||
|
||||
res = update_session_with_chat_assistant(api_key, chat_assistant_id, session_ids[0], {"name": "valid_name_2"})
|
||||
assert res["code"] == 0
|
||||
|
||||
@pytest.mark.p3
|
||||
@pytest.mark.parametrize(
|
||||
"payload, expected_code, expected_message",
|
||||
[
|
||||
pytest.param({"unknown_key": "unknown_value"}, 100, "ValueError", marks=pytest.mark.skip),
|
||||
({}, 0, ""),
|
||||
pytest.param(None, 100, "TypeError", marks=pytest.mark.skip),
|
||||
],
|
||||
)
|
||||
def test_invalid_params(self, api_key, add_sessions_with_chat_assistant_func, payload, expected_code, expected_message):
|
||||
chat_assistant_id, session_ids = add_sessions_with_chat_assistant_func
|
||||
res = update_session_with_chat_assistant(api_key, chat_assistant_id, session_ids[0], payload)
|
||||
assert res["code"] == expected_code
|
||||
if expected_code != 0:
|
||||
assert expected_message in res["message"]
|
||||
|
||||
@pytest.mark.p3
|
||||
def test_concurrent_update_session(self, api_key, add_sessions_with_chat_assistant_func):
|
||||
chunk_num = 50
|
||||
chat_assistant_id, session_ids = add_sessions_with_chat_assistant_func
|
||||
|
||||
with ThreadPoolExecutor(max_workers=5) as executor:
|
||||
futures = [
|
||||
executor.submit(
|
||||
update_session_with_chat_assistant,
|
||||
api_key,
|
||||
chat_assistant_id,
|
||||
session_ids[randint(0, 4)],
|
||||
{"name": f"update session test {i}"},
|
||||
)
|
||||
for i in range(chunk_num)
|
||||
]
|
||||
responses = [f.result() for f in futures]
|
||||
assert all(r["code"] == 0 for r in responses)
|
||||
|
||||
@pytest.mark.p3
|
||||
def test_update_session_to_deleted_chat_assistant(self, api_key, add_sessions_with_chat_assistant_func):
|
||||
chat_assistant_id, session_ids = add_sessions_with_chat_assistant_func
|
||||
delete_chat_assistants(api_key, {"ids": [chat_assistant_id]})
|
||||
res = update_session_with_chat_assistant(api_key, chat_assistant_id, session_ids[0], {"name": "valid_name"})
|
||||
assert res["code"] == 102
|
||||
assert res["message"] == "You do not own the session"
|
||||
Reference in New Issue
Block a user