database_test.go (4169B)
1 package internal 2 3 import ( 4 "context" 5 "strings" 6 "testing" 7 ) 8 9 func TestMigrationsCRUDAndSearch(t *testing.T) { 10 t.Parallel() 11 ctx := context.Background() 12 dir := t.TempDir() 13 path := dir + "/test.db" 14 15 db, err := OpenAtPath(ctx, path) 16 if err != nil { 17 t.Fatalf("open db: %v", err) 18 } 19 defer db.Close() 20 21 // Create user 22 uid := int64(1) 23 _, err = db.sql.ExecContext(ctx, `INSERT INTO users(id, username, encrypted_password, api_token, created_at, updated_at) VALUES(1, 'tester', 'x', 'tok', strftime('%Y-%m-%dT%H:%M:%fZ','now'), strftime('%Y-%m-%dT%H:%M:%fZ','now'))`) 24 if err != nil { 25 t.Fatalf("insert user: %v", err) 26 } 27 // Create with archive content 28 b, err := db.CreateBookmarkWithArchive(ctx, uid, "http://example.local/1", "Example 1", nil, false, "The city of Durham has great food.") 29 if err != nil { 30 t.Fatalf("create with archive: %v", err) 31 } 32 if b.ID == 0 { 33 t.Fatalf("expected id > 0") 34 } 35 36 // Archive present 37 content, _, ok, err := db.GetArchive(ctx, b.ID) 38 if err != nil || !ok { 39 t.Fatalf("get archive: ok=%v err=%v", ok, err) 40 } 41 if !strings.Contains(strings.ToLower(content), "durham") { 42 t.Fatalf("expected archive to contain durham, got: %q", content) 43 } 44 45 // Search with excerpt 46 hits, err := db.SearchBookmarksWithExcerpt(ctx, uid, "durham", 10, 0) 47 if err != nil { 48 t.Fatalf("search: %v", err) 49 } 50 if len(hits) != 1 { 51 t.Fatalf("expected 1 hit, got %d", len(hits)) 52 } 53 if !hits[0].Excerpt.Valid || !strings.Contains(strings.ToLower(hits[0].Excerpt.String), "«durham»") { 54 t.Fatalf("expected excerpt with highlighted token, got: %q", hits[0].Excerpt.String) 55 } 56 57 // Delete and ensure gone from search 58 okDel, err := db.DeleteBookmark(ctx, b.ID) 59 if err != nil || !okDel { 60 t.Fatalf("delete: ok=%v err=%v", okDel, err) 61 } 62 hits, err = db.SearchBookmarksWithExcerpt(ctx, uid, "durham", 10, 0) 63 if err != nil { 64 t.Fatalf("search after delete: %v", err) 65 } 66 if len(hits) != 0 { 67 t.Fatalf("expected 0 hits after delete, got %d", len(hits)) 68 } 69 } 70 71 func TestUniqueURL(t *testing.T) { 72 t.Parallel() 73 ctx := context.Background() 74 dir := t.TempDir() 75 path := dir + "/uniq.db" 76 db, err := OpenAtPath(ctx, path) 77 if err != nil { 78 t.Fatalf("open db: %v", err) 79 } 80 defer db.Close() 81 82 // Create user 83 uid := int64(1) 84 _, err = db.sql.ExecContext(ctx, `INSERT INTO users(id, username, encrypted_password, api_token, created_at, updated_at) VALUES(1, 'tester', 'x', 'tok', strftime('%Y-%m-%dT%H:%M:%fZ','now'), strftime('%Y-%m-%dT%H:%M:%fZ','now'))`) 85 if err != nil { 86 t.Fatalf("insert user: %v", err) 87 } 88 if _, err := db.CreateBookmark(ctx, uid, "http://dupe.local", "One", nil); err != nil { 89 t.Fatalf("first create: %v", err) 90 } 91 if _, err := db.CreateBookmark(ctx, uid, "http://dupe.local", "Two", nil); err == nil { 92 t.Fatalf("expected unique constraint error, got nil") 93 } 94 } 95 96 func TestFTSIndexUpdatesOnArchive(t *testing.T) { 97 t.Parallel() 98 ctx := context.Background() 99 dir := t.TempDir() 100 path := dir + "/fts.db" 101 db, err := OpenAtPath(ctx, path) 102 if err != nil { 103 t.Fatalf("open db: %v", err) 104 } 105 defer db.Close() 106 107 // Create user 108 uid := int64(1) 109 _, err = db.sql.ExecContext(ctx, `INSERT INTO users(id, username, encrypted_password, api_token, created_at, updated_at) VALUES(1, 'tester', 'x', 'tok', strftime('%Y-%m-%dT%H:%M:%fZ','now'), strftime('%Y-%m-%dT%H:%M:%fZ','now'))`) 110 if err != nil { 111 t.Fatalf("insert user: %v", err) 112 } 113 b, err := db.CreateBookmark(ctx, uid, "http://no-archive.local", "No Archive", nil) 114 if err != nil { 115 t.Fatalf("create: %v", err) 116 } 117 // Should not find term before archive content exists 118 hits, err := db.SearchBookmarksWithExcerpt(ctx, uid, "needle", 5, 0) 119 if err != nil { 120 t.Fatalf("search pre-archive: %v", err) 121 } 122 if len(hits) != 0 { 123 t.Fatalf("expected 0 hits before archiving, got %d", len(hits)) 124 } 125 // Save archive and ensure search works 126 if err := db.SaveArchive(ctx, b.ID, "finding a needle in a haystack"); err != nil { 127 t.Fatalf("save archive: %v", err) 128 } 129 hits, err = db.SearchBookmarksWithExcerpt(ctx, uid, "needle", 5, 0) 130 if err != nil { 131 t.Fatalf("search post-archive: %v", err) 132 } 133 if len(hits) != 1 { 134 t.Fatalf("expected 1 hit after archiving, got %d", len(hits)) 135 } 136 }