mirror of https://github.com/usememos/memos
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
820 lines
22 KiB
Go
820 lines
22 KiB
Go
package v1
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"google.golang.org/protobuf/types/known/fieldmaskpb"
|
|
|
|
v1pb "github.com/usememos/memos/proto/gen/api/v1"
|
|
)
|
|
|
|
func TestListShortcuts(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
t.Run("ListShortcuts success", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
// Create a user
|
|
user, err := ts.CreateRegularUser(ctx, "testuser")
|
|
require.NoError(t, err)
|
|
|
|
// Set user context
|
|
userCtx := ts.CreateUserContext(ctx, user.Username)
|
|
|
|
// List shortcuts (should be empty initially)
|
|
req := &v1pb.ListShortcutsRequest{
|
|
Parent: fmt.Sprintf("users/%d", user.ID),
|
|
}
|
|
|
|
resp, err := ts.Service.ListShortcuts(userCtx, req)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, resp)
|
|
require.Empty(t, resp.Shortcuts)
|
|
})
|
|
|
|
t.Run("ListShortcuts permission denied for different user", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
// Create two users
|
|
user1, err := ts.CreateRegularUser(ctx, "user1")
|
|
require.NoError(t, err)
|
|
user2, err := ts.CreateRegularUser(ctx, "user2")
|
|
require.NoError(t, err)
|
|
|
|
// Set user1 context but try to list user2's shortcuts
|
|
userCtx := ts.CreateUserContext(ctx, user1.Username)
|
|
|
|
req := &v1pb.ListShortcutsRequest{
|
|
Parent: fmt.Sprintf("users/%d", user2.ID),
|
|
}
|
|
|
|
_, err = ts.Service.ListShortcuts(userCtx, req)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "permission denied")
|
|
})
|
|
|
|
t.Run("ListShortcuts invalid parent format", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
// Create user
|
|
user, err := ts.CreateRegularUser(ctx, "testuser")
|
|
require.NoError(t, err)
|
|
|
|
// Set user context
|
|
userCtx := ts.CreateUserContext(ctx, user.Username)
|
|
|
|
req := &v1pb.ListShortcutsRequest{
|
|
Parent: "invalid-parent-format",
|
|
}
|
|
|
|
_, err = ts.Service.ListShortcuts(userCtx, req)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "invalid user name")
|
|
})
|
|
|
|
t.Run("ListShortcuts unauthenticated", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
req := &v1pb.ListShortcutsRequest{
|
|
Parent: "users/1",
|
|
}
|
|
|
|
_, err := ts.Service.ListShortcuts(ctx, req)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "permission denied")
|
|
})
|
|
}
|
|
|
|
func TestGetShortcut(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
t.Run("GetShortcut success", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
// Create a user
|
|
user, err := ts.CreateRegularUser(ctx, "testuser")
|
|
require.NoError(t, err)
|
|
|
|
// Set user context
|
|
userCtx := ts.CreateUserContext(ctx, user.Username)
|
|
|
|
// First create a shortcut
|
|
createReq := &v1pb.CreateShortcutRequest{
|
|
Parent: fmt.Sprintf("users/%d", user.ID),
|
|
Shortcut: &v1pb.Shortcut{
|
|
Title: "Test Shortcut",
|
|
Filter: "tag in [\"test\"]",
|
|
},
|
|
}
|
|
|
|
created, err := ts.Service.CreateShortcut(userCtx, createReq)
|
|
require.NoError(t, err)
|
|
|
|
// Now get the shortcut
|
|
getReq := &v1pb.GetShortcutRequest{
|
|
Name: created.Name,
|
|
}
|
|
|
|
resp, err := ts.Service.GetShortcut(userCtx, getReq)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, resp)
|
|
require.Equal(t, created.Name, resp.Name)
|
|
require.Equal(t, "Test Shortcut", resp.Title)
|
|
require.Equal(t, "tag in [\"test\"]", resp.Filter)
|
|
})
|
|
|
|
t.Run("GetShortcut permission denied for different user", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
// Create two users
|
|
user1, err := ts.CreateRegularUser(ctx, "user1")
|
|
require.NoError(t, err)
|
|
user2, err := ts.CreateRegularUser(ctx, "user2")
|
|
require.NoError(t, err)
|
|
|
|
// Create shortcut as user1
|
|
user1Ctx := ts.CreateUserContext(ctx, user1.Username)
|
|
createReq := &v1pb.CreateShortcutRequest{
|
|
Parent: fmt.Sprintf("users/%d", user1.ID),
|
|
Shortcut: &v1pb.Shortcut{
|
|
Title: "User1 Shortcut",
|
|
Filter: "tag in [\"user1\"]",
|
|
},
|
|
}
|
|
|
|
created, err := ts.Service.CreateShortcut(user1Ctx, createReq)
|
|
require.NoError(t, err)
|
|
|
|
// Try to get shortcut as user2
|
|
user2Ctx := ts.CreateUserContext(ctx, user2.Username)
|
|
getReq := &v1pb.GetShortcutRequest{
|
|
Name: created.Name,
|
|
}
|
|
|
|
_, err = ts.Service.GetShortcut(user2Ctx, getReq)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "permission denied")
|
|
})
|
|
|
|
t.Run("GetShortcut invalid name format", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
// Create user
|
|
user, err := ts.CreateRegularUser(ctx, "testuser")
|
|
require.NoError(t, err)
|
|
|
|
// Set user context
|
|
userCtx := ts.CreateUserContext(ctx, user.Username)
|
|
|
|
req := &v1pb.GetShortcutRequest{
|
|
Name: "invalid-shortcut-name",
|
|
}
|
|
|
|
_, err = ts.Service.GetShortcut(userCtx, req)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "invalid shortcut name")
|
|
})
|
|
|
|
t.Run("GetShortcut not found", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
// Create user
|
|
user, err := ts.CreateRegularUser(ctx, "testuser")
|
|
require.NoError(t, err)
|
|
|
|
// Set user context
|
|
userCtx := ts.CreateUserContext(ctx, user.Username)
|
|
|
|
req := &v1pb.GetShortcutRequest{
|
|
Name: fmt.Sprintf("users/%d", user.ID) + "/shortcuts/nonexistent",
|
|
}
|
|
|
|
_, err = ts.Service.GetShortcut(userCtx, req)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "not found")
|
|
})
|
|
}
|
|
|
|
func TestCreateShortcut(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
t.Run("CreateShortcut success", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
// Create a user
|
|
user, err := ts.CreateRegularUser(ctx, "testuser")
|
|
require.NoError(t, err)
|
|
|
|
// Set user context
|
|
userCtx := ts.CreateUserContext(ctx, user.Username)
|
|
|
|
req := &v1pb.CreateShortcutRequest{
|
|
Parent: fmt.Sprintf("users/%d", user.ID),
|
|
Shortcut: &v1pb.Shortcut{
|
|
Title: "My Shortcut",
|
|
Filter: "tag in [\"important\"]",
|
|
},
|
|
}
|
|
|
|
resp, err := ts.Service.CreateShortcut(userCtx, req)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, resp)
|
|
require.Equal(t, "My Shortcut", resp.Title)
|
|
require.Equal(t, "tag in [\"important\"]", resp.Filter)
|
|
require.Contains(t, resp.Name, fmt.Sprintf("users/%d/shortcuts/", user.ID))
|
|
|
|
// Verify the shortcut was created by listing
|
|
listReq := &v1pb.ListShortcutsRequest{
|
|
Parent: fmt.Sprintf("users/%d", user.ID),
|
|
}
|
|
|
|
listResp, err := ts.Service.ListShortcuts(userCtx, listReq)
|
|
require.NoError(t, err)
|
|
require.Len(t, listResp.Shortcuts, 1)
|
|
require.Equal(t, "My Shortcut", listResp.Shortcuts[0].Title)
|
|
})
|
|
|
|
t.Run("CreateShortcut permission denied for different user", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
// Create two users
|
|
user1, err := ts.CreateRegularUser(ctx, "user1")
|
|
require.NoError(t, err)
|
|
user2, err := ts.CreateRegularUser(ctx, "user2")
|
|
require.NoError(t, err)
|
|
|
|
// Set user1 context but try to create shortcut for user2
|
|
userCtx := ts.CreateUserContext(ctx, user1.Username)
|
|
|
|
req := &v1pb.CreateShortcutRequest{
|
|
Parent: fmt.Sprintf("users/%d", user2.ID),
|
|
Shortcut: &v1pb.Shortcut{
|
|
Title: "Forbidden Shortcut",
|
|
Filter: "tag in [\"forbidden\"]",
|
|
},
|
|
}
|
|
|
|
_, err = ts.Service.CreateShortcut(userCtx, req)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "permission denied")
|
|
})
|
|
|
|
t.Run("CreateShortcut invalid parent format", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
// Create user
|
|
user, err := ts.CreateRegularUser(ctx, "testuser")
|
|
require.NoError(t, err)
|
|
|
|
// Set user context
|
|
userCtx := ts.CreateUserContext(ctx, user.Username)
|
|
|
|
req := &v1pb.CreateShortcutRequest{
|
|
Parent: "invalid-parent",
|
|
Shortcut: &v1pb.Shortcut{
|
|
Title: "Test Shortcut",
|
|
Filter: "tag in [\"test\"]",
|
|
},
|
|
}
|
|
|
|
_, err = ts.Service.CreateShortcut(userCtx, req)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "invalid user name")
|
|
})
|
|
|
|
t.Run("CreateShortcut invalid filter", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
// Create user
|
|
user, err := ts.CreateRegularUser(ctx, "testuser")
|
|
require.NoError(t, err)
|
|
|
|
// Set user context
|
|
userCtx := ts.CreateUserContext(ctx, user.Username)
|
|
|
|
req := &v1pb.CreateShortcutRequest{
|
|
Parent: fmt.Sprintf("users/%d", user.ID),
|
|
Shortcut: &v1pb.Shortcut{
|
|
Title: "Invalid Filter Shortcut",
|
|
Filter: "invalid||filter))syntax",
|
|
},
|
|
}
|
|
|
|
_, err = ts.Service.CreateShortcut(userCtx, req)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "invalid filter")
|
|
})
|
|
|
|
t.Run("CreateShortcut missing title", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
// Create user
|
|
user, err := ts.CreateRegularUser(ctx, "testuser")
|
|
require.NoError(t, err)
|
|
|
|
// Set user context
|
|
userCtx := ts.CreateUserContext(ctx, user.Username)
|
|
|
|
req := &v1pb.CreateShortcutRequest{
|
|
Parent: fmt.Sprintf("users/%d", user.ID),
|
|
Shortcut: &v1pb.Shortcut{
|
|
Filter: "tag in [\"test\"]",
|
|
},
|
|
}
|
|
|
|
_, err = ts.Service.CreateShortcut(userCtx, req)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "title is required")
|
|
})
|
|
}
|
|
|
|
func TestUpdateShortcut(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
t.Run("UpdateShortcut success", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
// Create a user
|
|
user, err := ts.CreateRegularUser(ctx, "testuser")
|
|
require.NoError(t, err)
|
|
|
|
// Set user context
|
|
userCtx := ts.CreateUserContext(ctx, user.Username)
|
|
|
|
// Create a shortcut first
|
|
createReq := &v1pb.CreateShortcutRequest{
|
|
Parent: fmt.Sprintf("users/%d", user.ID),
|
|
Shortcut: &v1pb.Shortcut{
|
|
Title: "Original Title",
|
|
Filter: "tag in [\"original\"]",
|
|
},
|
|
}
|
|
|
|
created, err := ts.Service.CreateShortcut(userCtx, createReq)
|
|
require.NoError(t, err)
|
|
|
|
// Update the shortcut
|
|
updateReq := &v1pb.UpdateShortcutRequest{
|
|
Shortcut: &v1pb.Shortcut{
|
|
Name: created.Name,
|
|
Title: "Updated Title",
|
|
Filter: "tag in [\"updated\"]",
|
|
},
|
|
UpdateMask: &fieldmaskpb.FieldMask{
|
|
Paths: []string{"title", "filter"},
|
|
},
|
|
}
|
|
|
|
updated, err := ts.Service.UpdateShortcut(userCtx, updateReq)
|
|
require.NoError(t, err)
|
|
require.NotNil(t, updated)
|
|
require.Equal(t, "Updated Title", updated.Title)
|
|
require.Equal(t, "tag in [\"updated\"]", updated.Filter)
|
|
require.Equal(t, created.Name, updated.Name)
|
|
})
|
|
|
|
t.Run("UpdateShortcut permission denied for different user", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
// Create two users
|
|
user1, err := ts.CreateRegularUser(ctx, "user1")
|
|
require.NoError(t, err)
|
|
user2, err := ts.CreateRegularUser(ctx, "user2")
|
|
require.NoError(t, err)
|
|
|
|
// Create shortcut as user1
|
|
user1Ctx := ts.CreateUserContext(ctx, user1.Username)
|
|
createReq := &v1pb.CreateShortcutRequest{
|
|
Parent: fmt.Sprintf("users/%d", user1.ID),
|
|
Shortcut: &v1pb.Shortcut{
|
|
Title: "User1 Shortcut",
|
|
Filter: "tag in [\"user1\"]",
|
|
},
|
|
}
|
|
|
|
created, err := ts.Service.CreateShortcut(user1Ctx, createReq)
|
|
require.NoError(t, err)
|
|
|
|
// Try to update shortcut as user2
|
|
user2Ctx := ts.CreateUserContext(ctx, user2.Username)
|
|
updateReq := &v1pb.UpdateShortcutRequest{
|
|
Shortcut: &v1pb.Shortcut{
|
|
Name: created.Name,
|
|
Title: "Hacked Title",
|
|
Filter: "tag in [\"hacked\"]",
|
|
},
|
|
UpdateMask: &fieldmaskpb.FieldMask{
|
|
Paths: []string{"title", "filter"},
|
|
},
|
|
}
|
|
|
|
_, err = ts.Service.UpdateShortcut(user2Ctx, updateReq)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "permission denied")
|
|
})
|
|
|
|
t.Run("UpdateShortcut missing update mask", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
// Create a user and context for authentication
|
|
user, err := ts.CreateRegularUser(ctx, "testuser")
|
|
require.NoError(t, err)
|
|
userCtx := ts.CreateUserContext(ctx, user.Username)
|
|
|
|
req := &v1pb.UpdateShortcutRequest{
|
|
Shortcut: &v1pb.Shortcut{
|
|
Name: fmt.Sprintf("users/%d/shortcuts/test", user.ID),
|
|
Title: "Updated Title",
|
|
},
|
|
}
|
|
|
|
_, err = ts.Service.UpdateShortcut(userCtx, req)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "update mask is required")
|
|
})
|
|
|
|
t.Run("UpdateShortcut invalid name format", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
req := &v1pb.UpdateShortcutRequest{
|
|
Shortcut: &v1pb.Shortcut{
|
|
Name: "invalid-shortcut-name",
|
|
Title: "Updated Title",
|
|
},
|
|
UpdateMask: &fieldmaskpb.FieldMask{
|
|
Paths: []string{"title"},
|
|
},
|
|
}
|
|
|
|
_, err := ts.Service.UpdateShortcut(ctx, req)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "invalid shortcut name")
|
|
})
|
|
|
|
t.Run("UpdateShortcut invalid filter", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
// Create user
|
|
user, err := ts.CreateRegularUser(ctx, "testuser")
|
|
require.NoError(t, err)
|
|
|
|
// Set user context
|
|
userCtx := ts.CreateUserContext(ctx, user.Username)
|
|
|
|
// Create a shortcut first
|
|
createReq := &v1pb.CreateShortcutRequest{
|
|
Parent: fmt.Sprintf("users/%d", user.ID),
|
|
Shortcut: &v1pb.Shortcut{
|
|
Title: "Test Shortcut",
|
|
Filter: "tag in [\"test\"]",
|
|
},
|
|
}
|
|
|
|
created, err := ts.Service.CreateShortcut(userCtx, createReq)
|
|
require.NoError(t, err)
|
|
|
|
// Try to update with invalid filter
|
|
updateReq := &v1pb.UpdateShortcutRequest{
|
|
Shortcut: &v1pb.Shortcut{
|
|
Name: created.Name,
|
|
Filter: "invalid||filter))syntax",
|
|
},
|
|
UpdateMask: &fieldmaskpb.FieldMask{
|
|
Paths: []string{"filter"},
|
|
},
|
|
}
|
|
|
|
_, err = ts.Service.UpdateShortcut(userCtx, updateReq)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "invalid filter")
|
|
})
|
|
}
|
|
|
|
func TestDeleteShortcut(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
t.Run("DeleteShortcut success", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
// Create a user
|
|
user, err := ts.CreateRegularUser(ctx, "testuser")
|
|
require.NoError(t, err)
|
|
|
|
// Set user context
|
|
userCtx := ts.CreateUserContext(ctx, user.Username)
|
|
|
|
// Create a shortcut first
|
|
createReq := &v1pb.CreateShortcutRequest{
|
|
Parent: fmt.Sprintf("users/%d", user.ID),
|
|
Shortcut: &v1pb.Shortcut{
|
|
Title: "Shortcut to Delete",
|
|
Filter: "tag in [\"delete\"]",
|
|
},
|
|
}
|
|
|
|
created, err := ts.Service.CreateShortcut(userCtx, createReq)
|
|
require.NoError(t, err)
|
|
|
|
// Delete the shortcut
|
|
deleteReq := &v1pb.DeleteShortcutRequest{
|
|
Name: created.Name,
|
|
}
|
|
|
|
_, err = ts.Service.DeleteShortcut(userCtx, deleteReq)
|
|
require.NoError(t, err)
|
|
|
|
// Verify deletion by listing shortcuts
|
|
listReq := &v1pb.ListShortcutsRequest{
|
|
Parent: fmt.Sprintf("users/%d", user.ID),
|
|
}
|
|
|
|
listResp, err := ts.Service.ListShortcuts(userCtx, listReq)
|
|
require.NoError(t, err)
|
|
require.Empty(t, listResp.Shortcuts)
|
|
|
|
// Also verify by trying to get the deleted shortcut
|
|
getReq := &v1pb.GetShortcutRequest{
|
|
Name: created.Name,
|
|
}
|
|
|
|
_, err = ts.Service.GetShortcut(userCtx, getReq)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "not found")
|
|
})
|
|
|
|
t.Run("DeleteShortcut permission denied for different user", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
// Create two users
|
|
user1, err := ts.CreateRegularUser(ctx, "user1")
|
|
require.NoError(t, err)
|
|
user2, err := ts.CreateRegularUser(ctx, "user2")
|
|
require.NoError(t, err)
|
|
|
|
// Create shortcut as user1
|
|
user1Ctx := ts.CreateUserContext(ctx, user1.Username)
|
|
createReq := &v1pb.CreateShortcutRequest{
|
|
Parent: fmt.Sprintf("users/%d", user1.ID),
|
|
Shortcut: &v1pb.Shortcut{
|
|
Title: "User1 Shortcut",
|
|
Filter: "tag in [\"user1\"]",
|
|
},
|
|
}
|
|
|
|
created, err := ts.Service.CreateShortcut(user1Ctx, createReq)
|
|
require.NoError(t, err)
|
|
|
|
// Try to delete shortcut as user2
|
|
user2Ctx := ts.CreateUserContext(ctx, user2.Username)
|
|
deleteReq := &v1pb.DeleteShortcutRequest{
|
|
Name: created.Name,
|
|
}
|
|
|
|
_, err = ts.Service.DeleteShortcut(user2Ctx, deleteReq)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "permission denied")
|
|
})
|
|
|
|
t.Run("DeleteShortcut invalid name format", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
req := &v1pb.DeleteShortcutRequest{
|
|
Name: "invalid-shortcut-name",
|
|
}
|
|
|
|
_, err := ts.Service.DeleteShortcut(ctx, req)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "invalid shortcut name")
|
|
})
|
|
|
|
t.Run("DeleteShortcut not found", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
// Create user
|
|
user, err := ts.CreateRegularUser(ctx, "testuser")
|
|
require.NoError(t, err)
|
|
|
|
// Set user context
|
|
userCtx := ts.CreateUserContext(ctx, user.Username)
|
|
|
|
req := &v1pb.DeleteShortcutRequest{
|
|
Name: fmt.Sprintf("users/%d", user.ID) + "/shortcuts/nonexistent",
|
|
}
|
|
|
|
_, err = ts.Service.DeleteShortcut(userCtx, req)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "not found")
|
|
})
|
|
}
|
|
|
|
func TestShortcutFiltering(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
t.Run("CreateShortcut with valid filters", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
// Create user
|
|
user, err := ts.CreateRegularUser(ctx, "testuser")
|
|
require.NoError(t, err)
|
|
|
|
// Set user context
|
|
userCtx := ts.CreateUserContext(ctx, user.Username)
|
|
|
|
// Test various valid filter formats
|
|
validFilters := []string{
|
|
"tag in [\"work\"]",
|
|
"content.contains(\"meeting\")",
|
|
"tag in [\"work\"] && content.contains(\"meeting\")",
|
|
"tag in [\"work\"] || tag in [\"personal\"]",
|
|
"creator_id == 1",
|
|
"visibility == \"PUBLIC\"",
|
|
"has_task_list == true",
|
|
"has_task_list == false",
|
|
}
|
|
|
|
for i, filter := range validFilters {
|
|
req := &v1pb.CreateShortcutRequest{
|
|
Parent: fmt.Sprintf("users/%d", user.ID),
|
|
Shortcut: &v1pb.Shortcut{
|
|
Title: "Valid Filter " + string(rune(i)),
|
|
Filter: filter,
|
|
},
|
|
}
|
|
|
|
_, err = ts.Service.CreateShortcut(userCtx, req)
|
|
require.NoError(t, err, "Filter should be valid: %s", filter)
|
|
}
|
|
})
|
|
|
|
t.Run("CreateShortcut with invalid filters", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
// Create user
|
|
user, err := ts.CreateRegularUser(ctx, "testuser")
|
|
require.NoError(t, err)
|
|
|
|
// Set user context
|
|
userCtx := ts.CreateUserContext(ctx, user.Username)
|
|
|
|
// Test various invalid filter formats
|
|
invalidFilters := []string{
|
|
"tag in ", // incomplete expression
|
|
"invalid_field @in [\"value\"]", // unknown field
|
|
"tag in [\"work\"] &&", // incomplete expression
|
|
"tag in [\"work\"] || || tag in [\"test\"]", // double operator
|
|
"((tag in [\"work\"]", // unmatched parentheses
|
|
"tag in [\"work\"] && )", // mismatched parentheses
|
|
"tag == \"work\"", // wrong operator (== not supported for tags)
|
|
"tag in work", // missing brackets
|
|
}
|
|
|
|
for _, filter := range invalidFilters {
|
|
req := &v1pb.CreateShortcutRequest{
|
|
Parent: fmt.Sprintf("users/%d", user.ID),
|
|
Shortcut: &v1pb.Shortcut{
|
|
Title: "Invalid Filter Test",
|
|
Filter: filter,
|
|
},
|
|
}
|
|
|
|
_, err = ts.Service.CreateShortcut(userCtx, req)
|
|
require.Error(t, err, "Filter should be invalid: %s", filter)
|
|
require.Contains(t, err.Error(), "invalid filter", "Error should mention invalid filter for: %s", filter)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestShortcutCRUDComplete(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
t.Run("Complete CRUD lifecycle", func(t *testing.T) {
|
|
ts := NewTestService(t)
|
|
defer ts.Cleanup()
|
|
|
|
// Create user
|
|
user, err := ts.CreateRegularUser(ctx, "testuser")
|
|
require.NoError(t, err)
|
|
|
|
// Set user context
|
|
userCtx := ts.CreateUserContext(ctx, user.Username)
|
|
|
|
// 1. Create multiple shortcuts
|
|
shortcut1Req := &v1pb.CreateShortcutRequest{
|
|
Parent: fmt.Sprintf("users/%d", user.ID),
|
|
Shortcut: &v1pb.Shortcut{
|
|
Title: "Work Notes",
|
|
Filter: "tag in [\"work\"]",
|
|
},
|
|
}
|
|
|
|
shortcut2Req := &v1pb.CreateShortcutRequest{
|
|
Parent: fmt.Sprintf("users/%d", user.ID),
|
|
Shortcut: &v1pb.Shortcut{
|
|
Title: "Personal Notes",
|
|
Filter: "tag in [\"personal\"]",
|
|
},
|
|
}
|
|
|
|
created1, err := ts.Service.CreateShortcut(userCtx, shortcut1Req)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "Work Notes", created1.Title)
|
|
|
|
created2, err := ts.Service.CreateShortcut(userCtx, shortcut2Req)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "Personal Notes", created2.Title)
|
|
|
|
// 2. List shortcuts and verify both exist
|
|
listReq := &v1pb.ListShortcutsRequest{
|
|
Parent: fmt.Sprintf("users/%d", user.ID),
|
|
}
|
|
|
|
listResp, err := ts.Service.ListShortcuts(userCtx, listReq)
|
|
require.NoError(t, err)
|
|
require.Len(t, listResp.Shortcuts, 2)
|
|
|
|
// 3. Get individual shortcuts
|
|
getReq1 := &v1pb.GetShortcutRequest{Name: created1.Name}
|
|
getResp1, err := ts.Service.GetShortcut(userCtx, getReq1)
|
|
require.NoError(t, err)
|
|
require.Equal(t, created1.Name, getResp1.Name)
|
|
require.Equal(t, "Work Notes", getResp1.Title)
|
|
|
|
getReq2 := &v1pb.GetShortcutRequest{Name: created2.Name}
|
|
getResp2, err := ts.Service.GetShortcut(userCtx, getReq2)
|
|
require.NoError(t, err)
|
|
require.Equal(t, created2.Name, getResp2.Name)
|
|
require.Equal(t, "Personal Notes", getResp2.Title)
|
|
|
|
// 4. Update one shortcut
|
|
updateReq := &v1pb.UpdateShortcutRequest{
|
|
Shortcut: &v1pb.Shortcut{
|
|
Name: created1.Name,
|
|
Title: "Work & Meeting Notes",
|
|
Filter: "tag in [\"work\"] || tag in [\"meeting\"]",
|
|
},
|
|
UpdateMask: &fieldmaskpb.FieldMask{
|
|
Paths: []string{"title", "filter"},
|
|
},
|
|
}
|
|
|
|
updated, err := ts.Service.UpdateShortcut(userCtx, updateReq)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "Work & Meeting Notes", updated.Title)
|
|
require.Equal(t, "tag in [\"work\"] || tag in [\"meeting\"]", updated.Filter)
|
|
|
|
// 5. Verify update by getting it again
|
|
getUpdatedReq := &v1pb.GetShortcutRequest{Name: created1.Name}
|
|
getUpdatedResp, err := ts.Service.GetShortcut(userCtx, getUpdatedReq)
|
|
require.NoError(t, err)
|
|
require.Equal(t, "Work & Meeting Notes", getUpdatedResp.Title)
|
|
require.Equal(t, "tag in [\"work\"] || tag in [\"meeting\"]", getUpdatedResp.Filter)
|
|
|
|
// 6. Delete one shortcut
|
|
deleteReq := &v1pb.DeleteShortcutRequest{
|
|
Name: created2.Name,
|
|
}
|
|
|
|
_, err = ts.Service.DeleteShortcut(userCtx, deleteReq)
|
|
require.NoError(t, err)
|
|
|
|
// 7. Verify deletion by listing (should only have 1 left)
|
|
finalListResp, err := ts.Service.ListShortcuts(userCtx, listReq)
|
|
require.NoError(t, err)
|
|
require.Len(t, finalListResp.Shortcuts, 1)
|
|
require.Equal(t, "Work & Meeting Notes", finalListResp.Shortcuts[0].Title)
|
|
|
|
// 8. Verify deleted shortcut can't be accessed
|
|
getDeletedReq := &v1pb.GetShortcutRequest{Name: created2.Name}
|
|
_, err = ts.Service.GetShortcut(userCtx, getDeletedReq)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "not found")
|
|
})
|
|
}
|