memos/store/test/memo_test.go

409 lines
10 KiB
Go

package test
import (
"context"
"fmt"
"testing"
"github.com/stretchr/testify/require"
"github.com/usememos/memos/store"
storepb "github.com/usememos/memos/proto/gen/store"
)
func TestMemoStore(t *testing.T) {
ctx := context.Background()
ts := NewTestingStore(ctx, t)
user, err := createTestingHostUser(ctx, ts)
require.NoError(t, err)
memoCreate := &store.Memo{
UID: "test-resource-name",
CreatorID: user.ID,
Content: "test_content",
Visibility: store.Public,
}
memo, err := ts.CreateMemo(ctx, memoCreate)
require.NoError(t, err)
require.Equal(t, memoCreate.Content, memo.Content)
memoPatchContent := "test_content_2"
memoPatch := &store.UpdateMemo{
ID: memo.ID,
Content: &memoPatchContent,
}
err = ts.UpdateMemo(ctx, memoPatch)
require.NoError(t, err)
memo, err = ts.GetMemo(ctx, &store.FindMemo{
ID: &memo.ID,
})
require.NoError(t, err)
require.NotNil(t, memo)
memoList, err := ts.ListMemos(ctx, &store.FindMemo{
CreatorID: &user.ID,
})
require.NoError(t, err)
require.Equal(t, 1, len(memoList))
require.Equal(t, memo, memoList[0])
err = ts.DeleteMemo(ctx, &store.DeleteMemo{
ID: memo.ID,
})
require.NoError(t, err)
memoList, err = ts.ListMemos(ctx, &store.FindMemo{
CreatorID: &user.ID,
})
require.NoError(t, err)
require.Equal(t, 0, len(memoList))
memoList, err = ts.ListMemos(ctx, &store.FindMemo{
CreatorID: &user.ID,
VisibilityList: []store.Visibility{store.Public},
})
require.NoError(t, err)
require.Equal(t, 0, len(memoList))
ts.Close()
}
func TestMemoListByTags(t *testing.T) {
ctx := context.Background()
ts := NewTestingStore(ctx, t)
user, err := createTestingHostUser(ctx, ts)
require.NoError(t, err)
memoCreate := &store.Memo{
UID: "test-resource-name",
CreatorID: user.ID,
Content: "test_content",
Visibility: store.Public,
Payload: &storepb.MemoPayload{
Tags: []string{"test_tag"},
},
}
memo, err := ts.CreateMemo(ctx, memoCreate)
require.NoError(t, err)
require.Equal(t, memoCreate.Content, memo.Content)
memo, err = ts.GetMemo(ctx, &store.FindMemo{
ID: &memo.ID,
})
require.NoError(t, err)
require.NotNil(t, memo)
memoList, err := ts.ListMemos(ctx, &store.FindMemo{
Filters: []string{"tag in [\"test_tag\"]"},
})
require.NoError(t, err)
require.Equal(t, 1, len(memoList))
require.Equal(t, memo, memoList[0])
ts.Close()
}
func TestDeleteMemoStore(t *testing.T) {
ctx := context.Background()
ts := NewTestingStore(ctx, t)
user, err := createTestingHostUser(ctx, ts)
require.NoError(t, err)
memoCreate := &store.Memo{
UID: "test-resource-name",
CreatorID: user.ID,
Content: "test_content",
Visibility: store.Public,
}
memo, err := ts.CreateMemo(ctx, memoCreate)
require.NoError(t, err)
require.Equal(t, memoCreate.Content, memo.Content)
err = ts.DeleteMemo(ctx, &store.DeleteMemo{
ID: memo.ID,
})
require.NoError(t, err)
ts.Close()
}
func TestMemoGetByID(t *testing.T) {
ctx := context.Background()
ts := NewTestingStore(ctx, t)
user, err := createTestingHostUser(ctx, ts)
require.NoError(t, err)
memo, err := ts.CreateMemo(ctx, &store.Memo{
UID: "test-memo-1",
CreatorID: user.ID,
Content: "test content",
Visibility: store.Public,
})
require.NoError(t, err)
// Get by ID
found, err := ts.GetMemo(ctx, &store.FindMemo{ID: &memo.ID})
require.NoError(t, err)
require.NotNil(t, found)
require.Equal(t, memo.ID, found.ID)
require.Equal(t, memo.Content, found.Content)
// Get non-existent
nonExistentID := int32(99999)
notFound, err := ts.GetMemo(ctx, &store.FindMemo{ID: &nonExistentID})
require.NoError(t, err)
require.Nil(t, notFound)
ts.Close()
}
func TestMemoGetByUID(t *testing.T) {
ctx := context.Background()
ts := NewTestingStore(ctx, t)
user, err := createTestingHostUser(ctx, ts)
require.NoError(t, err)
uid := "unique-memo-uid"
memo, err := ts.CreateMemo(ctx, &store.Memo{
UID: uid,
CreatorID: user.ID,
Content: "test content",
Visibility: store.Public,
})
require.NoError(t, err)
// Get by UID
found, err := ts.GetMemo(ctx, &store.FindMemo{UID: &uid})
require.NoError(t, err)
require.NotNil(t, found)
require.Equal(t, memo.UID, found.UID)
// Get non-existent UID
nonExistentUID := "non-existent-uid"
notFound, err := ts.GetMemo(ctx, &store.FindMemo{UID: &nonExistentUID})
require.NoError(t, err)
require.Nil(t, notFound)
ts.Close()
}
func TestMemoListByVisibility(t *testing.T) {
ctx := context.Background()
ts := NewTestingStore(ctx, t)
user, err := createTestingHostUser(ctx, ts)
require.NoError(t, err)
// Create memos with different visibilities
_, err = ts.CreateMemo(ctx, &store.Memo{
UID: "public-memo",
CreatorID: user.ID,
Content: "public content",
Visibility: store.Public,
})
require.NoError(t, err)
_, err = ts.CreateMemo(ctx, &store.Memo{
UID: "protected-memo",
CreatorID: user.ID,
Content: "protected content",
Visibility: store.Protected,
})
require.NoError(t, err)
_, err = ts.CreateMemo(ctx, &store.Memo{
UID: "private-memo",
CreatorID: user.ID,
Content: "private content",
Visibility: store.Private,
})
require.NoError(t, err)
// List public memos only
publicMemos, err := ts.ListMemos(ctx, &store.FindMemo{
VisibilityList: []store.Visibility{store.Public},
})
require.NoError(t, err)
require.Equal(t, 1, len(publicMemos))
require.Equal(t, store.Public, publicMemos[0].Visibility)
// List protected memos only
protectedMemos, err := ts.ListMemos(ctx, &store.FindMemo{
VisibilityList: []store.Visibility{store.Protected},
})
require.NoError(t, err)
require.Equal(t, 1, len(protectedMemos))
require.Equal(t, store.Protected, protectedMemos[0].Visibility)
// List public and protected (multiple visibility)
publicAndProtected, err := ts.ListMemos(ctx, &store.FindMemo{
VisibilityList: []store.Visibility{store.Public, store.Protected},
})
require.NoError(t, err)
require.Equal(t, 2, len(publicAndProtected))
// List all
allMemos, err := ts.ListMemos(ctx, &store.FindMemo{})
require.NoError(t, err)
require.Equal(t, 3, len(allMemos))
ts.Close()
}
func TestMemoListWithPagination(t *testing.T) {
ctx := context.Background()
ts := NewTestingStore(ctx, t)
user, err := createTestingHostUser(ctx, ts)
require.NoError(t, err)
// Create 10 memos
for i := 0; i < 10; i++ {
_, err := ts.CreateMemo(ctx, &store.Memo{
UID: fmt.Sprintf("memo-%d", i),
CreatorID: user.ID,
Content: fmt.Sprintf("content %d", i),
Visibility: store.Public,
})
require.NoError(t, err)
}
// Test limit
limit := 5
limitedMemos, err := ts.ListMemos(ctx, &store.FindMemo{Limit: &limit})
require.NoError(t, err)
require.Equal(t, 5, len(limitedMemos))
// Test offset
offset := 3
offsetMemos, err := ts.ListMemos(ctx, &store.FindMemo{Limit: &limit, Offset: &offset})
require.NoError(t, err)
require.Equal(t, 5, len(offsetMemos))
// Verify offset works correctly (different memos)
require.NotEqual(t, limitedMemos[0].ID, offsetMemos[0].ID)
ts.Close()
}
func TestMemoUpdatePinned(t *testing.T) {
ctx := context.Background()
ts := NewTestingStore(ctx, t)
user, err := createTestingHostUser(ctx, ts)
require.NoError(t, err)
memo, err := ts.CreateMemo(ctx, &store.Memo{
UID: "pinnable-memo",
CreatorID: user.ID,
Content: "content",
Visibility: store.Public,
})
require.NoError(t, err)
require.False(t, memo.Pinned)
// Pin the memo
pinned := true
err = ts.UpdateMemo(ctx, &store.UpdateMemo{
ID: memo.ID,
Pinned: &pinned,
})
require.NoError(t, err)
// Verify pinned
found, err := ts.GetMemo(ctx, &store.FindMemo{ID: &memo.ID})
require.NoError(t, err)
require.True(t, found.Pinned)
// Unpin
unpinned := false
err = ts.UpdateMemo(ctx, &store.UpdateMemo{
ID: memo.ID,
Pinned: &unpinned,
})
require.NoError(t, err)
found, err = ts.GetMemo(ctx, &store.FindMemo{ID: &memo.ID})
require.NoError(t, err)
require.False(t, found.Pinned)
ts.Close()
}
func TestMemoUpdateVisibility(t *testing.T) {
ctx := context.Background()
ts := NewTestingStore(ctx, t)
user, err := createTestingHostUser(ctx, ts)
require.NoError(t, err)
memo, err := ts.CreateMemo(ctx, &store.Memo{
UID: "visibility-memo",
CreatorID: user.ID,
Content: "content",
Visibility: store.Public,
})
require.NoError(t, err)
require.Equal(t, store.Public, memo.Visibility)
// Change to private
privateVisibility := store.Private
err = ts.UpdateMemo(ctx, &store.UpdateMemo{
ID: memo.ID,
Visibility: &privateVisibility,
})
require.NoError(t, err)
found, err := ts.GetMemo(ctx, &store.FindMemo{ID: &memo.ID})
require.NoError(t, err)
require.Equal(t, store.Private, found.Visibility)
// Change to protected
protectedVisibility := store.Protected
err = ts.UpdateMemo(ctx, &store.UpdateMemo{
ID: memo.ID,
Visibility: &protectedVisibility,
})
require.NoError(t, err)
found, err = ts.GetMemo(ctx, &store.FindMemo{ID: &memo.ID})
require.NoError(t, err)
require.Equal(t, store.Protected, found.Visibility)
ts.Close()
}
func TestMemoInvalidUID(t *testing.T) {
ctx := context.Background()
ts := NewTestingStore(ctx, t)
user, err := createTestingHostUser(ctx, ts)
require.NoError(t, err)
// Create memo with invalid UID (contains special characters)
_, err = ts.CreateMemo(ctx, &store.Memo{
UID: "invalid uid with spaces",
CreatorID: user.ID,
Content: "content",
Visibility: store.Public,
})
require.Error(t, err)
require.Contains(t, err.Error(), "invalid uid")
ts.Close()
}
func TestMemoWithPayload(t *testing.T) {
ctx := context.Background()
ts := NewTestingStore(ctx, t)
user, err := createTestingHostUser(ctx, ts)
require.NoError(t, err)
// Create memo with tags in payload
tags := []string{"tag1", "tag2", "tag3"}
memo, err := ts.CreateMemo(ctx, &store.Memo{
UID: "memo-with-payload",
CreatorID: user.ID,
Content: "content with tags",
Visibility: store.Public,
Payload: &storepb.MemoPayload{
Tags: tags,
},
})
require.NoError(t, err)
require.NotNil(t, memo.Payload)
require.Equal(t, tags, memo.Payload.Tags)
// Fetch and verify
found, err := ts.GetMemo(ctx, &store.FindMemo{ID: &memo.ID})
require.NoError(t, err)
require.NotNil(t, found.Payload)
require.Equal(t, tags, found.Payload.Tags)
ts.Close()
}