137 lines
6.7 KiB
Go
137 lines
6.7 KiB
Go
package projects
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/glebarez/sqlite"
|
|
"github.com/stretchr/testify/require"
|
|
"gorm.io/gorm"
|
|
"senlinai-agent/backend/internal/models"
|
|
)
|
|
|
|
func TestProjectTagsAreScopedToProject(t *testing.T) {
|
|
newTestDB(t)
|
|
service := NewService()
|
|
first, err := service.CreateProject(1, "Alpha", "")
|
|
require.NoError(t, err)
|
|
second, err := service.CreateProject(1, "Beta", "")
|
|
require.NoError(t, err)
|
|
|
|
_, err = service.CreateTag(first.ID, "重要")
|
|
require.NoError(t, err)
|
|
_, err = service.CreateTag(second.ID, "重要")
|
|
require.NoError(t, err)
|
|
|
|
firstTags, err := service.ListTags(first.ID)
|
|
require.NoError(t, err)
|
|
require.Len(t, firstTags, 1)
|
|
require.Equal(t, first.ID, firstTags[0].ProjectID)
|
|
}
|
|
|
|
func TestDashboardCountsOnlyRequestedProject(t *testing.T) {
|
|
database := newTestDB(t)
|
|
service := NewService()
|
|
first, err := service.CreateProject(1, "Alpha", "")
|
|
require.NoError(t, err)
|
|
second, err := service.CreateProject(1, "Beta", "")
|
|
require.NoError(t, err)
|
|
require.NoError(t, database.Create(&models.SenlinAgentInboxItem{ProjectID: first.ID, CreatedBy: 1, SourceType: "text", Status: "open"}).Error)
|
|
require.NoError(t, database.Create(&models.SenlinAgentInboxItem{ProjectID: second.ID, CreatedBy: 1, SourceType: "text", Status: "open"}).Error)
|
|
require.NoError(t, database.Create(&models.SenlinAgentTask{ProjectID: first.ID, CreatedBy: 1, Title: "A", Status: "open"}).Error)
|
|
require.NoError(t, database.Create(&models.SenlinAgentTask{ProjectID: second.ID, CreatedBy: 1, Title: "B", Status: "open"}).Error)
|
|
|
|
dashboard, err := service.Dashboard(1, first.ID)
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, int64(1), dashboard.PendingInboxCount)
|
|
require.Equal(t, int64(1), dashboard.OpenTaskCount)
|
|
}
|
|
|
|
func TestDashboardRejectsProjectOwnedByAnotherUser(t *testing.T) {
|
|
newTestDB(t)
|
|
service := NewService()
|
|
project, err := service.CreateProject(2, "Beta", "")
|
|
require.NoError(t, err)
|
|
|
|
_, err = service.Dashboard(1, project.ID)
|
|
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func TestWorkspaceMatchesFrontendContract(t *testing.T) {
|
|
database := newTestDB(t)
|
|
service := NewService()
|
|
require.NoError(t, database.Create(&models.SenlinAgentUser{Email: "david@example.com", DisplayName: "David", PasswordHash: "hash"}).Error)
|
|
project, err := service.CreateProject(1, "Project A1", "Client strategy workspace")
|
|
require.NoError(t, err)
|
|
other, err := service.CreateProject(1, "Project A2", "")
|
|
require.NoError(t, err)
|
|
nextRun := time.Date(2026, 7, 20, 9, 0, 0, 0, time.UTC)
|
|
|
|
require.NoError(t, database.Create(&models.SenlinAgentTag{ProjectID: project.ID, Name: "UI"}).Error)
|
|
require.NoError(t, database.Create(&models.SenlinAgentTag{ProjectID: project.ID, Name: "knowledge"}).Error)
|
|
require.NoError(t, database.Create(&models.SenlinAgentInboxItem{ProjectID: project.ID, CreatedBy: 1, SourceType: "Manual", Title: "Collect notes", Body: "Turn pasted research into tasks.", Status: "open"}).Error)
|
|
require.NoError(t, database.Create(&models.SenlinAgentInboxItem{ProjectID: other.ID, CreatedBy: 1, SourceType: "Manual", Title: "Other notes", Body: "Hidden", Status: "open"}).Error)
|
|
require.NoError(t, database.Create(&models.SenlinAgentTask{ProjectID: project.ID, CreatedBy: 1, Title: "Confirm IA", Description: "Review channel layout.", Status: "open", DueAt: &nextRun}).Error)
|
|
require.NoError(t, database.Create(&models.SenlinAgentTask{ProjectID: project.ID, CreatedBy: 1, Title: "Archive notes", Description: "Move outdated notes.", Status: "done"}).Error)
|
|
require.NoError(t, database.Create(&models.SenlinAgentAISession{ProjectID: project.ID, CreatedBy: 1, Title: "UI prototype critique", Context: "Discuss channel behavior."}).Error)
|
|
require.NoError(t, database.Create(&models.SenlinAgentNote{ProjectID: project.ID, CreatedBy: 1, Title: "Workbench principles", Markdown: "# Notes"}).Error)
|
|
require.NoError(t, database.Create(&models.SenlinAgentSource{ProjectID: project.ID, CreatedBy: 1, Kind: "link", Title: "Reference board", URL: "https://example.com"}).Error)
|
|
require.NoError(t, database.Create(&models.SenlinAgentProjectChannel{ProjectID: project.ID, Title: "Roadmap Board", Icon: "link", URL: "https://example.com/roadmap-a1", SortOrder: 7}).Error)
|
|
require.NoError(t, database.Create(&models.SenlinAgentProjectChannel{ProjectID: other.ID, Title: "Other Board", Icon: "link", URL: "https://example.com/other", SortOrder: 7}).Error)
|
|
require.NoError(t, database.Create(&models.SenlinAgentCronPlan{ProjectID: project.ID, CreatedBy: 1, Title: "Weekly inbox review reminder", Schedule: "0 9 * * 1", NextRunAt: &nextRun, Enabled: true, LastResult: "Not run yet"}).Error)
|
|
require.NoError(t, database.Create(&models.SenlinAgentCronPlan{ProjectID: other.ID, CreatedBy: 1, Title: "Other cron", Schedule: "0 9 * * 2", Enabled: true}).Error)
|
|
|
|
workspace, err := service.Workspace(1, project.ID)
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, project.ID, workspace.Project.ID)
|
|
require.Equal(t, "Project A1", workspace.Project.Name)
|
|
require.Equal(t, "A1", workspace.Project.Initials)
|
|
require.Equal(t, int64(1), workspace.Project.UnreadCount)
|
|
require.Equal(t, []string{"all", "UI", "knowledge"}, workspace.Tags)
|
|
require.Len(t, workspace.Channels, 7)
|
|
require.Equal(t, "overview", workspace.Channels[0].Type)
|
|
require.Equal(t, "inbox", workspace.Channels[1].Type)
|
|
require.Equal(t, int64(1), *workspace.Channels[1].Count)
|
|
require.Equal(t, "custom_link", workspace.Channels[6].Type)
|
|
require.Equal(t, "Roadmap Board", workspace.Channels[6].Title)
|
|
require.Equal(t, "https://example.com/roadmap-a1", workspace.Channels[6].URL)
|
|
require.Len(t, workspace.Inbox, 1)
|
|
require.Equal(t, "Manual", workspace.Inbox[0].Source)
|
|
require.Equal(t, "Turn pasted research into tasks.", workspace.Inbox[0].Summary)
|
|
require.Len(t, workspace.Tasks, 2)
|
|
require.False(t, workspace.Tasks[0].Completed)
|
|
require.Equal(t, "David", workspace.Tasks[0].Owner)
|
|
require.Len(t, workspace.AISessions, 1)
|
|
require.Len(t, workspace.RecentSessions, 1)
|
|
require.Len(t, workspace.NotesSources, 2)
|
|
require.Equal(t, "note", workspace.NotesSources[0].Kind)
|
|
require.Equal(t, "link", workspace.NotesSources[1].Kind)
|
|
require.Len(t, workspace.CronPlans, 1)
|
|
require.True(t, workspace.CronPlans[0].Enabled)
|
|
require.Equal(t, "David", workspace.CronPlans[0].Owner)
|
|
}
|
|
|
|
func TestWorkspaceRejectsProjectOwnedByAnotherUser(t *testing.T) {
|
|
newTestDB(t)
|
|
service := NewService()
|
|
project, err := service.CreateProject(2, "Beta", "")
|
|
require.NoError(t, err)
|
|
|
|
_, err = service.Workspace(1, project.ID)
|
|
|
|
require.Error(t, err)
|
|
}
|
|
|
|
func newTestDB(t *testing.T) *gorm.DB {
|
|
t.Helper()
|
|
database, err := gorm.Open(sqlite.Open(fmt.Sprintf("file:%s?mode=memory&cache=shared", t.Name())), &gorm.Config{})
|
|
require.NoError(t, err)
|
|
require.NoError(t, models.AutoMigrate(database))
|
|
models.DBService = database
|
|
return database
|
|
}
|