mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-01-23 03:26:53 +08:00
Feat: message write testcase (#12417)
### What problem does this PR solve? Write testcase for message web apis. ### Type of change - [x] New Feature (non-breaking change which adds functionality) --------- Co-authored-by: Kevin Hu <kevinhu.sh@gmail.com>
This commit is contained in:
@ -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():
|
||||
|
||||
145
test/testcases/test_web_api/test_message_app/test_add_message.py
Normal file
145
test/testcases/test_web_api/test_message_app/test_add_message.py
Normal file
@ -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, "<Unauthorized '401: Unauthorized'>"),
|
||||
(RAGFlowWebApiAuth(INVALID_API_TOKEN), 401, "<Unauthorized '401: Unauthorized'>"),
|
||||
],
|
||||
)
|
||||
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
|
||||
@ -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, "<Unauthorized '401: Unauthorized'>"),
|
||||
(RAGFlowWebApiAuth(INVALID_API_TOKEN), 401, "<Unauthorized '401: Unauthorized'>"),
|
||||
],
|
||||
)
|
||||
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
|
||||
@ -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, "<Unauthorized '401: Unauthorized'>"),
|
||||
(RAGFlowWebApiAuth(INVALID_API_TOKEN), 401, "<Unauthorized '401: Unauthorized'>"),
|
||||
],
|
||||
)
|
||||
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"]
|
||||
@ -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, "<Unauthorized '401: Unauthorized'>"),
|
||||
(RAGFlowWebApiAuth(INVALID_API_TOKEN), 401, "<Unauthorized '401: Unauthorized'>"),
|
||||
],
|
||||
)
|
||||
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
|
||||
Reference in New Issue
Block a user