package memorydb import ( "context" "errors" "testing" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/mcache" _ "github.com/gogf/gf/contrib/drivers/sqlite/v2" "github.com/gogf/gf/v2/database/gdb" ) type rebuildTestTable struct { name string value string fail bool initEvents int } func (t *rebuildTestTable) Init(context.Context) error { t.initEvents++ return nil } func (t *rebuildTestTable) EventHandler(context.Context) error { return nil } func (t *rebuildTestTable) TableName(context.Context) string { return t.name } func (t *rebuildTestTable) LoadData(context.Context, int64) error { return nil } func (t *rebuildTestTable) DeleteData(context.Context, []int64) error { return nil } func (t *rebuildTestTable) CreateTable(ctx context.Context) error { if _, err := db.Exec(ctx, "DROP TABLE IF EXISTS "+t.name); err != nil { return err } if t.fail { return errors.New("source load failed") } if _, err := db.Exec(ctx, "CREATE TABLE "+t.name+" (value TEXT)"); err != nil { return err } _, err := db.Exec(ctx, "INSERT INTO "+t.name+" (value) VALUES (?)", t.value) return err } func TestRebuildRollsBackAndDoesNotRegisterEventsAgain(t *testing.T) { ctx := context.Background() previousDB, previousMap := db, memDBMap t.Cleanup(func() { db, memDBMap = previousDB, previousMap }) var err error db, err = gdb.New(gdb.ConfigNode{Link: "sqlite::@file(:memory:)", MaxOpenConnCount: 1}) if err != nil { t.Fatal(err) } t.Cleanup(func() { _ = db.Close(ctx) }) first := &rebuildTestTable{name: "cache_a", value: "new"} second := &rebuildTestTable{name: "cache_b", value: "new", fail: true} memDBMap = map[string]memDB{first.name: first, second.name: second} for _, name := range registeredMemoryDBNames() { if _, err := db.Exec(ctx, "CREATE TABLE "+name+" (value TEXT)"); err != nil { t.Fatal(err) } if _, err := db.Exec(ctx, "INSERT INTO "+name+" (value) VALUES ('old')"); err != nil { t.Fatal(err) } } cache := NewMemoryDB() if err := cache.Rebuild(ctx); err == nil { t.Fatal("expected rebuild failure") } for _, name := range registeredMemoryDBNames() { var result struct { Value string `json:"value"` } if err := db.Model(name).Scan(&result); err != nil || result.Value != "old" { t.Fatalf("%s was not rolled back: value=%q err=%v", name, result.Value, err) } } second.fail = false if err := mcache.Set(ctx, "rebuild-test-key", "stale", 0); err != nil { t.Fatal(err) } if err := cache.Rebuild(ctx); err != nil { t.Fatal(err) } for _, name := range registeredMemoryDBNames() { var result struct { Value string `json:"value"` } if err := db.Model(name).Scan(&result); err != nil || result.Value != "new" { t.Fatalf("%s was not reloaded: value=%q err=%v", name, result.Value, err) } } if first.initEvents != 0 || second.initEvents != 0 { t.Fatal("rebuild registered event handlers") } if mcache.Instance().MustContains(ctx, "rebuild-test-key") { t.Fatal("derived cache was not cleared") } }