diff --git a/test/testcases/test_web_api/test_message_app/conftest.py b/test/testcases/test_web_api/test_message_app/conftest.py index 424926416..353ac6b57 100644 --- a/test/testcases/test_web_api/test_message_app/conftest.py +++ b/test/testcases/test_web_api/test_message_app/conftest.py @@ -38,9 +38,54 @@ def add_empty_raw_type_memory(request, WebApiAuth): res = create_memory(WebApiAuth, payload) memory_id = res["data"]["id"] request.cls.memory_id = memory_id + request.cls.memory_type = payload["memory_type"] return memory_id +@pytest.fixture(scope="class") +def add_empty_multiple_type_memory(request, WebApiAuth): + def cleanup(): + memory_list_res = list_memory(WebApiAuth) + exist_memory_ids = [memory["id"] for memory in memory_list_res["data"]["memory_list"]] + for _memory_id in exist_memory_ids: + delete_memory(WebApiAuth, _memory_id) + request.addfinalizer(cleanup) + payload = { + "name": "test_memory_0", + "memory_type": ["raw"] + random.choices(["semantic", "episodic", "procedural"], k=random.randint(1, 3)), + "embd_id": "BAAI/bge-small-en-v1.5@Builtin", + "llm_id": "glm-4-flash@ZHIPU-AI" + } + res = create_memory(WebApiAuth, payload) + memory_id = res["data"]["id"] + request.cls.memory_id = memory_id + request.cls.memory_type = payload["memory_type"] + return memory_id + + +@pytest.fixture(scope="class") +def add_2_multiple_type_memory(request, WebApiAuth): + def cleanup(): + memory_list_res = list_memory(WebApiAuth) + exist_memory_ids = [memory["id"] for memory in memory_list_res["data"]["memory_list"]] + for _memory_id in exist_memory_ids: + delete_memory(WebApiAuth, _memory_id) + + request.addfinalizer(cleanup) + memory_ids = [] + for i in range(2): + payload = { + "name": f"test_memory_{i}", + "memory_type": ["raw"] + random.choices(["semantic", "episodic", "procedural"], k=random.randint(1, 3)), + "embd_id": "BAAI/bge-small-en-v1.5@Builtin", + "llm_id": "glm-4-flash@ZHIPU-AI" + } + res = create_memory(WebApiAuth, payload) + memory_ids.append(res["data"]["id"]) + request.cls.memory_ids = memory_ids + return memory_ids + + @pytest.fixture(scope="class") def add_memory_with_multiple_type_message_func(request, WebApiAuth): def cleanup(): diff --git a/test/testcases/test_web_api/test_message_app/test_add_message.py b/test/testcases/test_web_api/test_message_app/test_add_message.py new file mode 100644 index 000000000..83c06e86e --- /dev/null +++ b/test/testcases/test_web_api/test_message_app/test_add_message.py @@ -0,0 +1,145 @@ +# +# 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 time +import uuid +import pytest + +from test_web_api.common import list_memory_message, add_message +from configs import INVALID_API_TOKEN +from libs.auth import RAGFlowWebApiAuth + +class TestAuthorization: + @pytest.mark.p1 + @pytest.mark.parametrize( + "invalid_auth, expected_code, expected_message", + [ + (None, 401, ""), + (RAGFlowWebApiAuth(INVALID_API_TOKEN), 401, ""), + ], + ) + def test_auth_invalid(self, invalid_auth, expected_code, expected_message): + res = add_message(invalid_auth, {}) + assert res["code"] == expected_code, res + assert res["message"] == expected_message, res + + +@pytest.mark.usefixtures("add_empty_raw_type_memory") +class TestAddRawMessage: + + @pytest.mark.p1 + def test_add_raw_message(self, WebApiAuth): + memory_id = self.memory_id + agent_id = uuid.uuid4().hex + session_id = uuid.uuid4().hex + message_payload = { + "memory_id": [memory_id], + "agent_id": agent_id, + "session_id": session_id, + "user_id": "", + "user_input": "what is pineapple?", + "agent_response": """ +A pineapple is a tropical fruit known for its sweet, tangy flavor and distinctive, spiky appearance. Here are the key facts: +Scientific Name: Ananas comosus +Physical Description: It has a tough, spiky, diamond-patterned outer skin (rind) that is usually green, yellow, or brownish. Inside, the juicy yellow flesh surrounds a fibrous core. +Growth: Unlike most fruits, pineapples do not grow on trees. They grow from a central stem as a composite fruit, meaning they are formed from many individual berries that fuse together around the core. They grow on a short, leafy plant close to the ground. +Uses: Pineapples are eaten fresh, cooked, grilled, juiced, or canned. They are a popular ingredient in desserts, fruit salads, savory dishes (like pizzas or ham glazes), smoothies, and cocktails. +Nutrition: They are a good source of Vitamin C, manganese, and contain an enzyme called bromelain, which aids in digestion and can tenderize meat. +Symbolism: The pineapple is a traditional symbol of hospitality and welcome in many cultures. +Are you asking about the fruit itself, or its use in a specific context? +""" + } + add_res = add_message(WebApiAuth, message_payload) + assert add_res["code"] == 0, add_res + time.sleep(2) # make sure refresh to index before search + message_res = list_memory_message(WebApiAuth, memory_id, params={"agent_id": agent_id, "keywords": session_id}) + assert message_res["code"] == 0, message_res + assert message_res["data"]["messages"]["total_count"] > 0 + for message in message_res["data"]["messages"]["message_list"]: + assert message["agent_id"] == agent_id, message + assert message["session_id"] == session_id, message + + +@pytest.mark.usefixtures("add_empty_multiple_type_memory") +class TestAddMultipleTypeMessage: + + @pytest.mark.p1 + def test_add_multiple_type_message(self, WebApiAuth): + memory_id = self.memory_id + agent_id = uuid.uuid4().hex + session_id = uuid.uuid4().hex + message_payload = { + "memory_id": [memory_id], + "agent_id": agent_id, + "session_id": session_id, + "user_id": "", + "user_input": "what is pineapple?", + "agent_response": """ +A pineapple is a tropical fruit known for its sweet, tangy flavor and distinctive, spiky appearance. Here are the key facts: +Scientific Name: Ananas comosus +Physical Description: It has a tough, spiky, diamond-patterned outer skin (rind) that is usually green, yellow, or brownish. Inside, the juicy yellow flesh surrounds a fibrous core. +Growth: Unlike most fruits, pineapples do not grow on trees. They grow from a central stem as a composite fruit, meaning they are formed from many individual berries that fuse together around the core. They grow on a short, leafy plant close to the ground. +Uses: Pineapples are eaten fresh, cooked, grilled, juiced, or canned. They are a popular ingredient in desserts, fruit salads, savory dishes (like pizzas or ham glazes), smoothies, and cocktails. +Nutrition: They are a good source of Vitamin C, manganese, and contain an enzyme called bromelain, which aids in digestion and can tenderize meat. +Symbolism: The pineapple is a traditional symbol of hospitality and welcome in many cultures. +Are you asking about the fruit itself, or its use in a specific context? +""" + } + add_res = add_message(WebApiAuth, message_payload) + assert add_res["code"] == 0, add_res + time.sleep(2) # make sure refresh to index before search + message_res = list_memory_message(WebApiAuth, memory_id, params={"agent_id": agent_id, "keywords": session_id}) + assert message_res["code"] == 0, message_res + assert message_res["data"]["messages"]["total_count"] > 0 + for message in message_res["data"]["messages"]["message_list"]: + assert message["agent_id"] == agent_id, message + assert message["session_id"] == session_id, message + + +@pytest.mark.usefixtures("add_2_multiple_type_memory") +class TestAddToMultipleMemory: + + @pytest.mark.p1 + def test_add_to_multiple_memory(self, WebApiAuth): + memory_ids = self.memory_ids + agent_id = uuid.uuid4().hex + session_id = uuid.uuid4().hex + message_payload = { + "memory_id": memory_ids, + "agent_id": agent_id, + "session_id": session_id, + "user_id": "", + "user_input": "what is pineapple?", + "agent_response": """ +A pineapple is a tropical fruit known for its sweet, tangy flavor and distinctive, spiky appearance. Here are the key facts: +Scientific Name: Ananas comosus +Physical Description: It has a tough, spiky, diamond-patterned outer skin (rind) that is usually green, yellow, or brownish. Inside, the juicy yellow flesh surrounds a fibrous core. +Growth: Unlike most fruits, pineapples do not grow on trees. They grow from a central stem as a composite fruit, meaning they are formed from many individual berries that fuse together around the core. They grow on a short, leafy plant close to the ground. +Uses: Pineapples are eaten fresh, cooked, grilled, juiced, or canned. They are a popular ingredient in desserts, fruit salads, savory dishes (like pizzas or ham glazes), smoothies, and cocktails. +Nutrition: They are a good source of Vitamin C, manganese, and contain an enzyme called bromelain, which aids in digestion and can tenderize meat. +Symbolism: The pineapple is a traditional symbol of hospitality and welcome in many cultures. +Are you asking about the fruit itself, or its use in a specific context? +""" + } + add_res = add_message(WebApiAuth, message_payload) + assert add_res["code"] == 0, add_res + time.sleep(2) # make sure refresh to index before search + for memory_id in memory_ids: + message_res = list_memory_message(WebApiAuth, memory_id, params={"agent_id": agent_id, "keywords": session_id}) + assert message_res["code"] == 0, message_res + assert message_res["data"]["messages"]["total_count"] > 0 + for message in message_res["data"]["messages"]["message_list"]: + assert message["agent_id"] == agent_id, message + assert message["session_id"] == session_id, message diff --git a/test/testcases/test_web_api/test_message_app/test_forget_message.py b/test/testcases/test_web_api/test_message_app/test_forget_message.py new file mode 100644 index 000000000..897d82f0d --- /dev/null +++ b/test/testcases/test_web_api/test_message_app/test_forget_message.py @@ -0,0 +1,54 @@ +# +# 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 random +import pytest +from test_web_api.common import forget_message, list_memory_message, get_message_content +from configs import INVALID_API_TOKEN +from libs.auth import RAGFlowWebApiAuth + + +class TestAuthorization: + @pytest.mark.p1 + @pytest.mark.parametrize( + "invalid_auth, expected_code, expected_message", + [ + (None, 401, ""), + (RAGFlowWebApiAuth(INVALID_API_TOKEN), 401, ""), + ], + ) + def test_auth_invalid(self, invalid_auth, expected_code, expected_message): + res = forget_message(invalid_auth, "empty_memory_id", 0) + assert res["code"] == expected_code, res + assert res["message"] == expected_message, res + + +@pytest.mark.usefixtures("add_memory_with_5_raw_message_func") +class TestForgetMessage: + + @pytest.mark.p1 + def test_forget_message(self, WebApiAuth): + memory_id = self.memory_id + list_res = list_memory_message(WebApiAuth, memory_id) + assert list_res["code"] == 0, list_res + assert len(list_res["data"]["messages"]["message_list"]) > 0 + + message = random.choice(list_res["data"]["messages"]["message_list"]) + res = forget_message(WebApiAuth, memory_id, message["message_id"]) + assert res["code"] == 0, res + + forgot_message_res = get_message_content(WebApiAuth, memory_id, message["message_id"]) + assert forgot_message_res["code"] == 0, forgot_message_res + assert forgot_message_res["data"]["forget_at"] not in ["-", ""], forgot_message_res diff --git a/test/testcases/test_web_api/test_message_app/test_search_message.py b/test/testcases/test_web_api/test_message_app/test_search_message.py new file mode 100644 index 000000000..d3a99cbe5 --- /dev/null +++ b/test/testcases/test_web_api/test_message_app/test_search_message.py @@ -0,0 +1,82 @@ +# +# 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 test_web_api.common import search_message, list_memory_message +from configs import INVALID_API_TOKEN +from libs.auth import RAGFlowWebApiAuth + +class TestAuthorization: + @pytest.mark.p1 + @pytest.mark.parametrize( + "invalid_auth, expected_code, expected_message", + [ + (None, 401, ""), + (RAGFlowWebApiAuth(INVALID_API_TOKEN), 401, ""), + ], + ) + def test_auth_invalid(self, invalid_auth, expected_code, expected_message): + res = search_message(invalid_auth) + assert res["code"] == expected_code, res + assert res["message"] == expected_message, res + + +@pytest.mark.usefixtures("add_memory_with_multiple_type_message_func") +class TestSearchMessage: + + @pytest.mark.p1 + def test_query(self, WebApiAuth): + memory_id = self.memory_id + list_res = list_memory_message(WebApiAuth, memory_id) + assert list_res["code"] == 0, list_res + assert list_res["data"]["messages"]["total_count"] > 0 + + query = "Coriander is a versatile herb with two main edible parts. What's its name can refer to?" + res = search_message(WebApiAuth, {"memory_id": memory_id, "query": query}) + assert res["code"] == 0, res + assert len(res["data"]) > 0 + + @pytest.mark.p2 + def test_query_with_agent_filter(self, WebApiAuth): + memory_id = self.memory_id + list_res = list_memory_message(WebApiAuth, memory_id) + assert list_res["code"] == 0, list_res + assert list_res["data"]["messages"]["total_count"] > 0 + + agent_id = self.agent_id + query = "Coriander is a versatile herb with two main edible parts. What's its name can refer to?" + res = search_message(WebApiAuth, {"memory_id": memory_id, "query": query, "agent_id": agent_id}) + assert res["code"] == 0, res + assert len(res["data"]) > 0 + for message in res["data"]: + assert message["agent_id"] == agent_id, message + + @pytest.mark.p2 + def test_query_with_not_default_params(self, WebApiAuth): + memory_id = self.memory_id + list_res = list_memory_message(WebApiAuth, memory_id) + assert list_res["code"] == 0, list_res + assert list_res["data"]["messages"]["total_count"] > 0 + + query = "Coriander is a versatile herb with two main edible parts. What's its name can refer to?" + params = { + "similarity_threshold": 0.1, + "keywords_similarity_weight": 0.6, + "top_n": 4 + } + res = search_message(WebApiAuth, {"memory_id": memory_id, "query": query, **params}) + assert res["code"] == 0, res + assert len(res["data"]) > 0 + assert len(res["data"]) <= params["top_n"] diff --git a/test/testcases/test_web_api/test_message_app/test_update_message_status.py b/test/testcases/test_web_api/test_message_app/test_update_message_status.py new file mode 100644 index 000000000..b8a5c60fa --- /dev/null +++ b/test/testcases/test_web_api/test_message_app/test_update_message_status.py @@ -0,0 +1,75 @@ +# +# 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 random + +import pytest +from test_web_api.common import update_message_status, list_memory_message, get_message_content +from configs import INVALID_API_TOKEN +from libs.auth import RAGFlowWebApiAuth + + +class TestAuthorization: + @pytest.mark.p1 + @pytest.mark.parametrize( + "invalid_auth, expected_code, expected_message", + [ + (None, 401, ""), + (RAGFlowWebApiAuth(INVALID_API_TOKEN), 401, ""), + ], + ) + def test_auth_invalid(self, invalid_auth, expected_code, expected_message): + res = update_message_status(invalid_auth, "empty_memory_id", 0, False) + assert res["code"] == expected_code, res + assert res["message"] == expected_message, res + + +@pytest.mark.usefixtures("add_memory_with_5_raw_message_func") +class TestUpdateMessageStatus: + + @pytest.mark.p1 + def test_update_to_false(self, WebApiAuth): + memory_id = self.memory_id + list_res = list_memory_message(WebApiAuth, memory_id) + assert list_res["code"] == 0, list_res + assert len(list_res["data"]["messages"]["message_list"]) > 0 + + message = random.choice(list_res["data"]["messages"]["message_list"]) + res = update_message_status(WebApiAuth, memory_id, message["message_id"], False) + assert res["code"] == 0, res + + updated_message_res = get_message_content(WebApiAuth, memory_id, message["message_id"]) + assert updated_message_res["code"] == 0, res + assert not updated_message_res["data"]["status"], res + + @pytest.mark.p1 + def test_update_to_true(self, WebApiAuth): + memory_id = self.memory_id + list_res = list_memory_message(WebApiAuth, memory_id) + assert list_res["code"] == 0, list_res + assert len(list_res["data"]["messages"]["message_list"]) > 0 + # set 1 random message to false first + message = random.choice(list_res["data"]["messages"]["message_list"]) + set_to_false_res = update_message_status(WebApiAuth, memory_id, message["message_id"], False) + assert set_to_false_res["code"] == 0, set_to_false_res + updated_message_res = get_message_content(WebApiAuth, memory_id, message["message_id"]) + assert updated_message_res["code"] == 0, set_to_false_res + assert not updated_message_res["data"]["status"], updated_message_res + # set to true + set_to_true_res = update_message_status(WebApiAuth, memory_id, message["message_id"], True) + assert set_to_true_res["code"] == 0, set_to_true_res + res = get_message_content(WebApiAuth, memory_id, message["message_id"]) + assert res["code"] == 0, res + assert res["data"]["status"], res