360 lines
10 KiB
Go
360 lines
10 KiB
Go
package leveldb
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"m8sh.su/x/m8sh/database"
|
|
)
|
|
|
|
func TestReactions_SetAllowed(t *testing.T) {
|
|
db, cleanup := openDB(t)
|
|
defer cleanup()
|
|
|
|
reactions := db.Reactions()
|
|
owner := "masha"
|
|
date := time.Now()
|
|
|
|
t.Run("set allowed emojis", func(t *testing.T) {
|
|
err := reactions.SetAllowed(owner, date, []string{"👍", "❤️", "🔥"})
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("overwrite allowed emojis", func(t *testing.T) {
|
|
err := reactions.SetAllowed(owner, date, []string{"👎"})
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("set empty allowed", func(t *testing.T) {
|
|
err := reactions.SetAllowed(owner, date.Add(time.Second), []string{})
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
|
|
func TestReactions_Allowed(t *testing.T) {
|
|
db, cleanup := openDB(t)
|
|
defer cleanup()
|
|
|
|
reactions := db.Reactions()
|
|
owner := "masha"
|
|
date := time.Now()
|
|
|
|
err := reactions.SetAllowed(owner, date, []string{"👍", "🔥"})
|
|
require.NoError(t, err)
|
|
|
|
t.Run("get allowed emojis", func(t *testing.T) {
|
|
got, err := reactions.GetAllowed(owner, date)
|
|
require.NoError(t, err)
|
|
require.Equal(t, []string{"👍", "🔥"}, got)
|
|
})
|
|
|
|
t.Run("get non-existing allowed", func(t *testing.T) {
|
|
_, err := reactions.GetAllowed("unknown", date)
|
|
require.ErrorIs(t, err, database.ErrNotFound)
|
|
})
|
|
|
|
t.Run("get allowed for different time", func(t *testing.T) {
|
|
_, err := reactions.GetAllowed(owner, date.Add(time.Hour))
|
|
require.ErrorIs(t, err, database.ErrNotFound)
|
|
})
|
|
}
|
|
|
|
func TestReactions_Add(t *testing.T) {
|
|
db, cleanup := openDB(t)
|
|
defer cleanup()
|
|
|
|
reactions := db.Reactions()
|
|
user := "masha"
|
|
author := "bob"
|
|
domain := "d2.io"
|
|
date := time.Now()
|
|
|
|
t.Run("add reaction", func(t *testing.T) {
|
|
err := reactions.Add(user, author, domain, date, "👍", []byte("sig123"))
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("add another emoji", func(t *testing.T) {
|
|
err := reactions.Add(user, author, domain, date, "🔥", []byte("sig456"))
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("add different user", func(t *testing.T) {
|
|
err := reactions.Add("petya", author, domain, date, "👍", []byte("sig789"))
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("add different content", func(t *testing.T) {
|
|
err := reactions.Add(user, "alice", "d3.net", date.Add(time.Second), "❤️", []byte("sig000"))
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("add with empty signature", func(t *testing.T) {
|
|
err := reactions.Add(user, author, domain, date.Add(2*time.Second), "❤️", nil)
|
|
require.NoError(t, err)
|
|
})
|
|
}
|
|
|
|
func TestReactions_Remove(t *testing.T) {
|
|
db, cleanup := openDB(t)
|
|
defer cleanup()
|
|
|
|
reactions := db.Reactions()
|
|
user := "masha"
|
|
author := "bob"
|
|
domain := "d2.io"
|
|
date := time.Now()
|
|
|
|
err := reactions.Add(user, author, domain, date, "👍", []byte("sig"))
|
|
require.NoError(t, err)
|
|
|
|
t.Run("remove existing reaction", func(t *testing.T) {
|
|
err := reactions.Remove(user, author, domain, date, "👍")
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("remove non-existing returns ErrNotFound", func(t *testing.T) {
|
|
err := reactions.Remove(user, author, domain, date, "🔥")
|
|
require.ErrorIs(t, err, database.ErrNotFound)
|
|
})
|
|
|
|
t.Run("remove twice returns ErrNotFound", func(t *testing.T) {
|
|
err := reactions.Remove(user, author, domain, date, "👍")
|
|
require.ErrorIs(t, err, database.ErrNotFound)
|
|
})
|
|
}
|
|
|
|
func TestReactions_OfUser(t *testing.T) {
|
|
db, cleanup := openDB(t)
|
|
defer cleanup()
|
|
|
|
reactions := db.Reactions()
|
|
user := "masha"
|
|
date := time.Now()
|
|
|
|
t.Run("empty reactions", func(t *testing.T) {
|
|
list, err := reactions.OfUser("newuser", 10, 0)
|
|
require.NoError(t, err)
|
|
require.Empty(t, list)
|
|
})
|
|
|
|
t.Run("single reaction", func(t *testing.T) {
|
|
err := reactions.Add(user, "bob", "d2.io", date, "👍", []byte("sig123"))
|
|
require.NoError(t, err)
|
|
|
|
list, err := reactions.OfUser(user, 10, 0)
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 1)
|
|
require.Equal(t, "bob", list[0].Author)
|
|
require.Equal(t, "d2.io", list[0].Domain)
|
|
require.Equal(t, "👍", list[0].Emoji)
|
|
})
|
|
|
|
t.Run("multiple reactions", func(t *testing.T) {
|
|
err := reactions.Add(user, "alice", "d3.net", date.Add(time.Second), "🔥", []byte("sig456"))
|
|
require.NoError(t, err)
|
|
|
|
list, err := reactions.OfUser(user, 10, 0)
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 2)
|
|
})
|
|
|
|
t.Run("pagination limit", func(t *testing.T) {
|
|
list, err := reactions.OfUser(user, 1, 0)
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 1)
|
|
})
|
|
|
|
t.Run("pagination offset", func(t *testing.T) {
|
|
list, err := reactions.OfUser(user, 10, 1)
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 1)
|
|
})
|
|
|
|
t.Run("user isolation", func(t *testing.T) {
|
|
err := reactions.Add("petya", "bob", "d2.io", date, "👍", []byte("sig777"))
|
|
require.NoError(t, err)
|
|
|
|
mashaList, err := reactions.OfUser("masha", 10, 0)
|
|
require.NoError(t, err)
|
|
|
|
petyaList, err := reactions.OfUser("petya", 10, 0)
|
|
require.NoError(t, err)
|
|
|
|
require.Len(t, mashaList, 2)
|
|
require.Len(t, petyaList, 1)
|
|
})
|
|
}
|
|
|
|
func TestReactions_ToContent(t *testing.T) {
|
|
db, cleanup := openDB(t)
|
|
defer cleanup()
|
|
|
|
r := db.Reactions()
|
|
author := "bob"
|
|
domain := "d2.io"
|
|
date := time.Now()
|
|
|
|
t.Run("empty reactions", func(t *testing.T) {
|
|
list, err := r.ToContent(author, domain, date, 10, 0)
|
|
require.NoError(t, err)
|
|
require.Empty(t, list)
|
|
})
|
|
|
|
t.Run("reactions from multiple users", func(t *testing.T) {
|
|
require.NoError(t, r.Add("masha", author, domain, date, "👍", []byte("sig1")))
|
|
require.NoError(t, r.Add("petya", author, domain, date, "🔥", []byte("sig2")))
|
|
require.NoError(t, r.Add("alice", author, domain, date, "👍", []byte("sig3")))
|
|
|
|
list, err := r.ToContent(author, domain, date, 10, 0)
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 3)
|
|
})
|
|
|
|
t.Run("pagination", func(t *testing.T) {
|
|
list, err := r.ToContent(author, domain, date, 2, 0)
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 2)
|
|
|
|
list, err = r.ToContent(author, domain, date, 10, 2)
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 1)
|
|
})
|
|
|
|
t.Run("wrong domain returns empty", func(t *testing.T) {
|
|
list, err := r.ToContent(author, "unknown.com", date, 10, 0)
|
|
require.NoError(t, err)
|
|
require.Empty(t, list)
|
|
})
|
|
|
|
t.Run("wrong author returns empty", func(t *testing.T) {
|
|
list, err := r.ToContent("unknown", domain, date, 10, 0)
|
|
require.NoError(t, err)
|
|
require.Empty(t, list)
|
|
})
|
|
|
|
t.Run("signature preserved", func(t *testing.T) {
|
|
list, err := r.ToContent(author, domain, date, 10, 0)
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 3)
|
|
|
|
sigs := make(map[string][]byte)
|
|
for _, r := range list {
|
|
sigs[r.User] = r.Signature
|
|
}
|
|
require.Equal(t, []byte("sig1"), sigs["masha"])
|
|
require.Equal(t, []byte("sig2"), sigs["petya"])
|
|
require.Equal(t, []byte("sig3"), sigs["alice"])
|
|
})
|
|
}
|
|
|
|
func TestReactions_UpdateReference(t *testing.T) {
|
|
db, cleanup := openDB(t)
|
|
defer cleanup()
|
|
db.reactions.flushInterval = 10 * time.Millisecond
|
|
|
|
reactions := db.Reactions()
|
|
owner := "bob"
|
|
date := time.Now()
|
|
|
|
t.Run("increment new reaction", func(t *testing.T) {
|
|
err := reactions.UpdateReference(owner, date, "d1.com", "👍", 1)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("increment existing multiple times", func(t *testing.T) {
|
|
require.NoError(t, reactions.UpdateReference(owner, date, "d1.com", "👍", 2))
|
|
require.NoError(t, reactions.UpdateReference(owner, date, "d1.com", "👍", 3))
|
|
})
|
|
|
|
t.Run("decrement partial", func(t *testing.T) {
|
|
require.NoError(t, reactions.UpdateReference(owner, date, "d1.com", "👍", -2))
|
|
})
|
|
|
|
t.Run("decrement below zero clamps to zero", func(t *testing.T) {
|
|
require.NoError(t, reactions.UpdateReference(owner, date, "d3.net", "🔥", 1))
|
|
require.NoError(t, reactions.UpdateReference(owner, date, "d3.net", "🔥", -10))
|
|
})
|
|
}
|
|
|
|
func TestReactions_ListReactions(t *testing.T) {
|
|
db, cleanup := openDB(t)
|
|
defer cleanup()
|
|
db.reactions.flushInterval = 10 * time.Millisecond
|
|
|
|
reactions := db.Reactions()
|
|
owner := "bob"
|
|
date := time.Now()
|
|
|
|
t.Run("empty reactions", func(t *testing.T) {
|
|
list, err := reactions.ListReactions(owner, date)
|
|
require.NoError(t, err)
|
|
require.Empty(t, list)
|
|
})
|
|
|
|
t.Run("single emoji after flush", func(t *testing.T) {
|
|
require.NoError(t, reactions.UpdateReference(owner, date, "d1.com", "👍", 5))
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
list, err := reactions.ListReactions(owner, date)
|
|
require.NoError(t, err)
|
|
require.Len(t, list, 1)
|
|
require.Equal(t, "👍", list[0].Emoji)
|
|
require.Equal(t, uint64(5), list[0].Count)
|
|
})
|
|
|
|
t.Run("multiple emojis from different domains", func(t *testing.T) {
|
|
require.NoError(t, reactions.UpdateReference(owner, date, "d1.com", "🔥", 3))
|
|
require.NoError(t, reactions.UpdateReference(owner, date, "d2.io", "🔥", 2))
|
|
require.NoError(t, reactions.UpdateReference(owner, date, "d1.com", "❤️", 1))
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
list, err := reactions.ListReactions(owner, date)
|
|
require.NoError(t, err)
|
|
|
|
counts := make(map[string]uint64)
|
|
for _, r := range list {
|
|
counts[r.Emoji] = r.Count
|
|
}
|
|
require.Equal(t, uint64(5), counts["👍"])
|
|
require.Equal(t, uint64(5), counts["🔥"])
|
|
require.Equal(t, uint64(1), counts["❤️"])
|
|
})
|
|
|
|
t.Run("decrement to zero removes emoji", func(t *testing.T) {
|
|
owner2 := "test-delete"
|
|
date2 := time.Now()
|
|
require.NoError(t, reactions.UpdateReference(owner2, date2, "d1.com", "👍", 1))
|
|
require.NoError(t, reactions.UpdateReference(owner2, date2, "d1.com", "👍", -1))
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
list, err := reactions.ListReactions(owner2, date2)
|
|
require.NoError(t, err)
|
|
require.Empty(t, list)
|
|
})
|
|
}
|
|
|
|
func TestReactions_AfterClose(t *testing.T) {
|
|
path := t.TempDir() + "/db"
|
|
db, err := New(path)
|
|
require.NoError(t, err)
|
|
|
|
reactions := db.Reactions()
|
|
err = reactions.SetAllowed("masha", time.Now(), []string{"👍"})
|
|
require.NoError(t, err)
|
|
|
|
require.NoError(t, db.Close())
|
|
|
|
require.NotPanics(t, func() {
|
|
reactions.SetAllowed("masha", time.Now(), []string{"👍"})
|
|
reactions.GetAllowed("masha", time.Now())
|
|
reactions.Add("masha", "bob", "d2.io", time.Now(), "👍", nil)
|
|
reactions.Remove("masha", "bob", "d2.io", time.Now(), "👍")
|
|
reactions.OfUser("masha", 10, 0)
|
|
reactions.ToContent("bob", "d2.io", time.Now(), 10, 0)
|
|
reactions.UpdateReference("bob", time.Now(), "d1.com", "👍", 1)
|
|
reactions.ListReactions("bob", time.Now())
|
|
})
|
|
}
|