package routing import ( "context" "database/sql" "testing" "time" "github.com/wangjia/pangolin/server/internal/config" "github.com/wangjia/pangolin/server/internal/store" ) func openDB(t *testing.T) *sql.DB { t.Helper() db, err := store.Open(&config.Config{Driver: "sqlite", DSN: ":memory:"}) if err != nil { t.Fatal(err) } t.Cleanup(func() { _ = db.Close() }) if err := store.MigrateUp(db, "sqlite"); err != nil { t.Fatal(err) } _ = store.ApplyCodesLibMigrations(context.Background(), db, "sqlite") return db } func seedU(t *testing.T, db *sql.DB, id int64, uuid string) { t.Helper() if _, err := db.Exec(`INSERT INTO users (id,uuid,email,pw_hash,dp_uuid,status,created_at) VALUES (?,?,?, 'x','dp-'||?, 'active', ?)`, id, uuid, uuid+"@x", uuid, time.Now().UTC()); err != nil { t.Fatal(err) } } // TestSQLiteRoutingStoreGetNoProfileRow isolates the "queried the DB, found // no row" path from TestSQLiteRoutingStoreUpsertGet's combined // empty→upsert→overwrite flow: a store backed by a real (non-nil) *sql.DB, // with the user seeded but no routing_profiles row for them, must return // (nil, nil) — not an error — via the sql.ErrNoRows branch in Store.Get. func TestSQLiteRoutingStoreGetNoProfileRow(t *testing.T) { db := openDB(t) seedU(t, db, 2, "u2") st := NewStore(db) if st == nil { t.Fatal("NewStore returned nil") } got, err := st.Get(context.Background(), 2) if err != nil { t.Fatalf("want nil error for no-rows, got %v", err) } if got != nil { t.Fatalf("want nil profile for seeded user with no profile row, got %+v", got) } } func TestSQLiteRoutingStoreUpsertGet(t *testing.T) { db := openDB(t) // 内存库 + MigrateUp(sqlite) seedU(t, db, 1, "u1") st := NewStore(db) ctx := context.Background() // 无档案 → nil,nil got, err := st.Get(ctx, 1) if err != nil || got != nil { t.Fatalf("empty want nil,nil got %v,%v", got, err) } // Upsert 后可取回 p := Default() p.Final = "direct" if err := st.Upsert(ctx, 1, p); err != nil { t.Fatal(err) } got, err = st.Get(ctx, 1) if err != nil || got == nil || got.Final != "direct" { t.Fatalf("got %v,%v", got, err) } // 二次 Upsert 覆盖 p.Final = "proxy" _ = st.Upsert(ctx, 1, p) got, _ = st.Get(ctx, 1) if got.Final != "proxy" { t.Fatalf("upsert overwrite failed: %s", got.Final) } }