1package sqlite
2
3import (
4 "context"
5 "errors"
6 "os"
7 "path/filepath"
8 "sync"
9 "testing"
10 "time"
11
12 "github.com/stretchr/testify/require"
13)
14
15func TestRetryPragmaHonorsCancellation(t *testing.T) {
16 ctx, cancel := context.WithCancel(context.Background())
17 cancel()
18 start := time.Now()
19 err := retryPragma(ctx, func() error { return errors.New("database is locked") })
20 require.ErrorIs(t, err, context.Canceled)
21 require.Less(t, time.Since(start), lockRetryInterval)
22}
23
24func TestLockDatabaseStartupTruncatesStaleContents(t *testing.T) {
25 path := filepath.Join(t.TempDir(), "startup.lock")
26 require.NoError(t, os.WriteFile(path, []byte("stale"), 0o600))
27 lock, err := lockDatabaseStartup(context.Background(), path)
28 require.NoError(t, err)
29 require.NoError(t, lock.Close())
30 info, err := os.Stat(path)
31 require.NoError(t, err)
32 require.Zero(t, info.Size())
33}
34
35func TestNewConnectionUsesWAL(t *testing.T) {
36 db, err := NewConnection(context.Background(), filepath.Join(t.TempDir(), "wal.db"))
37 require.NoError(t, err)
38 defer db.Close()
39 var mode string
40 require.NoError(t, db.QueryRow("PRAGMA journal_mode").Scan(&mode))
41 require.Equal(t, "wal", mode)
42}
43
44func TestNewConnectionConcurrentFirstOpen(t *testing.T) {
45 dbPath := filepath.Join(t.TempDir(), "shared.db")
46 const openers = 8
47 var wg sync.WaitGroup
48 openErrors := make(chan error, openers)
49 for range openers {
50 wg.Add(1)
51 go func() {
52 defer wg.Done()
53 db, err := NewConnection(context.Background(), dbPath)
54 if err == nil {
55 err = db.Close()
56 }
57 openErrors <- err
58 }()
59 }
60 wg.Wait()
61 close(openErrors)
62 for err := range openErrors {
63 require.NoError(t, err)
64 }
65}