From e2454a8ae420866745dbb75ff76ccf6c7241721d Mon Sep 17 00:00:00 2001 From: varsnotwars Date: Tue, 19 Aug 2025 23:57:38 +1000 Subject: [PATCH] chore: add test for ListMemos (#5015) --- .../router/api/v1/test/memo_service_test.go | 252 ++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 server/router/api/v1/test/memo_service_test.go diff --git a/server/router/api/v1/test/memo_service_test.go b/server/router/api/v1/test/memo_service_test.go new file mode 100644 index 000000000..c968c2327 --- /dev/null +++ b/server/router/api/v1/test/memo_service_test.go @@ -0,0 +1,252 @@ +package v1 + +import ( + "context" + "fmt" + "slices" + "testing" + + "github.com/stretchr/testify/require" + + apiv1 "github.com/usememos/memos/proto/gen/api/v1" +) + +func TestListMemos(t *testing.T) { + ctx := context.Background() + + ts := NewTestService(t) + defer ts.Cleanup() + + // Create userOne + userOne, err := ts.CreateRegularUser(ctx, "test-user-1") + require.NoError(t, err) + require.NotNil(t, userOne) + + // Create userOne context + userOneCtx := ts.CreateUserContext(ctx, userOne.ID) + + // Create userTwo + userTwo, err := ts.CreateRegularUser(ctx, "test-user-2") + require.NoError(t, err) + require.NotNil(t, userTwo) + + // Create userTwo context + userTwoCtx := ts.CreateUserContext(ctx, userTwo.ID) + + // Create attachmentOne by userOne + attachmentOne, err := ts.Service.CreateAttachment(userOneCtx, &apiv1.CreateAttachmentRequest{ + Attachment: &apiv1.Attachment{ + Name: "", + Filename: "hello.txt", + Size: 5, + Type: "text/plain", + Content: []byte{ + 104, 101, 108, 108, 111, + }, + }, + }) + + require.NoError(t, err) + require.NotNil(t, attachmentOne) + + // Create attachmentTwo by userOne + attachmentTwo, err := ts.Service.CreateAttachment(userOneCtx, &apiv1.CreateAttachmentRequest{ + Attachment: &apiv1.Attachment{ + Name: "", + Filename: "world.txt", + Size: 5, + Type: "text/plain", + Content: []byte{ + 119, 111, 114, 108, 100, + }, + }, + }) + + require.NoError(t, err) + require.NotNil(t, attachmentTwo) + + // Create memoOne with two attachments by userOne + memoOne, err := ts.Service.CreateMemo(userOneCtx, &apiv1.CreateMemoRequest{ + Memo: &apiv1.Memo{ + Content: "Hellooo, any words after this sentence won't be in the snippet. This is the next sentence. And I also have two attachments.", + Visibility: apiv1.Visibility_PROTECTED, + Attachments: []*apiv1.Attachment{ + &apiv1.Attachment{ + Name: attachmentOne.Name, + }, + &apiv1.Attachment{ + Name: attachmentTwo.Name, + }, + }, + }, + }) + + require.NoError(t, err) + require.NotNil(t, memoOne) + + // Create memoTwo by userTwo referencing memoOne + memoTwo, err := ts.Service.CreateMemo(userTwoCtx, &apiv1.CreateMemoRequest{ + Memo: &apiv1.Memo{ + Content: "This is a memo reminding you to check the attachment attached to memoOne. I have referenced the memo below.⬇️", + Visibility: apiv1.Visibility_PROTECTED, + Relations: []*apiv1.MemoRelation{ + &apiv1.MemoRelation{ + RelatedMemo: &apiv1.MemoRelation_Memo{ + Name: memoOne.Name, + }, + }, + }, + }, + }) + + require.NoError(t, err) + require.NotNil(t, memoTwo) + + // Create memoThree by userOne + memoThree, err := ts.Service.CreateMemo(userOneCtx, &apiv1.CreateMemoRequest{ + Memo: &apiv1.Memo{ + Content: "This is a very popular memo. I have 2 reactions!", + Visibility: apiv1.Visibility_PROTECTED, + }, + }) + + require.NoError(t, err) + require.NotNil(t, memoThree) + + // Create reaction from userOne on memoThree + reactionOne, err := ts.Service.UpsertMemoReaction(userOneCtx, &apiv1.UpsertMemoReactionRequest{ + Name: memoThree.Name, + Reaction: &apiv1.Reaction{ + ContentId: memoThree.Name, + ReactionType: "❤️", + }, + }) + + require.NoError(t, err) + require.NotNil(t, reactionOne) + + // Create reaction from userTwo on memoThree + reactionTwo, err := ts.Service.UpsertMemoReaction(userTwoCtx, &apiv1.UpsertMemoReactionRequest{ + Name: memoThree.Name, + Reaction: &apiv1.Reaction{ + ContentId: memoThree.Name, + ReactionType: "👍", + }, + }) + + require.NoError(t, err) + require.NotNil(t, reactionTwo) + + memos, err := ts.Service.ListMemos(userOneCtx, &apiv1.ListMemosRequest{PageSize: 10}) + + require.NoError(t, err) + require.NotNil(t, memos) + require.Equal(t, 3, len(memos.Memos)) + + // /////////////// + // VERIFY MEMO ONE + // /////////////// + memoOneResIdx := slices.IndexFunc(memos.Memos, func(m *apiv1.Memo) bool { return m.GetName() == memoOne.GetName() }) + require.NotEqual(t, memoOneResIdx, -1) + + memoOneRes := memos.Memos[memoOneResIdx] + require.NotNil(t, memoOneRes) + + require.Equal(t, fmt.Sprintf("users/%d", userOne.ID), memoOneRes.GetCreator()) + require.Equal(t, apiv1.Visibility_PROTECTED, memoOneRes.GetVisibility()) + require.Equal(t, memoOne.Content, memoOneRes.GetContent()) + require.Equal(t, memoOne.Content[:64]+"...", memoOneRes.GetSnippet(), "memoOne's content is snipped past the 64 char limit") + require.Len(t, memoOneRes.Attachments, 2) + require.Len(t, memoOneRes.Relations, 1) + require.Empty(t, memoOneRes.Reactions) + + // verify memoOne's attachments + // attachment one + attachmentOneResIdx := slices.IndexFunc(memoOneRes.Attachments, func(a *apiv1.Attachment) bool { return a.GetName() == attachmentOne.GetName() }) + require.NotEqual(t, attachmentOneResIdx, -1) + + attachmentOneRes := memoOneRes.Attachments[attachmentOneResIdx] + require.NotNil(t, attachmentOneRes) + + require.Equal(t, attachmentOne.GetName(), attachmentOneRes.GetName()) + require.Equal(t, attachmentOne.GetContent(), attachmentOneRes.GetContent()) + + // attachment two + attachmentTwoResIdx := slices.IndexFunc(memoOneRes.Attachments, func(a *apiv1.Attachment) bool { return a.GetName() == attachmentTwo.GetName() }) + require.NotEqual(t, attachmentTwoResIdx, -1) + + attachmentTwoRes := memoOneRes.Attachments[attachmentTwoResIdx] + require.NotNil(t, attachmentTwoRes) + require.Equal(t, attachmentTwo.GetName(), attachmentTwoRes.GetName()) + + require.Equal(t, attachmentTwo.GetName(), attachmentTwoRes.GetName()) + require.Equal(t, attachmentTwo.GetContent(), attachmentTwoRes.GetContent()) + + // verify memoOne's relations + require.Len(t, memoOneRes.Relations, 1) + memoOneExpectedRelation := &apiv1.MemoRelation{ + Memo: &apiv1.MemoRelation_Memo{Name: memoTwo.GetName()}, + RelatedMemo: &apiv1.MemoRelation_Memo{Name: memoOne.GetName()}, + } + require.Equal(t, memoOneExpectedRelation.Memo.GetName(), memoOneRes.Relations[0].Memo.GetName()) + require.Equal(t, memoOneExpectedRelation.RelatedMemo.GetName(), memoOneRes.Relations[0].RelatedMemo.GetName()) + + // /////////////// + // VERIFY MEMO TWO + // /////////////// + memoTwoResIdx := slices.IndexFunc(memos.Memos, func(m *apiv1.Memo) bool { return m.GetName() == memoTwo.GetName() }) + require.NotEqual(t, memoTwoResIdx, -1) + + memoTwoRes := memos.Memos[memoTwoResIdx] + require.NotNil(t, memoTwoRes) + + require.Equal(t, fmt.Sprintf("users/%d", userTwo.ID), memoTwoRes.GetCreator()) + require.Equal(t, apiv1.Visibility_PROTECTED, memoTwoRes.GetVisibility()) + require.Equal(t, memoTwo.Content, memoTwoRes.GetContent()) + require.Empty(t, memoTwoRes.Attachments) + require.Len(t, memoTwoRes.Relations, 1) + require.Empty(t, memoTwoRes.Reactions) + + // verify memoTwo's relations + require.Len(t, memoTwoRes.Relations, 1) + memoTwoExpectedRelation := &apiv1.MemoRelation{ + Memo: &apiv1.MemoRelation_Memo{Name: memoTwo.GetName()}, + RelatedMemo: &apiv1.MemoRelation_Memo{Name: memoOne.GetName()}, + } + require.Equal(t, memoTwoExpectedRelation.Memo.GetName(), memoTwoRes.Relations[0].Memo.GetName()) + require.Equal(t, memoTwoExpectedRelation.RelatedMemo.GetName(), memoTwoRes.Relations[0].RelatedMemo.GetName()) + + // /////////////// + // VERIFY MEMO THREE + // /////////////// + memoThreeResIdx := slices.IndexFunc(memos.Memos, func(m *apiv1.Memo) bool { return m.GetName() == memoThree.GetName() }) + require.NotEqual(t, memoThreeResIdx, -1) + + memoThreeRes := memos.Memos[memoThreeResIdx] + require.NotNil(t, memoThreeRes) + + require.Equal(t, fmt.Sprintf("users/%d", userOne.ID), memoThreeRes.GetCreator()) + require.Equal(t, apiv1.Visibility_PROTECTED, memoThreeRes.GetVisibility()) + require.Equal(t, memoThree.Content, memoThreeRes.GetContent()) + require.Empty(t, memoThreeRes.Attachments) + require.Empty(t, memoThreeRes.Relations) + require.Len(t, memoThreeRes.Reactions, 2) + + // verify memoThree's reactions + require.Len(t, memoThreeRes.Reactions, 2) + // userOne's reaction + userOneReactionIdx := slices.IndexFunc(memoThreeRes.Reactions, func(r *apiv1.Reaction) bool { return r.GetCreator() == fmt.Sprintf("users/%d", userOne.ID) }) + require.NotEqual(t, userOneReactionIdx, -1) + + userOneReaction := memoThreeRes.Reactions[userOneReactionIdx] + require.NotNil(t, userOneReaction) + require.Equal(t, "❤️", userOneReaction.ReactionType) + + // userTwo's reaction + userTwoReactionIdx := slices.IndexFunc(memoThreeRes.Reactions, func(r *apiv1.Reaction) bool { return r.GetCreator() == fmt.Sprintf("users/%d", userTwo.ID) }) + require.NotEqual(t, userTwoReactionIdx, -1) + + userTwoReaction := memoThreeRes.Reactions[userTwoReactionIdx] + require.NotNil(t, userTwoReaction) + require.Equal(t, "👍", userTwoReaction.ReactionType) +}