test_conversations.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. import uuid
  2. import pytest
  3. from r2r import R2RClient, R2RException
  4. @pytest.fixture(scope="session")
  5. def config():
  6. class TestConfig:
  7. base_url = "http://localhost:7272"
  8. superuser_email = "admin@example.com"
  9. superuser_password = "change_me_immediately"
  10. return TestConfig()
  11. @pytest.fixture(scope="session")
  12. def client(config):
  13. """Create a client instance and log in as a superuser."""
  14. client = R2RClient(config.base_url)
  15. client.users.login(config.superuser_email, config.superuser_password)
  16. return client
  17. @pytest.fixture
  18. def test_conversation(client):
  19. """Create and yield a test conversation, then clean up."""
  20. conv_resp = client.conversations.create()
  21. conversation_id = conv_resp["results"]["id"]
  22. yield conversation_id
  23. # Cleanup: Try deleting the conversation if it still exists
  24. try:
  25. client.conversations.delete(id=conversation_id)
  26. except R2RException:
  27. pass
  28. def test_create_conversation(client):
  29. resp = client.conversations.create()["results"]
  30. conv_id = resp["id"]
  31. assert conv_id is not None, "No conversation_id returned"
  32. # Cleanup
  33. client.conversations.delete(id=conv_id)
  34. def test_list_conversations(client, test_conversation):
  35. listed = client.conversations.list(offset=0, limit=10)
  36. results = listed["results"]
  37. # Just ensure at least one conversation is listed
  38. assert len(results) >= 1, "Expected at least one conversation, none found"
  39. def test_retrieve_conversation(client, test_conversation):
  40. # Retrieve the conversation just created
  41. retrieved = client.conversations.retrieve(id=test_conversation)["results"]
  42. # A new conversation might have no messages, so results should be an empty list
  43. assert isinstance(retrieved, list), "Expected list of messages"
  44. assert (
  45. len(retrieved) == 0
  46. ), "Expected empty message list for a new conversation"
  47. def test_delete_conversation(client):
  48. # Create a conversation and delete it
  49. conv = client.conversations.create()["results"]
  50. conv_id = conv["id"]
  51. client.conversations.delete(id=conv_id)
  52. # Verify retrieval fails
  53. with pytest.raises(R2RException) as exc_info:
  54. client.conversations.retrieve(id=conv_id)
  55. assert (
  56. exc_info.value.status_code == 404
  57. ), "Wrong error code retrieving deleted conversation"
  58. def test_add_message(client, test_conversation):
  59. # Add a message to the conversation
  60. msg_resp = client.conversations.add_message(
  61. id=test_conversation,
  62. content="Hello",
  63. role="user",
  64. )["results"]
  65. msg_id = msg_resp["id"]
  66. assert msg_id, "No message ID returned after adding a message"
  67. # Retrieve conversation and verify message is present
  68. retrieved = client.conversations.retrieve(id=test_conversation)["results"]
  69. found = any(msg["id"] == msg_id for msg in retrieved)
  70. assert found, "Added message not found in conversation"
  71. def test_retrieve_non_existent_conversation(client):
  72. bad_id = str(uuid.uuid4())
  73. with pytest.raises(R2RException) as exc_info:
  74. client.conversations.retrieve(id=bad_id)
  75. assert (
  76. exc_info.value.status_code == 404
  77. ), "Wrong error code for non-existent conversation"
  78. def test_delete_non_existent_conversation(client):
  79. bad_id = str(uuid.uuid4())
  80. with pytest.raises(R2RException) as exc_info:
  81. result = client.conversations.delete(id=bad_id)
  82. print(result)
  83. assert (
  84. exc_info.value.status_code == 404
  85. ), "Wrong error code for delete non-existent"
  86. def test_add_message_to_non_existent_conversation(client):
  87. bad_id = str(uuid.uuid4())
  88. with pytest.raises(R2RException) as exc_info:
  89. client.conversations.add_message(
  90. id=bad_id,
  91. content="Hi",
  92. role="user",
  93. )
  94. # Expected a 404 since conversation doesn't exist
  95. assert (
  96. exc_info.value.status_code == 404
  97. ), "Wrong error code for adding message to non-existent conversation"
  98. def test_update_message(client, test_conversation):
  99. # Add a message first
  100. msg_resp = client.conversations.add_message(
  101. id=test_conversation,
  102. content="Original content",
  103. role="user",
  104. )["results"]
  105. original_msg_id = msg_resp["id"]
  106. # Update the message
  107. update_resp = client.conversations.update_message(
  108. id=test_conversation,
  109. message_id=original_msg_id,
  110. content="Updated content",
  111. metadata={"new_key": "new_value"},
  112. )["results"]
  113. print(update_resp)
  114. # /new_branch_id = update_resp["new_branch_id"]
  115. assert update_resp["message"], "No message returned after update"
  116. assert update_resp["metadata"], "No metadata returned after update"
  117. assert update_resp["id"], "No metadata returned after update"
  118. # Retrieve the conversation with the new branch
  119. updated_conv = client.conversations.retrieve(id=test_conversation)[
  120. "results"
  121. ]
  122. assert updated_conv, "No conversation returned after update"
  123. assert (
  124. updated_conv[0]["message"]["content"] == "Updated content"
  125. ), "Message content not updated"
  126. # found_updated = any(msg["id"] == new_message_id and msg["message"]["content"] == "Updated content" for msg in updated_conv)
  127. # assert found_updated, "Updated message not found in the new branch"
  128. def test_update_non_existent_message(client, test_conversation):
  129. fake_msg_id = str(uuid.uuid4())
  130. with pytest.raises(R2RException) as exc_info:
  131. client.conversations.update_message(
  132. id=test_conversation, message_id=fake_msg_id, content="Should fail"
  133. )
  134. assert (
  135. exc_info.value.status_code == 404
  136. ), "Wrong error code for updating non-existent message"
  137. def test_add_message_with_empty_content(client, test_conversation):
  138. with pytest.raises(R2RException) as exc_info:
  139. client.conversations.add_message(
  140. id=test_conversation,
  141. content="", # empty content
  142. role="user",
  143. )
  144. # Check for 400 or a relevant error code depending on server validation
  145. assert (
  146. exc_info.value.status_code == 400
  147. ), "Wrong error code or no error for empty content message"
  148. def test_add_message_invalid_role(client, test_conversation):
  149. with pytest.raises(R2RException) as exc_info:
  150. client.conversations.add_message(
  151. id=test_conversation,
  152. content="Hello",
  153. role="invalid_role",
  154. )
  155. assert (
  156. exc_info.value.status_code == 400
  157. ), "Wrong error code or no error for invalid role"
  158. def test_add_message_to_deleted_conversation(client):
  159. # Create a conversation and delete it
  160. conv_id = client.conversations.create()["results"]["id"]
  161. client.conversations.delete(id=conv_id)
  162. # Try adding a message to the deleted conversation
  163. with pytest.raises(R2RException) as exc_info:
  164. client.conversations.add_message(
  165. id=conv_id,
  166. content="Should fail",
  167. role="user",
  168. )
  169. assert (
  170. exc_info.value.status_code == 404
  171. ), "Wrong error code for adding message to deleted conversation"
  172. def test_update_message_with_additional_metadata(client, test_conversation):
  173. # Add a message with initial metadata
  174. msg_resp = client.conversations.add_message(
  175. id=test_conversation,
  176. content="Initial content",
  177. role="user",
  178. metadata={"initial_key": "initial_value"},
  179. )["results"]
  180. original_msg_id = msg_resp["id"]
  181. # Update the message with new content and additional metadata
  182. update_resp = client.conversations.update_message(
  183. id=test_conversation,
  184. message_id=original_msg_id,
  185. content="Updated content",
  186. metadata={"new_key": "new_value"},
  187. )["results"]
  188. # Retrieve the conversation from the new branch
  189. updated_conv = client.conversations.retrieve(id=test_conversation)[
  190. "results"
  191. ]
  192. # Find the updated message
  193. updated_message = next(
  194. (msg for msg in updated_conv if msg["id"] == original_msg_id), None
  195. )
  196. assert (
  197. updated_message is not None
  198. ), "Updated message not found in conversation"
  199. # Check that metadata includes old keys, new keys, and 'edited': True
  200. msg_metadata = updated_message["metadata"]
  201. assert (
  202. msg_metadata.get("initial_key") == "initial_value"
  203. ), "Old metadata not preserved"
  204. assert msg_metadata.get("new_key") == "new_value", "New metadata not added"
  205. assert (
  206. msg_metadata.get("edited") is True
  207. ), "'edited' flag not set in metadata"
  208. assert (
  209. updated_message["message"]["content"] == "Updated content"
  210. ), "Message content not updated"