test: improve coverage for importer and sqlite utils
- Fix TestImportIssues_Update by adding timestamps to test issue - Add comprehensive tests for sqlite utility functions (IsUniqueConstraintError, QueryContext, BeginTx, ExecInTransaction) - Coverage improvements: sqlite util.go 0% -> 95%, sqlite package 56.4% -> 57.1% Amp-Thread-ID: https://ampcode.com/threads/T-17e6a3e4-f881-4f53-b670-bdd796d58f68 Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
@@ -620,7 +620,7 @@ func TestImportIssues_Update(t *testing.T) {
|
||||
t.Fatalf("Failed to create initial issue: %v", err)
|
||||
}
|
||||
|
||||
// Import updated version
|
||||
// Import updated version with newer timestamp
|
||||
issue2 := &types.Issue{
|
||||
ID: "test-abc123",
|
||||
Title: "Updated Title",
|
||||
@@ -628,7 +628,10 @@ func TestImportIssues_Update(t *testing.T) {
|
||||
Status: types.StatusInProgress,
|
||||
Priority: 2,
|
||||
IssueType: types.TypeTask,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now().Add(time.Hour), // Newer than issue1
|
||||
}
|
||||
issue2.ContentHash = issue2.ComputeContentHash()
|
||||
|
||||
result, err := ImportIssues(ctx, tmpDB, store, []*types.Issue{issue2}, Options{})
|
||||
if err != nil {
|
||||
|
||||
162
internal/storage/sqlite/util_test.go
Normal file
162
internal/storage/sqlite/util_test.go
Normal file
@@ -0,0 +1,162 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestIsUniqueConstraintError(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
err error
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "nil error",
|
||||
err: nil,
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "UNIQUE constraint error",
|
||||
err: errors.New("UNIQUE constraint failed: issues.id"),
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "unique constraint lowercase",
|
||||
err: errors.New("unique constraint failed: issues.id"),
|
||||
expected: false, // SQLite uses uppercase "UNIQUE"
|
||||
},
|
||||
{
|
||||
name: "other error",
|
||||
err: errors.New("some other database error"),
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "empty error message",
|
||||
err: errors.New(""),
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := IsUniqueConstraintError(tt.err)
|
||||
if result != tt.expected {
|
||||
t.Errorf("IsUniqueConstraintError(%v) = %v, want %v", tt.err, result, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecInTransaction(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
store := newTestStore(t, t.TempDir()+"/test.db")
|
||||
defer store.Close()
|
||||
|
||||
t.Run("successful transaction", func(t *testing.T) {
|
||||
err := store.ExecInTransaction(ctx, func(tx *sql.Tx) error {
|
||||
_, err := tx.ExecContext(ctx, "INSERT INTO config (key, value) VALUES (?, ?)", "test_key", "test_value")
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("Transaction failed: %v", err)
|
||||
}
|
||||
|
||||
// Verify the data was committed
|
||||
var value string
|
||||
err = store.db.QueryRowContext(ctx, "SELECT value FROM config WHERE key = ?", "test_key").Scan(&value)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to query inserted value: %v", err)
|
||||
}
|
||||
if value != "test_value" {
|
||||
t.Errorf("Expected value 'test_value', got '%s'", value)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("failed transaction rolls back", func(t *testing.T) {
|
||||
expectedErr := errors.New("intentional error")
|
||||
err := store.ExecInTransaction(ctx, func(tx *sql.Tx) error {
|
||||
_, err := tx.ExecContext(ctx, "INSERT INTO config (key, value) VALUES (?, ?)", "rollback_key", "rollback_value")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return expectedErr
|
||||
})
|
||||
if err != expectedErr {
|
||||
t.Errorf("Expected error %v, got %v", expectedErr, err)
|
||||
}
|
||||
|
||||
// Verify the data was not committed
|
||||
var value string
|
||||
err = store.db.QueryRowContext(ctx, "SELECT value FROM config WHERE key = ?", "rollback_key").Scan(&value)
|
||||
if err != sql.ErrNoRows {
|
||||
t.Errorf("Expected no rows, but got value: %s (err: %v)", value, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestBeginTx(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
store := newTestStore(t, t.TempDir()+"/test.db")
|
||||
defer store.Close()
|
||||
|
||||
tx, err := store.BeginTx(ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to begin transaction: %v", err)
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
// Verify transaction is active
|
||||
_, err = tx.ExecContext(ctx, "INSERT INTO config (key, value) VALUES (?, ?)", "tx_test", "value")
|
||||
if err != nil {
|
||||
t.Errorf("Failed to execute in transaction: %v", err)
|
||||
}
|
||||
|
||||
// Rollback and verify data not committed
|
||||
if err := tx.Rollback(); err != nil {
|
||||
t.Errorf("Failed to rollback: %v", err)
|
||||
}
|
||||
|
||||
var value string
|
||||
err = store.db.QueryRowContext(ctx, "SELECT value FROM config WHERE key = ?", "tx_test").Scan(&value)
|
||||
if err != sql.ErrNoRows {
|
||||
t.Errorf("Expected no rows after rollback, got: %s", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueryContext(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
store := newTestStore(t, t.TempDir()+"/test.db")
|
||||
defer store.Close()
|
||||
|
||||
// Insert test data
|
||||
_, err := store.db.ExecContext(ctx, "INSERT INTO config (key, value) VALUES (?, ?)", "query_test", "query_value")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to insert test data: %v", err)
|
||||
}
|
||||
|
||||
rows, err := store.QueryContext(ctx, "SELECT key, value FROM config WHERE key = ?", "query_test")
|
||||
if err != nil {
|
||||
t.Fatalf("QueryContext failed: %v", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
if !rows.Next() {
|
||||
t.Fatal("Expected at least one row")
|
||||
}
|
||||
|
||||
var key, value string
|
||||
if err := rows.Scan(&key, &value); err != nil {
|
||||
t.Errorf("Failed to scan row: %v", err)
|
||||
}
|
||||
|
||||
if key != "query_test" || value != "query_value" {
|
||||
t.Errorf("Expected (query_test, query_value), got (%s, %s)", key, value)
|
||||
}
|
||||
|
||||
if rows.Next() {
|
||||
t.Error("Expected only one row")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user