Files
Maven/internal/store/migrations_test.go
T
claude 908d92a7e8 calendar: a Russian summary keeps its letters in the fact key (V-443)
safeKey kept ASCII only, so "Встреча с Аней" and "Обед с мамой" both
reduced to "--" and shared one key on one day. The second event of the
day overwrote the first, silently, and his calendar is Russian.

Letters and digits in any script now pass. Migration #18 deletes the rows
written under the old rule instead of rewriting them: a calendar fact is
derived, the next poll writes the day again, and a stale row reads as an
extra meeting.
2026-08-04 02:56:09 +04:00

83 lines
2.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package store
import (
"context"
"testing"
)
func userVersion(t *testing.T, s *Store) int {
t.Helper()
var v int
if err := s.db.QueryRowContext(context.Background(), "PRAGMA user_version").Scan(&v); err != nil {
t.Fatalf("read user_version: %v", err)
}
return v
}
func TestMigrateAppliesOnceAndIsIdempotent(t *testing.T) {
ctx := context.Background()
s := newTestStore(t)
// The 1 migration in the built-in slice (tools scope) was applied on Open.
startVer := len(migrations)
if v := userVersion(t, s); v != startVer {
t.Fatalf("fresh DB user_version = %d, want %d", v, startVer)
}
// Append a fake migration and run it: creates a throwaway table, bumps by 1.
migrations = append(migrations, `CREATE TABLE migrate_probe (id INTEGER PRIMARY KEY)`)
t.Cleanup(func() { migrations = migrations[:len(migrations)-1] })
if err := migrate(ctx, s.db); err != nil {
t.Fatalf("migrate: %v", err)
}
want := startVer + 1
if v := userVersion(t, s); v != want {
t.Fatalf("after migrate user_version = %d, want %d", v, want)
}
if _, err := s.db.ExecContext(ctx, "INSERT INTO migrate_probe DEFAULT VALUES"); err != nil {
t.Fatalf("probe table not created: %v", err)
}
// Second run is a no-op — re-running the CREATE would error (no IF NOT EXISTS).
if err := migrate(ctx, s.db); err != nil {
t.Fatalf("migrate second run not idempotent: %v", err)
}
if v := userVersion(t, s); v != want {
t.Fatalf("after re-migrate user_version = %d, want %d", v, want)
}
}
// Migration #18 clears the calendar keys written while safeKey dropped
// Cyrillic. Those rows are indistinguishable from real events on read, so
// leaving them would recite one meeting as several (Vikunja #443).
func TestCollapsedCalendarKeysAreDropped(t *testing.T) {
ctx := context.Background()
s := newTestStore(t)
rows := []string{
"calendar_event_20260804_--", // "Встреча с Аней" under the old rule
"calendar_event_20260804_", // a one-word Russian summary
"calendar_event_20260804_Встреча-с-Аней", // the new format
"calendar_event_20260804_Standup", // an ASCII summary, always fine
}
for _, key := range rows {
if _, err := s.db.ExecContext(ctx,
`INSERT INTO facts (ts, kind, key, value, source, confidence) VALUES (0, 'env', ?, 'x', 'poll:caldav', 1.0)`,
key); err != nil {
t.Fatalf("seed %q: %v", key, err)
}
}
if _, err := s.db.ExecContext(ctx, migrations[17]); err != nil {
t.Fatalf("migration 18: %v", err)
}
var got int
if err := s.db.QueryRowContext(ctx, `SELECT count(*) FROM facts WHERE key LIKE 'calendar_event_%'`).Scan(&got); err != nil {
t.Fatal(err)
}
if got != 2 {
t.Fatalf("%d calendar rows left, want the 2 that identify their event", got)
}
}