diff --git a/README.md b/README.md index 8ab7093..174eedb 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,14 @@ An in-process, in-memory database for Go. ## TO DO -* MDB Tests - * map index - * btree index - * btree iterator +* mapindex_test.go + * TestFullMapIndex + * TestPartialMapIndex +* btreeindex_test.go + * TestFullBTreeIndex + * TestPartialBTreeIndex +* btreeiterator_test.go +* collection +* database * WAL shipping + * WAL shipping with network disconnects diff --git a/mapindex_test.go b/mapindex_test.go index f1bd643..0d25d63 100644 --- a/mapindex_test.go +++ b/mapindex_test.go @@ -1,6 +1,7 @@ package mdb import ( + "errors" "fmt" "reflect" "testing" @@ -170,12 +171,193 @@ func TestFullMapIndex(t *testing.T) { return users }) - // update index field change key error + run("update change key error", func(t *testing.T, db *DB) map[string]*User { + users := map[string]*User{} - // update error from func - // update w/ ErrAbortUpdate - // update not found. - // update conflict. + for i := uint64(1); i < 10; i++ { + user := &User{ + ID: db.Users.c.NextID(), + Email: fmt.Sprintf("a.%d@c.com", i), + Name: fmt.Sprintf("name.%d", i), + ExtID: fmt.Sprintf("EXTID.%d", i), + } + if _, err := db.Users.c.Insert(*user); err != nil { + t.Fatal(err) + } + users[user.Email] = user + } + + var email string + for key := range users { + email = key + break + } + + err := db.Users.emailMap.Update(email, func(u User) (User, error) { + u.Email = "test@x.com" + return u, nil + }) + if err != ErrMismatchedIDs { + t.Fatal(err) + } + + return users + }) + + run("update function error", func(t *testing.T, db *DB) map[string]*User { + users := map[string]*User{} + + for i := uint64(1); i < 10; i++ { + user := &User{ + ID: db.Users.c.NextID(), + Email: fmt.Sprintf("a.%d@c.com", i), + Name: fmt.Sprintf("name.%d", i), + ExtID: fmt.Sprintf("EXTID.%d", i), + } + if _, err := db.Users.c.Insert(*user); err != nil { + t.Fatal(err) + } + users[user.Email] = user + } + + var email string + for key := range users { + email = key + break + } + + myErr := errors.New("hello") + + err := db.Users.emailMap.Update(email, func(u User) (User, error) { + return u, myErr + }) + if err != myErr { + t.Fatal(err) + } + + return users + }) + + run("update ErrAbortUpdate", func(t *testing.T, db *DB) map[string]*User { + users := map[string]*User{} + + for i := uint64(1); i < 10; i++ { + user := &User{ + ID: db.Users.c.NextID(), + Email: fmt.Sprintf("a.%d@c.com", i), + Name: fmt.Sprintf("name.%d", i), + ExtID: fmt.Sprintf("EXTID.%d", i), + } + if _, err := db.Users.c.Insert(*user); err != nil { + t.Fatal(err) + } + users[user.Email] = user + } + + var email string + for key := range users { + email = key + break + } + + err := db.Users.emailMap.Update(email, func(u User) (User, error) { + return u, ErrAbortUpdate + }) + if err != nil { + t.Fatal(err) + } + + return users + }) + + run("update ErrNotFound", func(t *testing.T, db *DB) map[string]*User { + users := map[string]*User{} + + for i := uint64(1); i < 10; i++ { + user := &User{ + ID: db.Users.c.NextID(), + Email: fmt.Sprintf("a.%d@c.com", i), + Name: fmt.Sprintf("name.%d", i), + ExtID: fmt.Sprintf("EXTID.%d", i), + } + if _, err := db.Users.c.Insert(*user); err != nil { + t.Fatal(err) + } + users[user.Email] = user + } + + var email string + for key := range users { + email = key + break + } + + err := db.Users.emailMap.Update(email+"x", func(u User) (User, error) { + return u, nil + }) + if err != ErrNotFound { + t.Fatal(err) + } + + return users + }) + + run("insert conflict", func(t *testing.T, db *DB) map[string]*User { + users := map[string]*User{} + + user := &User{ + ID: db.Users.c.NextID(), + Email: "a@b.com", + Name: "a", + ExtID: "", + } + + if _, err := db.Users.c.Insert(*user); err != nil { + t.Fatal(err) + } + users[user.Email] = user + + user2 := User{ + ID: db.Users.c.NextID(), + Email: "a@b.com", + Name: "someone else", + ExtID: "123", + } + + _, err := db.Users.c.Insert(user2) + if !errors.Is(err, ErrDuplicate) { + t.Fatal(err) + } + + return users + }) + + run("update conflict", func(t *testing.T, db *DB) map[string]*User { + users := map[string]*User{} + + user1 := &User{ID: db.Users.c.NextID(), Email: "a@b.com", Name: "a"} + user2 := &User{ID: db.Users.c.NextID(), Email: "x@y.com", Name: "x"} + + users[user1.Email] = user1 + users[user2.Email] = user2 + + for _, u := range users { + if _, err := db.Users.c.Insert(*u); err != nil { + t.Fatal(err) + } + } + + err := db.Users.c.Update(user2.ID, func(u User) (User, error) { + u.Email = "a@b.com" + return u, nil + }) + if !errors.Is(err, ErrDuplicate) { + t.Fatal(err) + } + + return users + }) + // update conflict } func TestPartialMapIndex(t *testing.T) { @@ -184,12 +366,11 @@ func TestPartialMapIndex(t *testing.T) { // insert outside index // insert and delete in index // insert and delete outside index - // insert withing index - // update out of index + // update outside index // update into index - // update error from func + // update function error // udpate ErrAbortUpdate - // update not found + // update ErrNotFound // update conflict in to in // update conflict out to in }