package mdb import ( "reflect" "testing" ) func TestFullBTreeIndex(t *testing.T) { // Test against the email index. run := func(name string, inner func(t *testing.T, db *DB) []*User) { testWithDB(t, name, func(t *testing.T, db *DB) { expected := inner(t, db) if err := db.Users.emailBTree.EqualsList(expected); err != nil { t.Fatal(err) } db.Close() db = OpenDB(db.root, true) if err := db.Users.emailBTree.EqualsList(expected); err != nil { t.Fatal(err) } }) } run("insert", func(t *testing.T, db *DB) (users []*User) { users = append(users, &User{ID: db.Users.c.NextID(), Email: "a@b.com", Name: "aaa"}, &User{ID: db.Users.c.NextID(), Email: "c@d.com", Name: "ccc"}) for _, u := range users { u2, err := db.Users.c.Insert(*u) if err != nil { t.Fatal(err) } if !reflect.DeepEqual(u2, *u) { t.Fatal(u2, *u) } } return users }) run("update", func(t *testing.T, db *DB) (users []*User) { users = append(users, &User{ID: db.Users.c.NextID(), Email: "a@b.com", Name: "aaa"}, &User{ID: db.Users.c.NextID(), Email: "e@f.com", Name: "eee"}, &User{ID: db.Users.c.NextID(), Email: "c@d.com", Name: "ccc"}) for _, u := range users { if _, err := db.Users.c.Insert(*u); err != nil { t.Fatal(err) } } err := db.Users.c.Update(users[2].ID, func(u User) (User, error) { u.Email = "g@h.com" return u, nil }) if err != nil { t.Fatal(err) } users[2].Email = "g@h.com" return users }) run("delete", func(t *testing.T, db *DB) (users []*User) { users = append(users, &User{ID: db.Users.c.NextID(), Email: "a@b.com", Name: "aaa"}, &User{ID: db.Users.c.NextID(), Email: "c@d.com", Name: "ccc"}, &User{ID: db.Users.c.NextID(), Email: "e@f.com", Name: "eee"}) for _, u := range users { if _, err := db.Users.c.Insert(*u); err != nil { t.Fatal(err) } } db.Users.c.Delete(users[0].ID) users = users[1:] return users }) run("get not found", func(t *testing.T, db *DB) (users []*User) { users = append(users, &User{ID: db.Users.c.NextID(), Email: "a@b.com", Name: "aaa"}, &User{ID: db.Users.c.NextID(), Email: "c@d.com", Name: "ccc"}, &User{ID: db.Users.c.NextID(), Email: "e@f.com", Name: "eee"}) for _, u := range users { if _, err := db.Users.c.Insert(*u); err != nil { t.Fatal(err) } } if u, ok := db.Users.emailBTree.Get(User{Email: "g@h.com"}); ok { t.Fatal(u, ok) } return users }) run("min/max empty", func(t *testing.T, db *DB) (users []*User) { if u, ok := db.Users.emailBTree.Min(); ok { t.Fatal(u, ok) } if u, ok := db.Users.emailBTree.Max(); ok { t.Fatal(u, ok) } return users }) } func TestPartialBTreeIndex(t *testing.T) { // Test against the extID btree index. run := func(name string, inner func(t *testing.T, db *DB) []*User) { testWithDB(t, name, func(t *testing.T, db *DB) { expected := inner(t, db) if err := db.Users.extIDBTree.EqualsList(expected); err != nil { t.Fatal(err) } db.Close() db = OpenDB(db.root, true) if err := db.Users.extIDBTree.EqualsList(expected); err != nil { t.Fatal(err) } }) } run("insert out", func(t *testing.T, db *DB) []*User { users := []*User{ {ID: db.Users.c.NextID(), Email: "a@b.com", Name: "xxx"}, {ID: db.Users.c.NextID(), Email: "c@d.com", Name: "ggg"}, {ID: db.Users.c.NextID(), Email: "e@f.com", Name: "aaa"}, } for _, u := range users { if _, err := db.Users.c.Insert(*u); err != nil { t.Fatal(err) } } return []*User{} }) run("insert in", func(t *testing.T, db *DB) []*User { users := []*User{ {ID: db.Users.c.NextID(), Email: "a@b.com", Name: "xxx"}, {ID: db.Users.c.NextID(), Email: "c@d.com", Name: "ggg", ExtID: "x"}, {ID: db.Users.c.NextID(), Email: "e@f.com", Name: "aaa"}, } for _, u := range users { if _, err := db.Users.c.Insert(*u); err != nil { t.Fatal(err) } } return []*User{users[1]} }) run("update out to out", func(t *testing.T, db *DB) []*User { users := []*User{ {ID: db.Users.c.NextID(), Email: "a@b.com", Name: "aaa"}, {ID: db.Users.c.NextID(), Email: "c@d.com", Name: "ccc", ExtID: "A"}, {ID: db.Users.c.NextID(), Email: "e@f.com", Name: "eee"}, {ID: db.Users.c.NextID(), Email: "g@h.com", Name: "ggg", ExtID: "B"}, } for _, u := range users { if _, err := db.Users.c.Insert(*u); err != nil { t.Fatal(err) } } err := db.Users.c.Update(users[0].ID, func(u User) (User, error) { u.Name = "axa" users[0].Name = "axa" return u, nil }) if err != nil { t.Fatal(err) } return []*User{users[1], users[3]} }) run("update in to in", func(t *testing.T, db *DB) []*User { users := []*User{ {ID: db.Users.c.NextID(), Email: "a@b.com", Name: "aaa"}, {ID: db.Users.c.NextID(), Email: "c@d.com", Name: "ccc", ExtID: "A"}, {ID: db.Users.c.NextID(), Email: "e@f.com", Name: "eee"}, {ID: db.Users.c.NextID(), Email: "g@h.com", Name: "ggg", ExtID: "B"}, } for _, u := range users { if _, err := db.Users.c.Insert(*u); err != nil { t.Fatal(err) } } err := db.Users.c.Update(users[1].ID, func(u User) (User, error) { u.ExtID = "C" users[1].ExtID = "C" return u, nil }) if err != nil { t.Fatal(err) } return []*User{users[3], users[1]} }) run("update out to in", func(t *testing.T, db *DB) []*User { users := []*User{ {ID: db.Users.c.NextID(), Email: "a@b.com", Name: "aaa"}, {ID: db.Users.c.NextID(), Email: "c@d.com", Name: "ccc", ExtID: "A"}, {ID: db.Users.c.NextID(), Email: "e@f.com", Name: "eee"}, {ID: db.Users.c.NextID(), Email: "g@h.com", Name: "ggg", ExtID: "B"}, } for _, u := range users { if _, err := db.Users.c.Insert(*u); err != nil { t.Fatal(err) } } err := db.Users.c.Update(users[2].ID, func(u User) (User, error) { u.ExtID = "C" users[2].ExtID = "C" return u, nil }) if err != nil { t.Fatal(err) } return []*User{users[1], users[3], users[2]} }) run("update in to out", func(t *testing.T, db *DB) []*User { users := []*User{ {ID: db.Users.c.NextID(), Email: "a@b.com", Name: "aaa"}, {ID: db.Users.c.NextID(), Email: "c@d.com", Name: "ccc", ExtID: "A"}, {ID: db.Users.c.NextID(), Email: "e@f.com", Name: "eee"}, {ID: db.Users.c.NextID(), Email: "g@h.com", Name: "ggg", ExtID: "B"}, } for _, u := range users { if _, err := db.Users.c.Insert(*u); err != nil { t.Fatal(err) } } err := db.Users.c.Update(users[1].ID, func(u User) (User, error) { u.ExtID = "" users[1].ExtID = "" return u, nil }) if err != nil { t.Fatal(err) } return []*User{users[3]} }) } func TestBTreeIndex_load_ErrDuplicate(t *testing.T) { testWithDB(t, "", func(t *testing.T, db *DB) { idx := NewBTreeIndex( db.Users.c, "extid", func(lhs, rhs *User) bool { return lhs.ExtID < rhs.ExtID }, nil) users := map[uint64]*User{ 1: {ID: 1, Email: "x@y.com", Name: "xx", ExtID: "x"}, 2: {ID: 2, Email: "a@b.com", Name: "aa", ExtID: "x"}, } if err := idx.load(users); err != ErrDuplicate { t.Fatal(err) } }) }