101 lines
2.8 KiB
Go
101 lines
2.8 KiB
Go
package store
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// A fresh DB has no marker yet, so the current embedder is recorded and
|
|
// nothing is flagged.
|
|
func TestCheckEmbedderFreshDBRecords(t *testing.T) {
|
|
s := newTestStore(t)
|
|
ctx := context.Background()
|
|
|
|
stored, mismatch, err := s.CheckEmbedder(ctx, "multilingual-e5-small@384")
|
|
if err != nil {
|
|
t.Fatalf("CheckEmbedder: %v", err)
|
|
}
|
|
if mismatch {
|
|
t.Fatal("fresh DB reported a mismatch")
|
|
}
|
|
if stored != "multilingual-e5-small@384" {
|
|
t.Fatalf("stored = %q", stored)
|
|
}
|
|
got, err := s.Meta(ctx, metaKeyEmbedderID)
|
|
if err != nil {
|
|
t.Fatalf("Meta: %v", err)
|
|
}
|
|
if got != "multilingual-e5-small@384" {
|
|
t.Fatalf("marker not persisted, got %q", got)
|
|
}
|
|
}
|
|
|
|
// The deployed box: notes were written by the old embedder, before the marker
|
|
// existed. Claiming them for the current one would hide exactly the problem
|
|
// the marker is for, so an unmarked DB that already holds vectors is a
|
|
// mismatch.
|
|
func TestCheckEmbedderUnmarkedDBWithVectorsIsMismatch(t *testing.T) {
|
|
s := newTestStore(t)
|
|
ctx := context.Background()
|
|
|
|
if _, err := s.WriteNote(ctx, time.Now(), "молоко в холодильнике", []float32{0.1, 0.2}, "voice"); err != nil {
|
|
t.Fatalf("WriteNote: %v", err)
|
|
}
|
|
|
|
stored, mismatch, err := s.CheckEmbedder(ctx, "multilingual-e5-small@384")
|
|
if err != nil {
|
|
t.Fatalf("CheckEmbedder: %v", err)
|
|
}
|
|
if !mismatch {
|
|
t.Fatal("an unmarked DB with stored vectors should report a mismatch")
|
|
}
|
|
if stored != EmbedderUnknown {
|
|
t.Fatalf("stored = %q, want %q", stored, EmbedderUnknown)
|
|
}
|
|
// It must NOT claim the DB — that would silence the warning on restart.
|
|
got, err := s.Meta(ctx, metaKeyEmbedderID)
|
|
if err != nil {
|
|
t.Fatalf("Meta: %v", err)
|
|
}
|
|
if got != "" {
|
|
t.Fatalf("marker written despite unknown provenance: %q", got)
|
|
}
|
|
}
|
|
|
|
// Both models are 384-dim, so this is the only thing that catches the swap.
|
|
func TestCheckEmbedderDifferentModelMismatch(t *testing.T) {
|
|
s := newTestStore(t)
|
|
ctx := context.Background()
|
|
|
|
if err := s.SetMeta(ctx, metaKeyEmbedderID, "paraphrase-multilingual-MiniLM-L12-v2@384"); err != nil {
|
|
t.Fatalf("SetMeta: %v", err)
|
|
}
|
|
stored, mismatch, err := s.CheckEmbedder(ctx, "multilingual-e5-small@384")
|
|
if err != nil {
|
|
t.Fatalf("CheckEmbedder: %v", err)
|
|
}
|
|
if !mismatch {
|
|
t.Fatal("different embedder not detected")
|
|
}
|
|
if stored != "paraphrase-multilingual-MiniLM-L12-v2@384" {
|
|
t.Fatalf("stored = %q", stored)
|
|
}
|
|
}
|
|
|
|
// The same embedder must never raise a false alarm, including on re-check.
|
|
func TestCheckEmbedderSameModelNoAlarm(t *testing.T) {
|
|
s := newTestStore(t)
|
|
ctx := context.Background()
|
|
|
|
for i := 0; i < 2; i++ {
|
|
_, mismatch, err := s.CheckEmbedder(ctx, "multilingual-e5-small@384")
|
|
if err != nil {
|
|
t.Fatalf("CheckEmbedder: %v", err)
|
|
}
|
|
if mismatch {
|
|
t.Fatalf("false alarm on pass %d", i)
|
|
}
|
|
}
|
|
}
|