mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-04-26 19:25:09 +00:00
334 lines
8.4 KiB
Go
334 lines
8.4 KiB
Go
package pds
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"atcr.io/pkg/atproto"
|
|
bsky "github.com/bluesky-social/indigo/api/bsky"
|
|
)
|
|
|
|
func TestPostMentionsUser(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
post *bsky.FeedPost
|
|
userDID string
|
|
expected bool
|
|
}{
|
|
{
|
|
name: "post mentions user",
|
|
post: &bsky.FeedPost{
|
|
Text: "@alice.bsky.social pushed myapp:latest",
|
|
Facets: []*bsky.RichtextFacet{{
|
|
Index: &bsky.RichtextFacet_ByteSlice{
|
|
ByteStart: 0,
|
|
ByteEnd: 20,
|
|
},
|
|
Features: []*bsky.RichtextFacet_Features_Elem{{
|
|
RichtextFacet_Mention: &bsky.RichtextFacet_Mention{
|
|
Did: "did:plc:alice123",
|
|
},
|
|
}},
|
|
}},
|
|
},
|
|
userDID: "did:plc:alice123",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "post mentions different user",
|
|
post: &bsky.FeedPost{
|
|
Text: "@bob.bsky.social pushed myapp:latest",
|
|
Facets: []*bsky.RichtextFacet{{
|
|
Index: &bsky.RichtextFacet_ByteSlice{
|
|
ByteStart: 0,
|
|
ByteEnd: 18,
|
|
},
|
|
Features: []*bsky.RichtextFacet_Features_Elem{{
|
|
RichtextFacet_Mention: &bsky.RichtextFacet_Mention{
|
|
Did: "did:plc:bob456",
|
|
},
|
|
}},
|
|
}},
|
|
},
|
|
userDID: "did:plc:alice123",
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "post with no facets",
|
|
post: &bsky.FeedPost{
|
|
Text: "Just a regular post",
|
|
Facets: nil,
|
|
},
|
|
userDID: "did:plc:alice123",
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "post with empty facets",
|
|
post: &bsky.FeedPost{
|
|
Text: "Just a regular post",
|
|
Facets: []*bsky.RichtextFacet{},
|
|
},
|
|
userDID: "did:plc:alice123",
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "post with link facet only (no mention)",
|
|
post: &bsky.FeedPost{
|
|
Text: "Check out https://example.com",
|
|
Facets: []*bsky.RichtextFacet{{
|
|
Index: &bsky.RichtextFacet_ByteSlice{
|
|
ByteStart: 10,
|
|
ByteEnd: 30,
|
|
},
|
|
Features: []*bsky.RichtextFacet_Features_Elem{{
|
|
RichtextFacet_Link: &bsky.RichtextFacet_Link{
|
|
Uri: "https://example.com",
|
|
},
|
|
}},
|
|
}},
|
|
},
|
|
userDID: "did:plc:alice123",
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "post with multiple mentions - match second",
|
|
post: &bsky.FeedPost{
|
|
Text: "@bob.bsky.social and @alice.bsky.social pushed",
|
|
Facets: []*bsky.RichtextFacet{
|
|
{
|
|
Index: &bsky.RichtextFacet_ByteSlice{
|
|
ByteStart: 0,
|
|
ByteEnd: 18,
|
|
},
|
|
Features: []*bsky.RichtextFacet_Features_Elem{{
|
|
RichtextFacet_Mention: &bsky.RichtextFacet_Mention{
|
|
Did: "did:plc:bob456",
|
|
},
|
|
}},
|
|
},
|
|
{
|
|
Index: &bsky.RichtextFacet_ByteSlice{
|
|
ByteStart: 23,
|
|
ByteEnd: 43,
|
|
},
|
|
Features: []*bsky.RichtextFacet_Features_Elem{{
|
|
RichtextFacet_Mention: &bsky.RichtextFacet_Mention{
|
|
Did: "did:plc:alice123",
|
|
},
|
|
}},
|
|
},
|
|
},
|
|
},
|
|
userDID: "did:plc:alice123",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "facet with nil features",
|
|
post: &bsky.FeedPost{
|
|
Text: "Some post",
|
|
Facets: []*bsky.RichtextFacet{{
|
|
Index: &bsky.RichtextFacet_ByteSlice{
|
|
ByteStart: 0,
|
|
ByteEnd: 4,
|
|
},
|
|
Features: nil,
|
|
}},
|
|
},
|
|
userDID: "did:plc:alice123",
|
|
expected: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := postMentionsUser(tt.post, tt.userDID)
|
|
if result != tt.expected {
|
|
t.Errorf("postMentionsUser() = %v, want %v", result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDeleteBlueskyPosts_NoPosts(t *testing.T) {
|
|
// Create a test PDS with records index
|
|
pds := setupTestPDSWithIndex(t, "did:plc:testowner")
|
|
|
|
ctx := sharedCtx
|
|
|
|
// Delete posts for a user that has no posts
|
|
deleted, err := pds.deleteBlueskyPosts(ctx, "did:plc:nonexistent")
|
|
if err != nil {
|
|
t.Fatalf("deleteBlueskyPosts() error = %v", err)
|
|
}
|
|
|
|
if deleted != 0 {
|
|
t.Errorf("deleteBlueskyPosts() deleted = %d, want 0", deleted)
|
|
}
|
|
}
|
|
|
|
func TestListBlueskyPostsForUser_NoPosts(t *testing.T) {
|
|
// Create a test PDS with records index
|
|
pds := setupTestPDSWithIndex(t, "did:plc:testowner")
|
|
|
|
ctx := sharedCtx
|
|
|
|
// List posts for a user that has no posts
|
|
posts, err := pds.ListBlueskyPostsForUser(ctx, "did:plc:nonexistent")
|
|
if err != nil {
|
|
t.Fatalf("ListBlueskyPostsForUser() error = %v", err)
|
|
}
|
|
|
|
if len(posts) != 0 {
|
|
t.Errorf("ListBlueskyPostsForUser() returned %d posts, want 0", len(posts))
|
|
}
|
|
}
|
|
|
|
func TestDeleteAndListBlueskyPosts_WithPosts(t *testing.T) {
|
|
// Create a test PDS with records index
|
|
pds := setupTestPDSWithIndex(t, "did:plc:testowner")
|
|
|
|
ctx := sharedCtx
|
|
|
|
// Create a test post that mentions alice
|
|
aliceDID := "did:plc:alice123"
|
|
post := &bsky.FeedPost{
|
|
LexiconTypeID: atproto.BskyPostCollection,
|
|
Text: "@alice.bsky.social pushed myapp:latest",
|
|
Facets: []*bsky.RichtextFacet{{
|
|
Index: &bsky.RichtextFacet_ByteSlice{
|
|
ByteStart: 0,
|
|
ByteEnd: 20,
|
|
},
|
|
Features: []*bsky.RichtextFacet_Features_Elem{{
|
|
RichtextFacet_Mention: &bsky.RichtextFacet_Mention{
|
|
Did: aliceDID,
|
|
},
|
|
}},
|
|
}},
|
|
CreatedAt: "2025-01-01T00:00:00Z",
|
|
}
|
|
|
|
// Create the post in the PDS
|
|
rkey, _, err := pds.repomgr.CreateRecord(ctx, pds.uid, atproto.BskyPostCollection, post)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create test post: %v", err)
|
|
}
|
|
|
|
// Index the record
|
|
if pds.recordsIndex != nil {
|
|
err = pds.recordsIndex.IndexRecord(atproto.BskyPostCollection, rkey, "testcid", aliceDID, "", 0)
|
|
if err != nil {
|
|
t.Fatalf("Failed to index test post: %v", err)
|
|
}
|
|
}
|
|
|
|
// List posts for alice - should find 1
|
|
posts, err := pds.ListBlueskyPostsForUser(ctx, aliceDID)
|
|
if err != nil {
|
|
t.Fatalf("ListBlueskyPostsForUser() error = %v", err)
|
|
}
|
|
|
|
if len(posts) != 1 {
|
|
t.Errorf("ListBlueskyPostsForUser() returned %d posts, want 1", len(posts))
|
|
}
|
|
|
|
if len(posts) > 0 {
|
|
if posts[0].Text != "@alice.bsky.social pushed myapp:latest" {
|
|
t.Errorf("Post text = %q, want %q", posts[0].Text, "@alice.bsky.social pushed myapp:latest")
|
|
}
|
|
if posts[0].CreatedAt != "2025-01-01T00:00:00Z" {
|
|
t.Errorf("Post createdAt = %q, want %q", posts[0].CreatedAt, "2025-01-01T00:00:00Z")
|
|
}
|
|
}
|
|
|
|
// List posts for bob - should find 0
|
|
bobPosts, err := pds.ListBlueskyPostsForUser(ctx, "did:plc:bob456")
|
|
if err != nil {
|
|
t.Fatalf("ListBlueskyPostsForUser(bob) error = %v", err)
|
|
}
|
|
|
|
if len(bobPosts) != 0 {
|
|
t.Errorf("ListBlueskyPostsForUser(bob) returned %d posts, want 0", len(bobPosts))
|
|
}
|
|
|
|
// Delete posts for alice
|
|
deleted, err := pds.deleteBlueskyPosts(ctx, aliceDID)
|
|
if err != nil {
|
|
t.Fatalf("deleteBlueskyPosts() error = %v", err)
|
|
}
|
|
|
|
if deleted != 1 {
|
|
t.Errorf("deleteBlueskyPosts() deleted = %d, want 1", deleted)
|
|
}
|
|
|
|
// List posts for alice again - should find 0 now
|
|
postsAfterDelete, err := pds.ListBlueskyPostsForUser(ctx, aliceDID)
|
|
if err != nil {
|
|
t.Fatalf("ListBlueskyPostsForUser() after delete error = %v", err)
|
|
}
|
|
|
|
if len(postsAfterDelete) != 0 {
|
|
t.Errorf("ListBlueskyPostsForUser() after delete returned %d posts, want 0", len(postsAfterDelete))
|
|
}
|
|
}
|
|
|
|
func TestDeleteUserData_IncludesPosts(t *testing.T) {
|
|
// Create a test PDS with records index
|
|
pds := setupTestPDSWithIndex(t, "did:plc:testowner")
|
|
|
|
ctx := sharedCtx
|
|
|
|
// Create a test post that mentions alice
|
|
aliceDID := "did:plc:alice123"
|
|
post := &bsky.FeedPost{
|
|
LexiconTypeID: atproto.BskyPostCollection,
|
|
Text: "@alice.bsky.social pushed myapp:latest",
|
|
Facets: []*bsky.RichtextFacet{{
|
|
Index: &bsky.RichtextFacet_ByteSlice{
|
|
ByteStart: 0,
|
|
ByteEnd: 20,
|
|
},
|
|
Features: []*bsky.RichtextFacet_Features_Elem{{
|
|
RichtextFacet_Mention: &bsky.RichtextFacet_Mention{
|
|
Did: aliceDID,
|
|
},
|
|
}},
|
|
}},
|
|
CreatedAt: "2025-01-01T00:00:00Z",
|
|
}
|
|
|
|
// Create the post in the PDS
|
|
rkey, _, err := pds.repomgr.CreateRecord(ctx, pds.uid, atproto.BskyPostCollection, post)
|
|
if err != nil {
|
|
t.Fatalf("Failed to create test post: %v", err)
|
|
}
|
|
|
|
// Index the record
|
|
if pds.recordsIndex != nil {
|
|
err = pds.recordsIndex.IndexRecord(atproto.BskyPostCollection, rkey, "testcid", aliceDID, "", 0)
|
|
if err != nil {
|
|
t.Fatalf("Failed to index test post: %v", err)
|
|
}
|
|
}
|
|
|
|
// Call DeleteUserData
|
|
result, err := pds.DeleteUserData(ctx, aliceDID)
|
|
if err != nil {
|
|
t.Fatalf("DeleteUserData() error = %v", err)
|
|
}
|
|
|
|
// Verify posts were deleted
|
|
if result.PostsDeleted != 1 {
|
|
t.Errorf("DeleteUserData() PostsDeleted = %d, want 1", result.PostsDeleted)
|
|
}
|
|
|
|
// Verify post is actually gone
|
|
posts, err := pds.ListBlueskyPostsForUser(ctx, aliceDID)
|
|
if err != nil {
|
|
t.Fatalf("ListBlueskyPostsForUser() error = %v", err)
|
|
}
|
|
|
|
if len(posts) != 0 {
|
|
t.Errorf("Posts still exist after DeleteUserData, count = %d", len(posts))
|
|
}
|
|
}
|