Files
gochat/internal/repository/attachment_repo_test.go
T
2026-06-04 15:44:48 +08:00

199 lines
6.1 KiB
Go

package repository
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gorm.io/gorm"
"github.com/gochat/gochat/internal/model"
)
// createTestAttachment is a helper that creates and persists an Attachment.
func createTestAttachment(t *testing.T, db *gorm.DB, messageID, accountID uint, fileType, fileName string) *model.Attachment {
t.Helper()
att := &model.Attachment{
MessageID: messageID,
AccountID: accountID,
FileType: fileType,
FileName: fileName,
FileSize: 1024,
}
require.NoError(t, db.Create(att).Error)
return att
}
// setupAttachmentTest prepares the full dependency chain (account → inbox → contact → conversation → message)
// and returns the db, repo, and pre-created message for convenience.
func setupAttachmentTest(t *testing.T) (*gorm.DB, *AttachmentRepo, *model.Message) {
t.Helper()
db := setupTestDB(t, &model.Attachment{})
repo := NewAttachmentRepo(db)
account := &model.Account{Name: "AttTestOrg", Locale: "en", Active: true}
require.NoError(t, db.Create(account).Error)
inbox := &model.Inbox{AccountID: account.ID, Name: "AttTestInbox", ChannelType: "web_widget", ChannelID: 1}
require.NoError(t, db.Create(inbox).Error)
contact := &model.Contact{AccountID: account.ID, Name: "AttTestContact"}
require.NoError(t, db.Create(contact).Error)
conv := &model.Conversation{
AccountID: account.ID, InboxID: inbox.ID, ContactID: contact.ID,
Status: "open", ChannelType: "web_widget", Channel: "web_widget",
}
require.NoError(t, db.Create(conv).Error)
msg := createTestMessage(t, db, conv.ID, account.ID, inbox.ID, "Hello with attachment")
return db, repo, msg
}
// --- FindByID ---
func TestAttachmentRepo_FindByID_Success(t *testing.T) {
db, repo, msg := setupAttachmentTest(t)
att := createTestAttachment(t, db, msg.ID, msg.AccountID, "image", "photo.png")
found, err := repo.FindByID(context.Background(), att.ID)
assert.NoError(t, err)
assert.Equal(t, att.ID, found.ID)
assert.Equal(t, att.MessageID, found.MessageID)
assert.Equal(t, att.FileType, found.FileType)
assert.Equal(t, att.FileName, found.FileName)
}
func TestAttachmentRepo_FindByID_NotFound(t *testing.T) {
_, repo, _ := setupAttachmentTest(t)
found, err := repo.FindByID(context.Background(), 99999)
assert.Error(t, err)
assert.Nil(t, found)
}
// --- FindByMessage ---
func TestAttachmentRepo_FindByMessage_Multiple(t *testing.T) {
db, repo, msg := setupAttachmentTest(t)
att1 := createTestAttachment(t, db, msg.ID, msg.AccountID, "image", "photo.png")
att2 := createTestAttachment(t, db, msg.ID, msg.AccountID, "file", "doc.pdf")
attachments, err := repo.FindByMessage(context.Background(), msg.ID)
assert.NoError(t, err)
assert.Len(t, attachments, 2)
// Should be ordered by id ASC
assert.Equal(t, att1.ID, attachments[0].ID)
assert.Equal(t, att2.ID, attachments[1].ID)
}
func TestAttachmentRepo_FindByMessage_Empty(t *testing.T) {
_, repo, msg := setupAttachmentTest(t)
attachments, err := repo.FindByMessage(context.Background(), msg.ID)
assert.NoError(t, err)
assert.Len(t, attachments, 0)
}
// --- Create ---
func TestAttachmentRepo_Create_Success(t *testing.T) {
db, repo, msg := setupAttachmentTest(t)
att := &model.Attachment{
MessageID: msg.ID,
AccountID: msg.AccountID,
FileType: "video",
FileURL: "https://example.com/video.mp4",
ThumbURL: "https://example.com/thumb.jpg",
FileName: "video.mp4",
FileSize: 2048,
ExternalURL: "https://example.com/external",
}
err := repo.Create(context.Background(), att)
assert.NoError(t, err)
assert.NotZero(t, att.ID)
// Verify persisted
var fetched model.Attachment
require.NoError(t, db.First(&fetched, att.ID).Error)
assert.Equal(t, "video", fetched.FileType)
assert.Equal(t, "https://example.com/video.mp4", fetched.FileURL)
}
// --- Update ---
func TestAttachmentRepo_Update_Success(t *testing.T) {
db, repo, msg := setupAttachmentTest(t)
att := createTestAttachment(t, db, msg.ID, msg.AccountID, "image", "old.png")
att.FileName = "new.png"
att.FileSize = 4096
err := repo.Update(context.Background(), att)
assert.NoError(t, err)
// Verify updated
var fetched model.Attachment
require.NoError(t, db.First(&fetched, att.ID).Error)
assert.Equal(t, "new.png", fetched.FileName)
assert.Equal(t, 4096, fetched.FileSize)
}
// --- Delete ---
func TestAttachmentRepo_Delete_Success(t *testing.T) {
db, repo, msg := setupAttachmentTest(t)
att := createTestAttachment(t, db, msg.ID, msg.AccountID, "image", "photo.png")
err := repo.Delete(context.Background(), att.ID)
assert.NoError(t, err)
// Verify soft-deleted: normal query should not find it
var found model.Attachment
err = db.First(&found, att.ID).Error
assert.Error(t, err) // record not found after soft delete
// Verify unscoped query finds it with DeletedAt set
var softDeleted model.Attachment
err = db.Unscoped().First(&softDeleted, att.ID).Error
assert.NoError(t, err)
assert.NotNil(t, softDeleted.DeletedAt)
}
func TestAttachmentRepo_Delete_NotFound(t *testing.T) {
_, repo, _ := setupAttachmentTest(t)
// Deleting a non-existent ID should not error (GORM soft delete behaviour)
err := repo.Delete(context.Background(), 99999)
assert.NoError(t, err)
}
// --- DeleteByMessage ---
func TestAttachmentRepo_DeleteByMessage_Success(t *testing.T) {
db, repo, msg := setupAttachmentTest(t)
att1 := createTestAttachment(t, db, msg.ID, msg.AccountID, "image", "photo1.png")
att2 := createTestAttachment(t, db, msg.ID, msg.AccountID, "file", "doc.pdf")
err := repo.DeleteByMessage(context.Background(), msg.ID)
assert.NoError(t, err)
// Both attachments should be soft-deleted
var count int64
db.Model(&model.Attachment{}).Where("message_id = ?", msg.ID).Count(&count)
assert.Equal(t, int64(0), count)
// Unscoped: both should still exist
var allCount int64
db.Unscoped().Model(&model.Attachment{}).Where("message_id = ?", msg.ID).Count(&count)
allCount = count
assert.Equal(t, int64(2), allCount)
// Verify individual DeletedAt
var sd1, sd2 model.Attachment
require.NoError(t, db.Unscoped().First(&sd1, att1.ID).Error)
assert.NotNil(t, sd1.DeletedAt)
require.NoError(t, db.Unscoped().First(&sd2, att2.ID).Error)
assert.NotNil(t, sd2.DeletedAt)
}