Persist chat history
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
defmodule MusicLibrary.ChatsTest do
|
||||
use MusicLibrary.DataCase
|
||||
|
||||
alias MusicLibrary.Chats
|
||||
alias MusicLibrary.Chats.Chat
|
||||
|
||||
@musicbrainz_id Ecto.UUID.generate()
|
||||
|
||||
defp create_chat(_context) do
|
||||
{:ok, chat} =
|
||||
Chats.create_chat_with_message(
|
||||
%{entity: :record, musicbrainz_id: @musicbrainz_id},
|
||||
%{role: "user", content: "Tell me about this album"}
|
||||
)
|
||||
|
||||
%{chat: chat}
|
||||
end
|
||||
|
||||
describe "list_chats/2" do
|
||||
setup [:create_chat]
|
||||
|
||||
test "returns empty list when no chats exist" do
|
||||
assert Chats.list_chats(:record, Ecto.UUID.generate()) == []
|
||||
end
|
||||
|
||||
test "returns chats for entity with message count", %{chat: chat} do
|
||||
chats = Chats.list_chats(:record, @musicbrainz_id)
|
||||
|
||||
assert [listed_chat] = chats
|
||||
assert listed_chat.id == chat.id
|
||||
assert listed_chat.message_count == 1
|
||||
end
|
||||
|
||||
test "does not return chats for different entity", %{chat: _chat} do
|
||||
assert Chats.list_chats(:artist, @musicbrainz_id) == []
|
||||
end
|
||||
|
||||
test "orders by updated_at desc", %{chat: first_chat} do
|
||||
{:ok, second_chat} =
|
||||
Chats.create_chat_with_message(
|
||||
%{entity: :record, musicbrainz_id: @musicbrainz_id},
|
||||
%{role: "user", content: "Another question"}
|
||||
)
|
||||
|
||||
chats = Chats.list_chats(:record, @musicbrainz_id)
|
||||
assert [%{id: id1}, %{id: id2}] = chats
|
||||
assert id1 == second_chat.id
|
||||
assert id2 == first_chat.id
|
||||
end
|
||||
end
|
||||
|
||||
describe "get_chat!/1" do
|
||||
setup [:create_chat]
|
||||
|
||||
test "returns chat with preloaded messages", %{chat: chat} do
|
||||
found = Chats.get_chat!(chat.id)
|
||||
|
||||
assert found.id == chat.id
|
||||
assert found.entity == :record
|
||||
assert [message] = found.messages
|
||||
assert message.role == "user"
|
||||
assert message.content == "Tell me about this album"
|
||||
end
|
||||
|
||||
test "raises for nonexistent chat" do
|
||||
assert_raise Ecto.NoResultsError, fn ->
|
||||
Chats.get_chat!(Ecto.UUID.generate())
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "create_chat_with_message/2" do
|
||||
test "creates chat with first message" do
|
||||
assert {:ok, chat} =
|
||||
Chats.create_chat_with_message(
|
||||
%{entity: :artist, musicbrainz_id: @musicbrainz_id},
|
||||
%{role: "user", content: "Who is this artist?"}
|
||||
)
|
||||
|
||||
assert chat.entity == :artist
|
||||
assert chat.musicbrainz_id == @musicbrainz_id
|
||||
assert chat.topic == "Who is this artist?"
|
||||
assert [message] = chat.messages
|
||||
assert message.role == "user"
|
||||
assert message.position == 0
|
||||
end
|
||||
|
||||
test "truncates topic to 80 characters" do
|
||||
long_message = String.duplicate("a", 200)
|
||||
|
||||
assert {:ok, chat} =
|
||||
Chats.create_chat_with_message(
|
||||
%{entity: :record, musicbrainz_id: @musicbrainz_id},
|
||||
%{role: "user", content: long_message}
|
||||
)
|
||||
|
||||
assert String.length(chat.topic) == 80
|
||||
end
|
||||
|
||||
test "returns error for invalid chat attrs" do
|
||||
assert {:error, _changeset} =
|
||||
Chats.create_chat_with_message(
|
||||
%{},
|
||||
%{role: "user", content: "Hello"}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe "add_message/2" do
|
||||
setup [:create_chat]
|
||||
|
||||
test "adds message with auto-computed position", %{chat: chat} do
|
||||
assert {:ok, message} =
|
||||
Chats.add_message(chat, %{role: "assistant", content: "Here's what I know..."})
|
||||
|
||||
assert message.role == "assistant"
|
||||
assert message.position == 1
|
||||
assert message.chat_id == chat.id
|
||||
end
|
||||
|
||||
test "increments position for each message", %{chat: chat} do
|
||||
{:ok, _} = Chats.add_message(chat, %{role: "assistant", content: "Response 1"})
|
||||
{:ok, msg} = Chats.add_message(chat, %{role: "user", content: "Follow up"})
|
||||
|
||||
assert msg.position == 2
|
||||
end
|
||||
|
||||
test "touches chat updated_at", %{chat: chat} do
|
||||
# Force a different timestamp by manually setting the original earlier
|
||||
Repo.update_all(
|
||||
from(c in Chat, where: c.id == ^chat.id),
|
||||
set: [updated_at: ~U[2025-01-01 00:00:00Z]]
|
||||
)
|
||||
|
||||
{:ok, _} = Chats.add_message(chat, %{role: "assistant", content: "Response"})
|
||||
|
||||
updated_chat = Chats.get_chat!(chat.id)
|
||||
assert DateTime.compare(updated_chat.updated_at, ~U[2025-01-01 00:00:00Z]) == :gt
|
||||
end
|
||||
end
|
||||
|
||||
describe "delete_chat/1" do
|
||||
setup [:create_chat]
|
||||
|
||||
test "deletes chat and its messages", %{chat: chat} do
|
||||
assert {:ok, _} = Chats.delete_chat(chat)
|
||||
|
||||
assert_raise Ecto.NoResultsError, fn ->
|
||||
Chats.get_chat!(chat.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user