fix: prevent FK constraint errors on concurrent issue creation (GH#956)
Root cause: CreateIssue used INSERT OR IGNORE which could silently skip the insert (e.g., on duplicate ID from hash collision), then fail with FOREIGN KEY constraint error when trying to record the creation event. Fix: Add insertIssueStrict() that uses plain INSERT (fails on duplicates) and use it for CreateIssue in both queries.go and transaction.go. The existing insertIssue() with INSERT OR IGNORE is preserved for import scenarios where duplicates are expected. Added test TestCreateIssueDuplicateID to verify duplicate IDs are properly rejected instead of silently ignored. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -139,6 +140,48 @@ func TestCreateIssueValidation(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestCreateIssueDuplicateID verifies that CreateIssue properly rejects duplicate IDs.
|
||||
// GH#956: This test ensures that insertIssueStrict (used by CreateIssue) properly fails
|
||||
// on duplicate IDs instead of silently ignoring them (which would cause FK constraint
|
||||
// errors when recording the creation event).
|
||||
func TestCreateIssueDuplicateID(t *testing.T) {
|
||||
store, cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Create first issue
|
||||
issue1 := &types.Issue{
|
||||
Title: "First issue",
|
||||
Status: types.StatusOpen,
|
||||
Priority: 2,
|
||||
IssueType: types.TypeTask,
|
||||
}
|
||||
err := store.CreateIssue(ctx, issue1, "test-user")
|
||||
if err != nil {
|
||||
t.Fatalf("CreateIssue failed for first issue: %v", err)
|
||||
}
|
||||
|
||||
// Try to create second issue with same explicit ID - should fail
|
||||
issue2 := &types.Issue{
|
||||
ID: issue1.ID, // Use same ID as first issue
|
||||
Title: "Second issue with duplicate ID",
|
||||
Status: types.StatusOpen,
|
||||
Priority: 2,
|
||||
IssueType: types.TypeTask,
|
||||
}
|
||||
err = store.CreateIssue(ctx, issue2, "test-user")
|
||||
if err == nil {
|
||||
t.Error("CreateIssue should have failed for duplicate ID, but succeeded")
|
||||
}
|
||||
|
||||
// Verify the error mentions constraint or duplicate
|
||||
errStr := err.Error()
|
||||
if !strings.Contains(errStr, "UNIQUE constraint") && !strings.Contains(errStr, "already exists") {
|
||||
t.Errorf("Expected error to mention constraint or duplicate, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetIssue(t *testing.T) {
|
||||
store, cleanup := setupTestDB(t)
|
||||
defer cleanup()
|
||||
|
||||
Reference in New Issue
Block a user