Amp-Thread-ID: https://ampcode.com/threads/T-4358e6e4-28ea-4ed7-ba3f-3da39072e169 Co-authored-by: Amp <amp@ampcode.com>
361 lines
8.2 KiB
Go
361 lines
8.2 KiB
Go
package sqlite
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/steveyegge/beads/internal/types"
|
|
)
|
|
|
|
const testUserAlice = "alice"
|
|
|
|
func TestAddComment(t *testing.T) {
|
|
store, cleanup := setupTestDB(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
|
|
// Create an issue
|
|
issue := &types.Issue{
|
|
Title: "Test issue",
|
|
Status: types.StatusOpen,
|
|
Priority: 1,
|
|
IssueType: types.TypeTask,
|
|
}
|
|
err := store.CreateIssue(ctx, issue, "test-user")
|
|
if err != nil {
|
|
t.Fatalf("CreateIssue failed: %v", err)
|
|
}
|
|
|
|
// Add a comment
|
|
err = store.AddComment(ctx, issue.ID, testUserAlice, "This is a test comment")
|
|
if err != nil {
|
|
t.Fatalf("AddComment failed: %v", err)
|
|
}
|
|
|
|
// Get events to verify comment was added
|
|
events, err := store.GetEvents(ctx, issue.ID, 0)
|
|
if err != nil {
|
|
t.Fatalf("GetEvents failed: %v", err)
|
|
}
|
|
|
|
// Should have 2 events: created and commented
|
|
if len(events) < 2 {
|
|
t.Fatalf("Expected at least 2 events, got %d", len(events))
|
|
}
|
|
|
|
// Find the comment event (most recent should be first due to DESC order)
|
|
var commentEvent *types.Event
|
|
for _, event := range events {
|
|
if event.EventType == types.EventCommented {
|
|
commentEvent = event
|
|
break
|
|
}
|
|
}
|
|
|
|
if commentEvent == nil {
|
|
t.Fatal("Comment event not found")
|
|
}
|
|
|
|
if commentEvent.Actor != testUserAlice {
|
|
t.Errorf("Expected actor 'alice', got '%s'", commentEvent.Actor)
|
|
}
|
|
|
|
if commentEvent.Comment == nil || *commentEvent.Comment != "This is a test comment" {
|
|
t.Errorf("Expected comment 'This is a test comment', got %v", commentEvent.Comment)
|
|
}
|
|
}
|
|
|
|
func TestAddMultipleComments(t *testing.T) {
|
|
store, cleanup := setupTestDB(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
|
|
// Create an issue
|
|
issue := &types.Issue{
|
|
Title: "Test issue",
|
|
Status: types.StatusOpen,
|
|
Priority: 1,
|
|
IssueType: types.TypeTask,
|
|
}
|
|
err := store.CreateIssue(ctx, issue, "test-user")
|
|
if err != nil {
|
|
t.Fatalf("CreateIssue failed: %v", err)
|
|
}
|
|
|
|
// Add multiple comments
|
|
comments := []struct {
|
|
actor string
|
|
comment string
|
|
}{
|
|
{"alice", "First comment"},
|
|
{"bob", "Second comment"},
|
|
{"charlie", "Third comment"},
|
|
}
|
|
|
|
for _, c := range comments {
|
|
err = store.AddComment(ctx, issue.ID, c.actor, c.comment)
|
|
if err != nil {
|
|
t.Fatalf("AddComment failed: %v", err)
|
|
}
|
|
}
|
|
|
|
// Get events
|
|
events, err := store.GetEvents(ctx, issue.ID, 0)
|
|
if err != nil {
|
|
t.Fatalf("GetEvents failed: %v", err)
|
|
}
|
|
|
|
// Count comment events
|
|
commentCount := 0
|
|
var commentEvents []*types.Event
|
|
for _, event := range events {
|
|
if event.EventType == types.EventCommented {
|
|
commentCount++
|
|
commentEvents = append(commentEvents, event)
|
|
}
|
|
}
|
|
|
|
if commentCount != 3 {
|
|
t.Fatalf("Expected 3 comment events, got %d", commentCount)
|
|
}
|
|
|
|
// Verify we can find all three comments
|
|
foundComments := make(map[string]bool)
|
|
for _, event := range commentEvents {
|
|
if event.Comment != nil {
|
|
foundComments[*event.Comment] = true
|
|
}
|
|
}
|
|
|
|
expectedComments := []string{"First comment", "Second comment", "Third comment"}
|
|
for _, expected := range expectedComments {
|
|
if !foundComments[expected] {
|
|
t.Errorf("Expected to find comment '%s'", expected)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestGetEventsWithLimit(t *testing.T) {
|
|
store, cleanup := setupTestDB(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
|
|
// Create an issue
|
|
issue := &types.Issue{
|
|
Title: "Test issue",
|
|
Status: types.StatusOpen,
|
|
Priority: 1,
|
|
IssueType: types.TypeTask,
|
|
}
|
|
err := store.CreateIssue(ctx, issue, "test-user")
|
|
if err != nil {
|
|
t.Fatalf("CreateIssue failed: %v", err)
|
|
}
|
|
|
|
// Add 5 comments
|
|
for i := 0; i < 5; i++ {
|
|
err = store.AddComment(ctx, issue.ID, "alice", "Comment")
|
|
if err != nil {
|
|
t.Fatalf("AddComment failed: %v", err)
|
|
}
|
|
}
|
|
|
|
// Get events with limit
|
|
events, err := store.GetEvents(ctx, issue.ID, 3)
|
|
if err != nil {
|
|
t.Fatalf("GetEvents failed: %v", err)
|
|
}
|
|
|
|
if len(events) != 3 {
|
|
t.Errorf("Expected 3 events with limit, got %d", len(events))
|
|
}
|
|
}
|
|
|
|
func TestGetEventsEmpty(t *testing.T) {
|
|
store, cleanup := setupTestDB(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
|
|
// Get events for non-existent issue
|
|
events, err := store.GetEvents(ctx, "bd-999", 0)
|
|
if err != nil {
|
|
t.Fatalf("GetEvents failed: %v", err)
|
|
}
|
|
|
|
if len(events) != 0 {
|
|
t.Errorf("Expected 0 events for non-existent issue, got %d", len(events))
|
|
}
|
|
}
|
|
|
|
func TestAddCommentMarksDirty(t *testing.T) {
|
|
store, cleanup := setupTestDB(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
|
|
// Create an issue
|
|
issue := &types.Issue{
|
|
Title: "Test issue",
|
|
Status: types.StatusOpen,
|
|
Priority: 1,
|
|
IssueType: types.TypeTask,
|
|
}
|
|
err := store.CreateIssue(ctx, issue, "test-user")
|
|
if err != nil {
|
|
t.Fatalf("CreateIssue failed: %v", err)
|
|
}
|
|
|
|
// Clear dirty issues
|
|
err = store.ClearDirtyIssues(ctx)
|
|
if err != nil {
|
|
t.Fatalf("ClearDirtyIssues failed: %v", err)
|
|
}
|
|
|
|
// Add comment - should mark issue dirty
|
|
err = store.AddComment(ctx, issue.ID, "alice", "Test comment")
|
|
if err != nil {
|
|
t.Fatalf("AddComment failed: %v", err)
|
|
}
|
|
|
|
// Verify issue is dirty
|
|
dirtyIssues, err := store.GetDirtyIssues(ctx)
|
|
if err != nil {
|
|
t.Fatalf("GetDirtyIssues failed: %v", err)
|
|
}
|
|
|
|
if len(dirtyIssues) != 1 || dirtyIssues[0] != issue.ID {
|
|
t.Error("Expected issue to be marked dirty after adding comment")
|
|
}
|
|
}
|
|
|
|
func TestAddCommentUpdatesTimestamp(t *testing.T) {
|
|
store, cleanup := setupTestDB(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
|
|
// Create an issue
|
|
issue := &types.Issue{
|
|
Title: "Test issue",
|
|
Status: types.StatusOpen,
|
|
Priority: 1,
|
|
IssueType: types.TypeTask,
|
|
}
|
|
err := store.CreateIssue(ctx, issue, "test-user")
|
|
if err != nil {
|
|
t.Fatalf("CreateIssue failed: %v", err)
|
|
}
|
|
|
|
originalUpdatedAt := issue.UpdatedAt
|
|
|
|
// Add comment
|
|
err = store.AddComment(ctx, issue.ID, "alice", "Test comment")
|
|
if err != nil {
|
|
t.Fatalf("AddComment failed: %v", err)
|
|
}
|
|
|
|
// Get issue again and verify updated_at changed
|
|
updatedIssue, err := store.GetIssue(ctx, issue.ID)
|
|
if err != nil {
|
|
t.Fatalf("GetIssue failed: %v", err)
|
|
}
|
|
|
|
if !updatedIssue.UpdatedAt.After(originalUpdatedAt) {
|
|
t.Error("Expected updated_at to be updated after adding comment")
|
|
}
|
|
}
|
|
|
|
func TestEventTypesInHistory(t *testing.T) {
|
|
store, cleanup := setupTestDB(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
|
|
// Create an issue
|
|
issue := &types.Issue{
|
|
Title: "Test issue",
|
|
Status: types.StatusOpen,
|
|
Priority: 1,
|
|
IssueType: types.TypeTask,
|
|
}
|
|
err := store.CreateIssue(ctx, issue, "test-user")
|
|
if err != nil {
|
|
t.Fatalf("CreateIssue failed: %v", err)
|
|
}
|
|
|
|
// Perform various operations that create events
|
|
err = store.UpdateIssue(ctx, issue.ID, map[string]interface{}{
|
|
"priority": 2,
|
|
}, "test-user")
|
|
if err != nil {
|
|
t.Fatalf("UpdateIssue failed: %v", err)
|
|
}
|
|
|
|
err = store.AddComment(ctx, issue.ID, "alice", "A comment")
|
|
if err != nil {
|
|
t.Fatalf("AddComment failed: %v", err)
|
|
}
|
|
|
|
err = store.AddLabel(ctx, issue.ID, "bug", "test-user")
|
|
if err != nil {
|
|
t.Fatalf("AddLabel failed: %v", err)
|
|
}
|
|
|
|
err = store.CloseIssue(ctx, issue.ID, "Done", "test-user")
|
|
if err != nil {
|
|
t.Fatalf("CloseIssue failed: %v", err)
|
|
}
|
|
|
|
// Get events
|
|
events, err := store.GetEvents(ctx, issue.ID, 0)
|
|
if err != nil {
|
|
t.Fatalf("GetEvents failed: %v", err)
|
|
}
|
|
|
|
// Should have multiple event types
|
|
eventTypes := make(map[types.EventType]bool)
|
|
for _, event := range events {
|
|
eventTypes[event.EventType] = true
|
|
}
|
|
|
|
// Verify we have different event types
|
|
if !eventTypes[types.EventCreated] {
|
|
t.Error("Expected EventCreated in history")
|
|
}
|
|
if !eventTypes[types.EventUpdated] {
|
|
t.Error("Expected EventUpdated in history")
|
|
}
|
|
if !eventTypes[types.EventCommented] {
|
|
t.Error("Expected EventCommented in history")
|
|
}
|
|
if !eventTypes[types.EventLabelAdded] {
|
|
t.Error("Expected EventLabelAdded in history")
|
|
}
|
|
if !eventTypes[types.EventClosed] {
|
|
t.Error("Expected EventClosed in history")
|
|
}
|
|
}
|
|
|
|
func TestAddCommentNotFound(t *testing.T) {
|
|
store, cleanup := setupTestDB(t)
|
|
defer cleanup()
|
|
|
|
ctx := context.Background()
|
|
nonExistentID := "bd-999"
|
|
|
|
err := store.AddComment(ctx, nonExistentID, "alice", "This should fail cleanly")
|
|
if err == nil {
|
|
t.Fatal("Expected error, got nil")
|
|
}
|
|
|
|
expectedError := "issue bd-999 not found"
|
|
if !strings.Contains(err.Error(), expectedError) {
|
|
t.Errorf("Expected error to contain %q, got %q", expectedError, err.Error())
|
|
}
|
|
}
|