veza/veza-backend-api/internal/services/room_service_test.go
2025-12-03 20:29:37 +01:00

263 lines
8.2 KiB
Go

package services
import (
"context"
"fmt"
"testing"
"time"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"go.uber.org/zap"
"gorm.io/gorm"
"veza-backend-api/internal/models"
"veza-backend-api/internal/repositories"
)
type MockRoomRepository struct {
rooms map[uuid.UUID]*models.Room
members map[uuid.UUID][]*models.RoomMember
}
func NewMockRoomRepository() *MockRoomRepository {
return &MockRoomRepository{
rooms: make(map[uuid.UUID]*models.Room),
members: make(map[uuid.UUID][]*models.RoomMember),
}
}
func (m *MockRoomRepository) Create(ctx context.Context, room *models.Room) error {
room.ID = uuid.New() // Generate new UUID
room.CreatedAt = time.Now()
room.UpdatedAt = time.Now()
m.rooms[room.ID] = room
return nil
}
func (m *MockRoomRepository) GetByID(ctx context.Context, id uuid.UUID) (*models.Room, error) {
room, ok := m.rooms[id]
if !ok {
return nil, gorm.ErrRecordNotFound
}
return room, nil
}
func (m *MockRoomRepository) GetByUserID(ctx context.Context, userID uuid.UUID) ([]*models.Room, error) {
var userRooms []*models.Room
for _, room := range m.rooms {
// In a real scenario, this would query room_members.
// For mock, we'll assume a direct match for now.
// This mock is simplified and doesn't fully simulate the join logic of a real repo.
// We'll rely on the AddMember mock below to add members correctly.
if _, ok := m.members[room.ID]; ok {
for _, member := range m.members[room.ID] {
if member.UserID == userID {
userRooms = append(userRooms, room)
break
}
}
}
}
return userRooms, nil
}
func (m *MockRoomRepository) AddMember(ctx context.Context, member *models.RoomMember) error {
// If the member ID is not set, generate it
if member.ID == uuid.Nil {
// This is a mock internal ID, actual GORM might auto-increment
member.ID = int64(len(m.members[member.RoomID]) + 1)
}
m.members[member.RoomID] = append(m.members[member.RoomID], member)
return nil
}
func (m *MockRoomRepository) GetMembersByRoomID(ctx context.Context, roomID uuid.UUID) ([]*models.RoomMember, error) {
return m.members[roomID], nil
}
func (m *MockRoomRepository) Update(ctx context.Context, room *models.Room) error {
panic("not implemented")
}
func (m *MockRoomRepository) Delete(ctx context.Context, id uuid.UUID) error {
panic("not implemented")
}
func (m *MockRoomRepository) RemoveMember(ctx context.Context, roomID uuid.UUID, userID uuid.UUID) error {
panic("not implemented")
}
type MockChatMessageRepository struct {
messages []models.ChatMessage
}
func NewMockChatMessageRepository() *MockChatMessageRepository {
return &MockChatMessageRepository{
messages: make([]models.ChatMessage, 0),
}
}
func (m *MockChatMessageRepository) GetConversationMessages(ctx context.Context, conversationID uuid.UUID, limit, offset int) ([]models.ChatMessage, error) {
var filtered []models.ChatMessage
for _, msg := range m.messages {
if msg.ConversationID == conversationID {
filtered = append(filtered, msg)
}
}
// Simple reverse order and limit/offset for mock
// Order by CreatedAt DESC
if len(filtered) > 1 {
for i := 0; i < len(filtered)/2; i++ {
filtered[i], filtered[len(filtered)-1-i] = filtered[len(filtered)-1-i], filtered[i]
}
}
start := offset
end := offset + limit
if start > len(filtered) {
start = len(filtered)
}
if end > len(filtered) {
end = len(filtered)
}
return filtered[start:end], nil
}
func TestRoomService_CreateRoom(t *testing.T) {
logger := zap.NewNop()
roomRepo := NewMockRoomRepository()
messageRepo := NewMockChatMessageRepository() // Not used in this test
service := NewRoomService(roomRepo, messageRepo, logger)
userID := int64(1)
req := CreateRoomRequest{
Name: "Test Room",
Type: "public",
IsPrivate: false,
}
room, err := service.CreateRoom(context.Background(), userID, req)
assert.NoError(t, err)
assert.NotNil(t, room)
assert.Equal(t, req.Name, room.Name)
assert.Contains(t, room.Participants, userID)
// Verify room created in repo
createdRoom, _ := roomRepo.GetByID(context.Background(), room.ID)
assert.NotNil(t, createdRoom)
assert.Equal(t, room.ID, createdRoom.ID) // Check UUID match
}
func TestRoomService_GetUserRooms(t *testing.T) {
logger := zap.NewNop()
roomRepo := NewMockRoomRepository()
messageRepo := NewMockChatMessageRepository()
service := NewRoomService(roomRepo, messageRepo, logger)
userID := int64(1)
userID2 := int64(2)
roomReq1 := CreateRoomRequest{Name: "Room 1", Type: "public", IsPrivate: false}
roomReq2 := CreateRoomRequest{Name: "Room 2", Type: "private", IsPrivate: true}
room1, _ := service.CreateRoom(context.Background(), userID, roomReq1)
room2, _ := service.CreateRoom(context.Background(), userID2, roomReq2)
// User 1 joins room 2
err := service.AddMember(context.Background(), room2.ID, userID)
assert.NoError(t, err)
rooms, err := service.GetUserRooms(context.Background(), userID)
assert.NoError(t, err)
assert.Len(t, rooms, 2) // Should contain Room 1 and Room 2
// Check content
var foundRoom1, foundRoom2 bool
for _, r := range rooms {
if r.ID == room1.ID {
foundRoom1 = true
}
if r.ID == room2.ID {
foundRoom2 = true
}
}
assert.True(t, foundRoom1)
assert.True(t, foundRoom2)
}
func TestRoomService_GetRoomHistory(t *testing.T) {
logger := zap.NewNop()
roomRepo := NewMockRoomRepository()
mockMessageRepo := NewMockChatMessageRepository()
service := NewRoomService(roomRepo, mockMessageRepo, logger)
// Create a dummy conversation ID
convID := uuid.New()
// Create a room first to simulate existence
roomReq := CreateRoomRequest{Name: "History Room", Type: "public", IsPrivate: false}
_, _ = service.CreateRoom(context.Background(), int64(1), roomReq)
// Add mock messages
mockMessageRepo.messages = []models.ChatMessage{
{ID: uuid.New(), ConversationID: convID, SenderID: uuid.New(), Content: "Hello 1", CreatedAt: time.Now().Add(-2 * time.Minute)},
{ID: uuid.New(), ConversationID: convID, SenderID: uuid.New(), Content: "Hello 2", CreatedAt: time.Now().Add(-1 * time.Minute)},
{ID: uuid.New(), ConversationID: convID, SenderID: uuid.New(), Content: "Hello 3", CreatedAt: time.Now()},
}
history, err := service.GetRoomHistory(context.Background(), convID, 10, 0)
assert.NoError(t, err)
assert.Len(t, history, 3)
assert.Equal(t, "Hello 3", history[0].Content) // Should be ordered by created_at DESC
history, err = service.GetRoomHistory(context.Background(), convID, 1, 1) // limit 1, offset 1
assert.NoError(t, err)
assert.Len(t, history, 1)
assert.Equal(t, "Hello 2", history[0].Content)
}
func TestRoomService_GetRoom_Success(t *testing.T) {
logger := zap.NewNop()
roomRepo := NewMockRoomRepository()
messageRepo := NewMockChatMessageRepository()
service := NewRoomService(roomRepo, messageRepo, logger)
userID := int64(1)
req := CreateRoomRequest{Name: "Single Room", Type: "public", IsPrivate: false}
createdRoom, _ := service.CreateRoom(context.Background(), userID, req)
retrievedRoom, err := service.GetRoom(context.Background(), createdRoom.ID)
assert.NoError(t, err)
assert.NotNil(t, retrievedRoom)
assert.Equal(t, createdRoom.ID, retrievedRoom.ID)
assert.Equal(t, "Single Room", retrievedRoom.Name)
}
func TestRoomService_GetRoom_NotFound(t *testing.T) {
logger := zap.NewNop()
roomRepo := NewMockRoomRepository()
messageRepo := NewMockChatMessageRepository()
service := NewRoomService(roomRepo, messageRepo, logger)
_, err := service.GetRoom(context.Background(), uuid.New())
assert.Error(t, err)
assert.Equal(t, "playlist not found", err.Error()) // Gorm returns playlist not found here
}
func TestRoomService_AddMember_Success(t *testing.T) {
logger := zap.NewNop()
roomRepo := NewMockRoomRepository()
messageRepo := NewMockChatMessageRepository()
service := NewRoomService(roomRepo, messageRepo, logger)
userID := int64(1)
roomReq := CreateRoomRequest{Name: "Member Room", Type: "public", IsPrivate: false}
room, _ := service.CreateRoom(context.Background(), userID, roomReq)
newMemberID := int64(2)
err := service.AddMember(context.Background(), room.ID, newMemberID)
assert.NoError(t, err)
members, _ := roomRepo.GetMembersByRoomID(context.Background(), room.ID)
assert.Len(t, members, 2) // Original creator + new member
assert.Equal(t, newMemberID, members[1].UserID)
}