159 lines
4.7 KiB
Go
159 lines
4.7 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestModelStoreSQLiteCreatesSchemaAndPersists(t *testing.T) {
|
|
dbPath := filepath.Join(t.TempDir(), "models.sqlite")
|
|
store := NewModelStore(ModelStoreConfig{
|
|
Type: databaseTypeSQLite,
|
|
DSN: dbPath,
|
|
SQLitePath: dbPath,
|
|
})
|
|
defer store.Close()
|
|
|
|
if err := store.Load(); err != nil {
|
|
t.Fatalf("load sqlite store: %v", err)
|
|
}
|
|
if _, err := os.Stat(dbPath); err != nil {
|
|
t.Fatalf("sqlite file not created: %v", err)
|
|
}
|
|
|
|
model, err := store.EnsureByHostModelKey("chaturbate.com", "alice")
|
|
if err != nil {
|
|
t.Fatalf("ensure model: %v", err)
|
|
}
|
|
if model.ID != "chaturbate.com:alice" {
|
|
t.Fatalf("unexpected model id: %q", model.ID)
|
|
}
|
|
|
|
if err := store.SetLastSeenOnline("chaturbate.com", "alice", true, time.Now().UTC().Format(time.RFC3339Nano)); err != nil {
|
|
t.Fatalf("set last seen online: %v", err)
|
|
}
|
|
|
|
models := store.List()
|
|
if len(models) != 1 {
|
|
t.Fatalf("expected 1 model, got %d", len(models))
|
|
}
|
|
if models[0].LastSeenOnline == nil || !*models[0].LastSeenOnline {
|
|
t.Fatalf("lastSeenOnline not persisted: %#v", models[0].LastSeenOnline)
|
|
}
|
|
|
|
meta := store.Meta()
|
|
if meta.Count != 1 {
|
|
t.Fatalf("expected meta count 1, got %d", meta.Count)
|
|
}
|
|
if meta.UpdatedAt == "" {
|
|
t.Fatal("expected meta updatedAt")
|
|
}
|
|
}
|
|
|
|
func TestMigrateModelStoreDataSQLiteToSQLiteReplacesTarget(t *testing.T) {
|
|
tmp := t.TempDir()
|
|
sourcePath := filepath.Join(tmp, "source.sqlite")
|
|
targetPath := filepath.Join(tmp, "target.sqlite")
|
|
|
|
sourceConfig := ModelStoreConfig{Type: databaseTypeSQLite, DSN: sourcePath, SQLitePath: sourcePath}
|
|
targetConfig := ModelStoreConfig{Type: databaseTypeSQLite, DSN: targetPath, SQLitePath: targetPath}
|
|
|
|
source := NewModelStore(sourceConfig)
|
|
defer source.Close()
|
|
if err := source.Load(); err != nil {
|
|
t.Fatalf("load source: %v", err)
|
|
}
|
|
if _, err := source.EnsureByHostModelKey("chaturbate.com", "alice"); err != nil {
|
|
t.Fatalf("ensure source model: %v", err)
|
|
}
|
|
if err := source.SetProfileImage("chaturbate.com", "alice", "https://example.test/a.jpg", "image/jpeg", []byte{1, 2, 3, 4}, time.Now().UTC().Format(time.RFC3339Nano)); err != nil {
|
|
t.Fatalf("set profile image: %v", err)
|
|
}
|
|
if err := source.SetBioContext("chaturbate.com", "alice", `{"ok":true}`, time.Now().UTC().Format(time.RFC3339Nano)); err != nil {
|
|
t.Fatalf("set bio context: %v", err)
|
|
}
|
|
|
|
target := NewModelStore(targetConfig)
|
|
if err := target.Load(); err != nil {
|
|
t.Fatalf("load target: %v", err)
|
|
}
|
|
if _, err := target.EnsureByHostModelKey("chaturbate.com", "stale"); err != nil {
|
|
t.Fatalf("ensure stale target model: %v", err)
|
|
}
|
|
_ = target.Close()
|
|
_ = source.Close()
|
|
|
|
count, err := migrateModelStoreData(sourceConfig, targetConfig)
|
|
if err != nil {
|
|
t.Fatalf("migrate sqlite to sqlite: %v", err)
|
|
}
|
|
if count != 1 {
|
|
t.Fatalf("expected 1 migrated row, got %d", count)
|
|
}
|
|
|
|
migrated := NewModelStore(targetConfig)
|
|
defer migrated.Close()
|
|
if err := migrated.Load(); err != nil {
|
|
t.Fatalf("load migrated target: %v", err)
|
|
}
|
|
models := migrated.List()
|
|
if len(models) != 1 {
|
|
t.Fatalf("expected target replacement with 1 row, got %d", len(models))
|
|
}
|
|
if models[0].ModelKey != "alice" {
|
|
t.Fatalf("unexpected migrated model: %q", models[0].ModelKey)
|
|
}
|
|
if models[0].ProfileImageCached == "" {
|
|
t.Fatal("expected migrated profile image blob marker")
|
|
}
|
|
bio, _, ok, err := migrated.GetBioContext("chaturbate.com", "alice")
|
|
if err != nil {
|
|
t.Fatalf("get migrated bio context: %v", err)
|
|
}
|
|
if !ok || bio != `{"ok":true}` {
|
|
t.Fatalf("unexpected migrated bio context ok=%v bio=%q", ok, bio)
|
|
}
|
|
}
|
|
|
|
func TestMoveSQLiteDatabaseFilesMovesSidecars(t *testing.T) {
|
|
tmp := t.TempDir()
|
|
sourcePath := filepath.Join(tmp, "old", "models.sqlite")
|
|
targetPath := filepath.Join(tmp, "new", "models.sqlite")
|
|
|
|
if err := os.MkdirAll(filepath.Dir(sourcePath), 0755); err != nil {
|
|
t.Fatalf("mkdir source: %v", err)
|
|
}
|
|
files := map[string]string{
|
|
sourcePath: "main",
|
|
sourcePath + "-wal": "wal",
|
|
sourcePath + "-shm": "shm",
|
|
sourcePath + "-journal": "journal",
|
|
}
|
|
for path, content := range files {
|
|
if err := os.WriteFile(path, []byte(content), 0644); err != nil {
|
|
t.Fatalf("write %s: %v", path, err)
|
|
}
|
|
}
|
|
|
|
if err := moveSQLiteDatabaseFiles(sourcePath, targetPath); err != nil {
|
|
t.Fatalf("move sqlite files: %v", err)
|
|
}
|
|
|
|
for source, content := range files {
|
|
if _, err := os.Stat(source); !os.IsNotExist(err) {
|
|
t.Fatalf("expected source removed %s, err=%v", source, err)
|
|
}
|
|
target := strings.Replace(source, sourcePath, targetPath, 1)
|
|
b, err := os.ReadFile(target)
|
|
if err != nil {
|
|
t.Fatalf("read target %s: %v", target, err)
|
|
}
|
|
if string(b) != content {
|
|
t.Fatalf("unexpected target content for %s: %q", target, string(b))
|
|
}
|
|
}
|
|
}
|