summaryrefslogtreecommitdiff
path: root/srv/src/post/store_test.go
diff options
context:
space:
mode:
authorBrian Picciano <mediocregopher@gmail.com>2022-05-06 17:22:17 -0600
committerBrian Picciano <mediocregopher@gmail.com>2022-05-06 17:22:21 -0600
commitf7d72adfb594980b0442c0fa7b5586e6248f96ac (patch)
tree05f3e80c1f8fc79b3ae67f886534681ddc8c0b62 /srv/src/post/store_test.go
parentd8b12cf17a43e700d841402f712efa8666e6137f (diff)
Implement post.Store
Diffstat (limited to 'srv/src/post/store_test.go')
-rw-r--r--srv/src/post/store_test.go248
1 files changed, 248 insertions, 0 deletions
diff --git a/srv/src/post/store_test.go b/srv/src/post/store_test.go
new file mode 100644
index 0000000..1890511
--- /dev/null
+++ b/srv/src/post/store_test.go
@@ -0,0 +1,248 @@
+package post
+
+import (
+ "io/ioutil"
+ "os"
+ "sort"
+ "strconv"
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/tilinna/clock"
+)
+
+func testPost(i int) Post {
+ istr := strconv.Itoa(i)
+ return Post{
+ ID: istr,
+ Title: istr,
+ Description: istr,
+ Body: istr,
+ }
+}
+
+type storeTestHarness struct {
+ clock *clock.Mock
+ store Store
+}
+
+func newStoreTestHarness(t *testing.T) storeTestHarness {
+
+ clock := clock.NewMock(time.Now().Truncate(1 * time.Hour))
+
+ tmpFile, err := ioutil.TempFile(os.TempDir(), "mediocre-blog-post-store-test-")
+ if err != nil {
+ t.Fatal("Cannot create temporary file", err)
+ }
+ tmpFilePath := tmpFile.Name()
+ tmpFile.Close()
+
+ t.Logf("using temporary sqlite file at %q", tmpFilePath)
+
+ t.Cleanup(func() {
+ if err := os.Remove(tmpFilePath); err != nil {
+ panic(err)
+ }
+ })
+
+ store, err := NewStore(StoreParams{
+ DBFilePath: tmpFilePath,
+ Clock: clock,
+ })
+ assert.NoError(t, err)
+
+ t.Cleanup(func() {
+ assert.NoError(t, store.Close())
+ })
+
+ return storeTestHarness{
+ clock: clock,
+ store: store,
+ }
+}
+
+func (h *storeTestHarness) testStoredPost(i int) StoredPost {
+ post := testPost(i)
+ return StoredPost{
+ Post: post,
+ PublishedAt: DateFromTime(h.clock.Now()),
+ }
+}
+
+func TestStore(t *testing.T) {
+
+ assertPostEqual := func(t *testing.T, exp, got StoredPost) {
+ t.Helper()
+ sort.Strings(exp.Tags)
+ sort.Strings(got.Tags)
+ assert.Equal(t, exp, got)
+ }
+
+ assertPostsEqual := func(t *testing.T, exp, got []StoredPost) {
+ t.Helper()
+
+ if !assert.Len(t, got, len(exp), "exp:%+v\ngot: %+v", exp, got) {
+ return
+ }
+
+ for i := range exp {
+ assertPostEqual(t, exp[i], got[i])
+ }
+ }
+
+ t.Run("not_found", func(t *testing.T) {
+ h := newStoreTestHarness(t)
+
+ _, err := h.store.GetByID("foo")
+ assert.ErrorIs(t, err, ErrNotFound)
+ })
+
+ t.Run("set_get_delete", func(t *testing.T) {
+ h := newStoreTestHarness(t)
+
+ nowDate := DateFromTime(h.clock.Now())
+
+ post := testPost(0)
+ post.Tags = []string{"foo", "bar"}
+
+ assert.NoError(t, h.store.Set(post))
+
+ gotPost, err := h.store.GetByID(post.ID)
+ assert.NoError(t, err)
+
+ assertPostEqual(t, StoredPost{
+ Post: post,
+ PublishedAt: nowDate,
+ }, gotPost)
+
+ // we will now try updating the post on a different day, and ensure it
+ // updates properly
+
+ h.clock.Add(24 * time.Hour)
+ newNowDate := DateFromTime(h.clock.Now())
+
+ post.Title = "something else"
+ post.Series = "whatever"
+ post.Body = "anything"
+ post.Tags = []string{"bar", "baz"}
+
+ assert.NoError(t, h.store.Set(post))
+
+ gotPost, err = h.store.GetByID(post.ID)
+ assert.NoError(t, err)
+
+ assertPostEqual(t, StoredPost{
+ Post: post,
+ PublishedAt: nowDate,
+ LastUpdatedAt: newNowDate,
+ }, gotPost)
+
+ // delete the post, it should go away
+ assert.NoError(t, h.store.Delete(post.ID))
+
+ _, err = h.store.GetByID(post.ID)
+ assert.ErrorIs(t, err, ErrNotFound)
+ })
+
+ t.Run("get", func(t *testing.T) {
+ h := newStoreTestHarness(t)
+
+ posts := []StoredPost{
+ h.testStoredPost(0),
+ h.testStoredPost(1),
+ h.testStoredPost(2),
+ h.testStoredPost(3),
+ }
+
+ for _, post := range posts {
+ assert.NoError(t, h.store.Set(post.Post))
+ }
+
+ gotPosts, hasMore, err := h.store.Get(0, 2)
+ assert.NoError(t, err)
+ assert.True(t, hasMore)
+ assertPostsEqual(t, posts[:2], gotPosts)
+
+ gotPosts, hasMore, err = h.store.Get(1, 2)
+ assert.NoError(t, err)
+ assert.False(t, hasMore)
+ assertPostsEqual(t, posts[2:4], gotPosts)
+
+ posts = append(posts, h.testStoredPost(4))
+ assert.NoError(t, h.store.Set(posts[4].Post))
+
+ gotPosts, hasMore, err = h.store.Get(1, 2)
+ assert.NoError(t, err)
+ assert.True(t, hasMore)
+ assertPostsEqual(t, posts[2:4], gotPosts)
+
+ gotPosts, hasMore, err = h.store.Get(2, 2)
+ assert.NoError(t, err)
+ assert.False(t, hasMore)
+ assertPostsEqual(t, posts[4:], gotPosts)
+ })
+
+ t.Run("get_by_series", func(t *testing.T) {
+ h := newStoreTestHarness(t)
+
+ posts := []StoredPost{
+ h.testStoredPost(0),
+ h.testStoredPost(1),
+ h.testStoredPost(2),
+ h.testStoredPost(3),
+ }
+
+ posts[0].Series = "foo"
+ posts[1].Series = "bar"
+ posts[2].Series = "bar"
+
+ for _, post := range posts {
+ assert.NoError(t, h.store.Set(post.Post))
+ }
+
+ fooPosts, err := h.store.GetBySeries("foo")
+ assert.NoError(t, err)
+ assertPostsEqual(t, posts[:1], fooPosts)
+
+ barPosts, err := h.store.GetBySeries("bar")
+ assert.NoError(t, err)
+ assertPostsEqual(t, posts[1:3], barPosts)
+
+ bazPosts, err := h.store.GetBySeries("baz")
+ assert.NoError(t, err)
+ assert.Empty(t, bazPosts)
+ })
+
+ t.Run("get_by_tag", func(t *testing.T) {
+
+ h := newStoreTestHarness(t)
+
+ posts := []StoredPost{
+ h.testStoredPost(0),
+ h.testStoredPost(1),
+ h.testStoredPost(2),
+ h.testStoredPost(3),
+ }
+
+ posts[0].Tags = []string{"foo"}
+ posts[1].Tags = []string{"foo", "bar"}
+ posts[2].Tags = []string{"bar"}
+
+ for _, post := range posts {
+ assert.NoError(t, h.store.Set(post.Post))
+ }
+
+ fooPosts, err := h.store.GetByTag("foo")
+ assert.NoError(t, err)
+ assertPostsEqual(t, posts[:2], fooPosts)
+
+ barPosts, err := h.store.GetByTag("bar")
+ assert.NoError(t, err)
+ assertPostsEqual(t, posts[1:3], barPosts)
+
+ bazPosts, err := h.store.GetByTag("baz")
+ assert.NoError(t, err)
+ assert.Empty(t, bazPosts)
+ })
+}