A community based topic aggregation platform built on atproto

test: update tests for lexicon migration and selfLabels structure

Updates all tests to use new social.coves.community.post namespace and
structured com.atproto.label.defs#selfLabels format.

Changes:
- Update test data to match new lexicon schema (author field, facets, etc)
- Update integration tests to use SelfLabels{Values: []SelfLabel{...}}
- Update vote_repo_test to use new namespace
- Update post creation tests for label validation
- Update E2E tests for community post namespace

All lexicon validation tests passing (64 pass, 2 skip for defs files).
All integration tests passing with JSONB label storage.

+11 -11
internal/db/postgres/vote_repo_test.go
···
CID: "bafyreigtest123",
RKey: "3k1234567890",
VoterDID: voterDID,
-
SubjectURI: "at://did:plc:community/social.coves.post.record/abc123",
+
SubjectURI: "at://did:plc:community/social.coves.community.post/abc123",
SubjectCID: "bafyreigpost123",
Direction: "up",
CreatedAt: time.Now(),
···
CID: "bafyreigtest456",
RKey: "3k9876543210",
VoterDID: voterDID,
-
SubjectURI: "at://did:plc:community/social.coves.post.record/xyz789",
+
SubjectURI: "at://did:plc:community/social.coves.community.post/xyz789",
SubjectCID: "bafyreigpost456",
Direction: "down",
CreatedAt: time.Now(),
···
CID: "bafyreignovoter",
RKey: "3k1111111111",
VoterDID: "did:plc:nonexistentvoter",
-
SubjectURI: "at://did:plc:community/social.coves.post.record/test123",
+
SubjectURI: "at://did:plc:community/social.coves.community.post/test123",
SubjectCID: "bafyreigpost789",
Direction: "up",
CreatedAt: time.Now(),
···
CID: "bafyreigtest789",
RKey: "3k5555555555",
VoterDID: voterDID,
-
SubjectURI: "at://did:plc:community/social.coves.post.record/post123",
+
SubjectURI: "at://did:plc:community/social.coves.community.post/post123",
SubjectCID: "bafyreigpost999",
Direction: "up",
CreatedAt: time.Now(),
···
voterDID := "did:plc:testvoter999"
createTestUser(t, db, "testvoter999.test", voterDID)
-
subjectURI := "at://did:plc:community/social.coves.post.record/subject123"
+
subjectURI := "at://did:plc:community/social.coves.community.post/subject123"
// Create vote
vote := &votes.Vote{
···
repo := NewVoteRepository(db)
ctx := context.Background()
-
_, err := repo.GetByVoterAndSubject(ctx, "did:plc:nobody", "at://did:plc:community/social.coves.post.record/nopost")
+
_, err := repo.GetByVoterAndSubject(ctx, "did:plc:nobody", "at://did:plc:community/social.coves.community.post/nopost")
assert.ErrorIs(t, err, votes.ErrVoteNotFound)
}
···
CID: "bafyreigdelete",
RKey: "3k7777777777",
VoterDID: voterDID,
-
SubjectURI: "at://did:plc:community/social.coves.post.record/deletetest",
+
SubjectURI: "at://did:plc:community/social.coves.community.post/deletetest",
SubjectCID: "bafyreigdeletepost",
Direction: "up",
CreatedAt: time.Now(),
···
CID: "bafyreigdelete2",
RKey: "3k8888888888",
VoterDID: voterDID,
-
SubjectURI: "at://did:plc:community/social.coves.post.record/deletetest2",
+
SubjectURI: "at://did:plc:community/social.coves.community.post/deletetest2",
SubjectCID: "bafyreigdeletepost2",
Direction: "down",
CreatedAt: time.Now(),
···
createTestUser(t, db, "testvoterlist1.test", voterDID1)
createTestUser(t, db, "testvoterlist2.test", voterDID2)
-
subjectURI := "at://did:plc:community/social.coves.post.record/listtest"
+
subjectURI := "at://did:plc:community/social.coves.community.post/listtest"
// Create multiple votes on same subject
vote1 := &votes.Vote{
···
CID: "bafyreigvoter1",
RKey: "3k0000000001",
VoterDID: voterDID,
-
SubjectURI: "at://did:plc:community/social.coves.post.record/post1",
+
SubjectURI: "at://did:plc:community/social.coves.community.post/post1",
SubjectCID: "bafyreigp1",
Direction: "up",
CreatedAt: time.Now(),
···
CID: "bafyreigvoter2",
RKey: "3k0000000002",
VoterDID: voterDID,
-
SubjectURI: "at://did:plc:community/social.coves.post.record/post2",
+
SubjectURI: "at://did:plc:community/social.coves.community.post/post2",
SubjectCID: "bafyreigp2",
Direction: "down",
CreatedAt: time.Now(),
+8 -8
tests/integration/aggregator_e2e_test.go
···
reqJSON, err := json.Marshal(reqBody)
require.NoError(t, err)
-
req := httptest.NewRequest("POST", "/xrpc/social.coves.post.create", bytes.NewReader(reqJSON))
+
req := httptest.NewRequest("POST", "/xrpc/social.coves.community.post.create", bytes.NewReader(reqJSON))
req.Header.Set("Content-Type", "application/json")
// Create JWT for aggregator (not a user)
···
Kind: "commit",
Commit: &jetstream.CommitEvent{
Operation: "create",
-
Collection: "social.coves.post.record",
+
Collection: "social.coves.community.post",
RKey: rkey,
CID: response.CID,
Record: map[string]interface{}{
-
"$type": "social.coves.post.record",
+
"$type": "social.coves.community.post",
"community": communityDID,
"author": aggregatorDID, // Aggregator is the author
"title": title,
···
reqJSON, err := json.Marshal(reqBody)
require.NoError(t, err)
-
req := httptest.NewRequest("POST", "/xrpc/social.coves.post.create", bytes.NewReader(reqJSON))
+
req := httptest.NewRequest("POST", "/xrpc/social.coves.community.post.create", bytes.NewReader(reqJSON))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+createSimpleTestJWT(aggregatorDID))
···
reqJSON, err := json.Marshal(reqBody)
require.NoError(t, err)
-
req := httptest.NewRequest("POST", "/xrpc/social.coves.post.create", bytes.NewReader(reqJSON))
+
req := httptest.NewRequest("POST", "/xrpc/social.coves.community.post.create", bytes.NewReader(reqJSON))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+createSimpleTestJWT(aggregatorDID))
···
reqJSON, err = json.Marshal(reqBody)
require.NoError(t, err)
-
req = httptest.NewRequest("POST", "/xrpc/social.coves.post.create", bytes.NewReader(reqJSON))
+
req = httptest.NewRequest("POST", "/xrpc/social.coves.community.post.create", bytes.NewReader(reqJSON))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+createSimpleTestJWT(aggregatorDID))
···
reqJSON, err := json.Marshal(reqBody)
require.NoError(t, err)
-
req := httptest.NewRequest("POST", "/xrpc/social.coves.post.create", bytes.NewReader(reqJSON))
+
req := httptest.NewRequest("POST", "/xrpc/social.coves.community.post.create", bytes.NewReader(reqJSON))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+createSimpleTestJWT(unauthorizedAggDID))
···
reqJSON, err := json.Marshal(reqBody)
require.NoError(t, err)
-
req := httptest.NewRequest("POST", "/xrpc/social.coves.post.create", bytes.NewReader(reqJSON))
+
req := httptest.NewRequest("POST", "/xrpc/social.coves.community.post.create", bytes.NewReader(reqJSON))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+createSimpleTestJWT(aggregatorDID))
+4 -4
tests/integration/aggregator_test.go
···
})
t.Run("records aggregator post for rate limiting", func(t *testing.T) {
-
postURI := fmt.Sprintf("at://%s/social.coves.post.record/post1", communityDID)
+
postURI := fmt.Sprintf("at://%s/social.coves.community.post/post1", communityDID)
err := aggRepo.RecordAggregatorPost(ctx, aggregatorDID, communityDID, postURI, "bafy123")
if err != nil {
···
t.Run("allows posts within rate limit", func(t *testing.T) {
// Create 9 posts (under the 10/hour limit)
for i := 0; i < 9; i++ {
-
postURI := fmt.Sprintf("at://%s/social.coves.post.record/post%d", communityDID, i)
+
postURI := fmt.Sprintf("at://%s/social.coves.community.post/post%d", communityDID, i)
if err := aggRepo.RecordAggregatorPost(ctx, aggregatorDID, communityDID, postURI, "bafy123"); err != nil {
t.Fatalf("Failed to record post %d: %v", i, err)
}
···
t.Run("enforces rate limit at 10 posts/hour", func(t *testing.T) {
// Add one more post to hit the limit (total = 10)
-
postURI := fmt.Sprintf("at://%s/social.coves.post.record/post10", communityDID)
+
postURI := fmt.Sprintf("at://%s/social.coves.community.post/post10", communityDID)
if err := aggRepo.RecordAggregatorPost(ctx, aggregatorDID, communityDID, postURI, "bafy123"); err != nil {
t.Fatalf("Failed to record 10th post: %v", err)
}
···
// Record 5 posts
for i := 0; i < 5; i++ {
-
postURI := fmt.Sprintf("at://%s/social.coves.post.record/triggerpost%d", communityDID, i)
+
postURI := fmt.Sprintf("at://%s/social.coves.community.post/triggerpost%d", communityDID, i)
if err := aggRepo.RecordAggregatorPost(ctx, aggregatorDID, communityDID, postURI, "bafy123"); err != nil {
t.Fatalf("Failed to record post %d: %v", i, err)
}
+1 -1
tests/integration/feed_test.go
···
assert.NotNil(t, feedPost.Post.Record, "Post %d should have Record field", i)
record, ok := feedPost.Post.Record.(map[string]interface{})
require.True(t, ok, "Record should be a map")
-
assert.Equal(t, "social.coves.post.record", record["$type"], "Record should have correct $type")
+
assert.Equal(t, "social.coves.community.post", record["$type"], "Record should have correct $type")
assert.NotEmpty(t, record["community"], "Record should have community")
assert.NotEmpty(t, record["author"], "Record should have author")
assert.NotEmpty(t, record["createdAt"], "Record should have createdAt")
+1 -1
tests/integration/helpers.go
···
// Generate URI
rkey := fmt.Sprintf("post-%d", time.Now().UnixNano())
-
uri := fmt.Sprintf("at://%s/social.coves.post.record/%s", communityDID, rkey)
+
uri := fmt.Sprintf("at://%s/social.coves.community.post/%s", communityDID, rkey)
// Insert post
_, err := db.ExecContext(ctx, `
+41 -21
tests/integration/post_creation_test.go
···
package integration
import (
+
"Coves/internal/api/middleware"
"Coves/internal/atproto/identity"
"Coves/internal/core/communities"
"Coves/internal/core/posts"
···
// This will fail at token refresh step (expected for unit test)
// We're using a fake token that can't be parsed
-
_, err := postService.CreatePost(ctx, req)
+
authCtx := middleware.SetTestUserDID(ctx, testUserDID)
+
_, err := postService.CreatePost(authCtx, req)
// For now, we expect an error because token is fake
// In a full E2E test with real PDS, this would succeed
···
// Should resolve handle to DID and proceed
// Will still fail at token refresh (expected with fake token)
-
_, err := postService.CreatePost(ctx, req)
+
authCtx := middleware.SetTestUserDID(ctx, testUserDID)
+
_, err := postService.CreatePost(authCtx, req)
require.Error(t, err)
// Should fail at token refresh, not community resolution
assert.Contains(t, err.Error(), "failed to refresh community credentials")
···
// Should resolve handle to DID and proceed
// Will still fail at token refresh (expected with fake token)
-
_, err := postService.CreatePost(ctx, req)
+
authCtx := middleware.SetTestUserDID(ctx, testUserDID)
+
_, err := postService.CreatePost(authCtx, req)
require.Error(t, err)
// Should fail at token refresh, not community resolution
assert.Contains(t, err.Error(), "failed to refresh community credentials")
···
AuthorDID: testUserDID,
}
-
_, err := postService.CreatePost(ctx, req)
+
authCtx := middleware.SetTestUserDID(ctx, testUserDID)
+
_, err := postService.CreatePost(authCtx, req)
require.Error(t, err)
assert.True(t, posts.IsValidationError(err))
})
···
AuthorDID: testUserDID,
}
-
_, err := postService.CreatePost(ctx, req)
+
authCtx := middleware.SetTestUserDID(ctx, testUserDID)
+
_, err := postService.CreatePost(authCtx, req)
require.Error(t, err)
// Should fail with community not found (wrapped in error)
assert.Contains(t, err.Error(), "community not found")
···
AuthorDID: "", // Missing!
}
-
_, err := postService.CreatePost(ctx, req)
+
authCtx := middleware.SetTestUserDID(ctx, testUserDID)
+
_, err := postService.CreatePost(authCtx, req)
require.Error(t, err)
assert.True(t, posts.IsValidationError(err))
assert.Contains(t, err.Error(), "authorDid")
···
AuthorDID: testUserDID,
}
-
_, err := postService.CreatePost(ctx, req)
+
authCtx := middleware.SetTestUserDID(ctx, testUserDID)
+
_, err := postService.CreatePost(authCtx, req)
require.Error(t, err)
assert.Equal(t, posts.ErrCommunityNotFound, err)
})
···
AuthorDID: testUserDID,
}
-
_, err := postService.CreatePost(ctx, req)
+
authCtx := middleware.SetTestUserDID(ctx, testUserDID)
+
_, err := postService.CreatePost(authCtx, req)
require.Error(t, err)
assert.True(t, posts.IsValidationError(err))
assert.Contains(t, err.Error(), "too long")
···
content := "Post with invalid label"
req := posts.CreatePostRequest{
-
Community: testCommunity.DID,
-
Content: &content,
-
ContentLabels: []string{"invalid_label"}, // Not in known values!
-
AuthorDID: testUserDID,
+
Community: testCommunity.DID,
+
Content: &content,
+
Labels: &posts.SelfLabels{
+
Values: []posts.SelfLabel{
+
{Val: "invalid_label"}, // Not in known values!
+
},
+
},
+
AuthorDID: testUserDID,
}
-
_, err := postService.CreatePost(ctx, req)
+
authCtx := middleware.SetTestUserDID(ctx, testUserDID)
+
_, err := postService.CreatePost(authCtx, req)
require.Error(t, err)
assert.True(t, posts.IsValidationError(err))
assert.Contains(t, err.Error(), "unknown content label")
···
content := "Post with valid labels"
req := posts.CreatePostRequest{
-
Community: testCommunity.DID,
-
Content: &content,
-
ContentLabels: []string{"nsfw", "spoiler"},
-
AuthorDID: testUserDID,
+
Community: testCommunity.DID,
+
Content: &content,
+
Labels: &posts.SelfLabels{
+
Values: []posts.SelfLabel{
+
{Val: "nsfw"},
+
{Val: "spoiler"},
+
},
+
},
+
AuthorDID: testUserDID,
}
// Will fail at token refresh (expected with fake token)
-
_, err := postService.CreatePost(ctx, req)
+
authCtx := middleware.SetTestUserDID(ctx, testUserDID)
+
_, err := postService.CreatePost(authCtx, req)
require.Error(t, err)
// Should fail at token refresh, not validation
assert.Contains(t, err.Error(), "failed to refresh community credentials")
···
title := "Test Title"
post := &posts.Post{
-
URI: "at://" + testCommunityDID + "/social.coves.post.record/test123",
+
URI: "at://" + testCommunityDID + "/social.coves.community.post/test123",
CID: "bafy2test123",
RKey: "test123",
AuthorDID: testUserDID,
···
content := "Duplicate post"
post1 := &posts.Post{
-
URI: "at://" + testCommunityDID + "/social.coves.post.record/duplicate",
+
URI: "at://" + testCommunityDID + "/social.coves.community.post/duplicate",
CID: "bafy2duplicate1",
RKey: "duplicate",
AuthorDID: testUserDID,
···
// Try to insert again with same URI
post2 := &posts.Post{
-
URI: "at://" + testCommunityDID + "/social.coves.post.record/duplicate",
+
URI: "at://" + testCommunityDID + "/social.coves.community.post/duplicate",
CID: "bafy2duplicate2",
RKey: "duplicate",
AuthorDID: testUserDID,
+15 -15
tests/integration/post_e2e_test.go
···
// XRPC endpoint → AppView Service → PDS write → Jetstream consumer → DB indexing
//
// This is a TRUE E2E test that simulates what happens in production:
-
// 1. Client calls POST /xrpc/social.coves.post.create with auth token
+
// 1. Client calls POST /xrpc/social.coves.community.post.create with auth token
// 2. Handler validates and calls PostService.CreatePost()
// 3. Service writes post to community's PDS repository
// 4. PDS broadcasts event to firehose/Jetstream
···
Kind: "commit",
Commit: &jetstream.CommitEvent{
Operation: "create",
-
Collection: "social.coves.post.record",
+
Collection: "social.coves.community.post",
RKey: rkey,
CID: "bafy2bzaceabc123def456", // Fake CID
Record: map[string]interface{}{
-
"$type": "social.coves.post.record",
+
"$type": "social.coves.community.post",
"community": community.DID,
"author": author.DID,
"title": *postReq.Title,
···
}
// STEP 4: Verify post was indexed in AppView database
-
expectedURI := fmt.Sprintf("at://%s/social.coves.post.record/%s", community.DID, rkey)
+
expectedURI := fmt.Sprintf("at://%s/social.coves.community.post/%s", community.DID, rkey)
indexedPost, err := postRepo.GetByURI(ctx, expectedURI)
if err != nil {
t.Fatalf("Post not indexed in AppView: %v", err)
···
Kind: "commit",
Commit: &jetstream.CommitEvent{
Operation: "create",
-
Collection: "social.coves.post.record",
+
Collection: "social.coves.community.post",
RKey: generateTID(),
CID: "bafy2bzacefake",
Record: map[string]interface{}{
-
"$type": "social.coves.post.record",
+
"$type": "social.coves.community.post",
"community": community.DID, // Claims to be for this community
"author": author.DID,
"title": "Fake Post",
···
Kind: "commit",
Commit: &jetstream.CommitEvent{
Operation: "create",
-
Collection: "social.coves.post.record",
+
Collection: "social.coves.community.post",
RKey: rkey,
CID: "bafy2bzaceidempotent",
Record: map[string]interface{}{
-
"$type": "social.coves.post.record",
+
"$type": "social.coves.community.post",
"community": community.DID,
"author": author.DID,
"title": "Duplicate Test",
···
}
// Verify only one post in database
-
uri := fmt.Sprintf("at://%s/social.coves.post.record/%s", community.DID, rkey)
+
uri := fmt.Sprintf("at://%s/social.coves.community.post/%s", community.DID, rkey)
post, err := postRepo.GetByURI(ctx, uri)
if err != nil {
t.Fatalf("Post not found: %v", err)
···
Kind: "commit",
Commit: &jetstream.CommitEvent{
Operation: "create",
-
Collection: "social.coves.post.record",
+
Collection: "social.coves.community.post",
RKey: generateTID(),
CID: "bafy2bzaceorphaned",
Record: map[string]interface{}{
-
"$type": "social.coves.post.record",
+
"$type": "social.coves.community.post",
"community": unknownCommunityDID,
"author": author.DID,
"title": "Orphaned Post",
···
}
// TestPostCreation_E2E_LivePDS tests the COMPLETE end-to-end flow with a live PDS:
-
// 1. HTTP POST to /xrpc/social.coves.post.create (with auth)
+
// 1. HTTP POST to /xrpc/social.coves.community.post.create (with auth)
// 2. Handler → Service → Write to community's PDS repository
// 3. PDS → Jetstream firehose event
// 4. Jetstream consumer → Index in AppView database
···
require.NoError(t, err)
// Create HTTP request
-
req := httptest.NewRequest("POST", "/xrpc/social.coves.post.create", bytes.NewReader(reqJSON))
+
req := httptest.NewRequest("POST", "/xrpc/social.coves.community.post.create", bytes.NewReader(reqJSON))
req.Header.Set("Content-Type", "application/json")
// Create a simple JWT for testing (Phase 1: no signature verification)
···
pdsHostname = strings.Split(pdsHostname, ":")[0] // Remove port
// Build Jetstream URL with filters for post records
-
jetstreamURL := fmt.Sprintf("ws://%s:6008/subscribe?wantedCollections=social.coves.post.record",
+
jetstreamURL := fmt.Sprintf("ws://%s:6008/subscribe?wantedCollections=social.coves.community.post",
pdsHostname)
t.Logf(" Jetstream URL: %s", jetstreamURL)
···
// Check if this is a post event for the target DID
if event.Did == targetDID && event.Kind == "commit" &&
-
event.Commit != nil && event.Commit.Collection == "social.coves.post.record" {
+
event.Commit != nil && event.Commit.Collection == "social.coves.community.post" {
// Process the event through the consumer
if err := consumer.HandleEvent(ctx, &event); err != nil {
return fmt.Errorf("failed to process event: %w", err)
+13 -13
tests/integration/post_handler_test.go
···
}
body, _ := json.Marshal(payload)
-
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.post.create", bytes.NewReader(body))
+
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.community.post.create", bytes.NewReader(body))
// Mock authenticated user context
ctx := middleware.SetTestUserDID(req.Context(), "did:plc:alice")
···
}
body, _ := json.Marshal(payload)
-
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.post.create", bytes.NewReader(body))
+
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.community.post.create", bytes.NewReader(body))
// No auth context set
rec := httptest.NewRecorder()
···
}
body, _ := json.Marshal(payload)
-
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.post.create", bytes.NewReader(body))
+
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.community.post.create", bytes.NewReader(body))
// Mock authenticated user context
ctx := middleware.SetTestUserDID(req.Context(), "did:plc:alice")
···
// Invalid JSON
invalidJSON := []byte(`{"community": "did:plc:test123", "content": `)
-
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.post.create", bytes.NewReader(invalidJSON))
+
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.community.post.create", bytes.NewReader(invalidJSON))
// Mock authenticated user context
ctx := middleware.SetTestUserDID(req.Context(), "did:plc:alice")
···
}
body, _ := json.Marshal(payload)
-
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.post.create", bytes.NewReader(body))
+
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.community.post.create", bytes.NewReader(body))
// Mock authenticated user context
ctx := middleware.SetTestUserDID(req.Context(), "did:plc:alice")
···
}
body, _ := json.Marshal(payload)
-
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.post.create", bytes.NewReader(body))
+
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.community.post.create", bytes.NewReader(body))
// Mock authenticated user context
ctx := middleware.SetTestUserDID(req.Context(), "did:plc:alice")
···
}
body, _ := json.Marshal(payload)
-
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.post.create", bytes.NewReader(body))
+
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.community.post.create", bytes.NewReader(body))
// Mock authenticated user context
ctx := middleware.SetTestUserDID(req.Context(), "did:plc:alice")
···
}
body, _ := json.Marshal(payload)
-
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.post.create", bytes.NewReader(body))
+
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.community.post.create", bytes.NewReader(body))
// Mock authenticated user context
ctx := middleware.SetTestUserDID(req.Context(), "did:plc:alice")
···
}
body, _ := json.Marshal(payload)
-
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.post.create", bytes.NewReader(body))
+
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.community.post.create", bytes.NewReader(body))
// Mock authenticated user context
ctx := middleware.SetTestUserDID(req.Context(), "did:plc:alice")
···
}
body, _ := json.Marshal(payload)
-
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.post.create", bytes.NewReader(body))
+
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.community.post.create", bytes.NewReader(body))
// Mock authenticated user context
ctx := middleware.SetTestUserDID(req.Context(), "did:plc:alice")
···
for _, method := range methods {
t.Run(method, func(t *testing.T) {
-
req := httptest.NewRequest(method, "/xrpc/social.coves.post.create", nil)
+
req := httptest.NewRequest(method, "/xrpc/social.coves.community.post.create", nil)
rec := httptest.NewRecorder()
handler.HandleCreate(rec, req)
···
}
body, _ := json.Marshal(payload)
-
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.post.create", bytes.NewReader(body))
+
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.community.post.create", bytes.NewReader(body))
ctx := middleware.SetTestUserDID(req.Context(), "did:plc:alice")
req = req.WithContext(ctx)
···
}
body, _ := json.Marshal(payload)
-
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.post.create", bytes.NewReader(body))
+
req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.community.post.create", bytes.NewReader(body))
ctx := middleware.SetTestUserDID(req.Context(), "did:plc:alice")
req = req.WithContext(ctx)
+1 -1
tests/integration/timeline_test.go
···
assert.NotNil(t, feedPost.Post.Record, "Post %d should have Record field", i)
record, ok := feedPost.Post.Record.(map[string]interface{})
require.True(t, ok, "Record should be a map")
-
assert.Equal(t, "social.coves.post.record", record["$type"], "Record should have correct $type")
+
assert.Equal(t, "social.coves.community.post", record["$type"], "Record should have correct $type")
assert.NotEmpty(t, record["community"], "Record should have community")
assert.NotEmpty(t, record["author"], "Record should have author")
assert.NotEmpty(t, record["createdAt"], "Record should have createdAt")
+1 -1
tests/lexicon-test-data/actor/saved-invalid-type.json
···
{
"$type": "social.coves.actor.saved",
-
"subject": "at://did:plc:exampleuser/social.coves.post.record/3k7a3dmb5bk2c",
+
"subject": "at://$1/social.coves.community.post/3k7a3dmb5bk2c",
"type": "article",
"createdAt": "2025-01-09T14:30:00Z"
}
+1 -1
tests/lexicon-test-data/actor/saved-valid.json
···
{
"$type": "social.coves.actor.saved",
-
"subject": "at://did:plc:exampleuser/social.coves.post.record/3k7a3dmb5bk2c",
+
"subject": "at://$1/social.coves.community.post/3k7a3dmb5bk2c",
"type": "post",
"createdAt": "2025-01-09T14:30:00Z",
"note": "Great tutorial on Go concurrency patterns"
+12 -3
tests/lexicon-test-data/interaction/comment-invalid-content.json
···
{
-
"$type": "social.coves.interaction.comment",
-
"post": "at://did:plc:author123/social.coves.post.record/3k7a3dmb5bk2c",
+
"$type": "social.coves.feed.comment",
+
"reply": {
+
"root": {
+
"uri": "at://did:plc:test123/social.coves.community.post/3k7a3dmb5bk2c",
+
"cid": "bafyreigj3fwnwjuzr35k2kuzmb5dixxczrzjhqkr5srlqplsh6gq3bj3si"
+
},
+
"parent": {
+
"uri": "at://did:plc:test123/social.coves.community.post/3k7a3dmb5bk2c",
+
"cid": "bafyreigj3fwnwjuzr35k2kuzmb5dixxczrzjhqkr5srlqplsh6gq3bj3si"
+
}
+
},
"createdAt": "2025-01-09T16:45:00Z"
-
}
+
}
+12 -7
tests/lexicon-test-data/interaction/comment-valid-sticker.json
···
{
-
"$type": "social.coves.interaction.comment",
-
"subject": "at://did:plc:author123/social.coves.post.record/3k7a3dmb5bk2c",
-
"content": {
-
"$type": "social.coves.interaction.comment#stickerContent",
-
"stickerId": "thumbs-up",
-
"stickerPackId": "default-pack"
+
"$type": "social.coves.feed.comment",
+
"reply": {
+
"root": {
+
"uri": "at://did:plc:test123/social.coves.community.post/3k7a3dmb5bk2c",
+
"cid": "bafyreigj3fwnwjuzr35k2kuzmb5dixxczrzjhqkr5srlqplsh6gq3bj3si"
+
},
+
"parent": {
+
"uri": "at://did:plc:test123/social.coves.community.post/3k7a3dmb5bk2c",
+
"cid": "bafyreigj3fwnwjuzr35k2kuzmb5dixxczrzjhqkr5srlqplsh6gq3bj3si"
+
}
},
+
"content": "👍",
"createdAt": "2025-01-09T16:50:00Z"
-
}
+
}
+26 -20
tests/lexicon-test-data/interaction/comment-valid-text.json
···
{
-
"$type": "social.coves.interaction.comment",
-
"subject": "at://did:plc:author123/social.coves.post.record/3k7a3dmb5bk2c",
-
"content": {
-
"$type": "social.coves.interaction.comment#textContent",
-
"text": "Great post! I especially liked the part about @alice.example.com's contribution to the project.",
-
"facets": [
-
{
-
"index": {
-
"byteStart": 46,
-
"byteEnd": 64
-
},
-
"features": [
-
{
-
"$type": "social.coves.richtext.facet#mention",
-
"did": "did:plc:aliceuser123"
-
}
-
]
-
}
-
]
+
"$type": "social.coves.feed.comment",
+
"reply": {
+
"root": {
+
"uri": "at://did:plc:test123/social.coves.community.post/3k7a3dmb5bk2c",
+
"cid": "bafyreigj3fwnwjuzr35k2kuzmb5dixxczrzjhqkr5srlqplsh6gq3bj3si"
+
},
+
"parent": {
+
"uri": "at://did:plc:test123/social.coves.community.post/3k7a3dmb5bk2c",
+
"cid": "bafyreigj3fwnwjuzr35k2kuzmb5dixxczrzjhqkr5srlqplsh6gq3bj3si"
+
}
},
+
"content": "Great post! I especially liked the part about @alice.example.com's contribution to the project.",
+
"facets": [
+
{
+
"index": {
+
"byteStart": 46,
+
"byteEnd": 64
+
},
+
"features": [
+
{
+
"$type": "social.coves.richtext.facet#mention",
+
"did": "did:plc:aliceuser123"
+
}
+
]
+
}
+
],
"createdAt": "2025-01-09T16:30:00Z"
-
}
+
}
+1 -1
tests/lexicon-test-data/moderation/tribunal-vote-invalid-decision.json
···
{
"$type": "social.coves.moderation.tribunalVote",
"tribunal": "at://did:plc:community123/social.coves.moderation.tribunal/3k7a3dmb5bk2c",
-
"subject": "at://did:plc:user123/social.coves.post.record/3k7a2clb4bj2b",
+
"subject": "at://$1/social.coves.community.post/3k7a2clb4bj2b",
"decision": "maybe",
"createdAt": "2025-01-09T18:00:00Z"
}
+1 -1
tests/lexicon-test-data/moderation/tribunal-vote-valid.json
···
{
"$type": "social.coves.moderation.tribunalVote",
"tribunal": "at://did:plc:community123/social.coves.moderation.tribunal/3k7a3dmb5bk2c",
-
"subject": "at://did:plc:spammer123/social.coves.post.record/3k7a2clb4bj2b",
+
"subject": "at://$1/social.coves.community.post/3k7a2clb4bj2b",
"decision": "remove",
"reasoning": "The moderator's action was justified based on clear violation of Rule 2 (No Spam). The user posted the same promotional content across multiple communities within a short timeframe.",
"precedents": [
+5 -5
tests/lexicon-test-data/post/post-invalid-enum-type.json
···
{
-
"$type": "social.coves.post.record",
+
"$type": "social.coves.community.post",
"community": "did:plc:programming123",
+
"author": "did:plc:testauthor123",
"postType": "invalid-type",
"title": "This has an invalid post type",
-
"text": "The postType field has an invalid value",
+
"content": "The postType field is not defined in the schema and should be rejected",
"tags": [],
-
"language": "en",
-
"contentWarnings": [],
+
"langs": ["en"],
"createdAt": "2025-01-09T14:30:00Z"
-
}
+
}
+5 -6
tests/lexicon-test-data/post/post-invalid-missing-community.json
···
{
-
"$type": "social.coves.post.record",
-
"postType": "text",
+
"$type": "social.coves.community.post",
+
"author": "did:plc:testauthor123",
"title": "Test Post",
-
"text": "This post is missing the required community field",
+
"content": "This post is missing the required community field",
"tags": ["test"],
-
"language": "en",
-
"contentWarnings": [],
+
"langs": ["en"],
"createdAt": "2025-01-09T14:30:00Z"
-
}
+
}
+6 -7
tests/lexicon-test-data/post/post-valid-text.json
···
{
-
"$type": "social.coves.post.record",
+
"$type": "social.coves.community.post",
"community": "did:plc:programming123",
-
"postType": "text",
+
"author": "did:plc:testauthor123",
"title": "Best practices for error handling in Go",
-
"text": "I've been working with Go for a while now and wanted to share some thoughts on error handling patterns...",
-
"textFacets": [
+
"content": "I've been working with Go for a while now and wanted to share some thoughts on error handling patterns...",
+
"facets": [
{
"index": {
"byteStart": 20,
···
}
],
"tags": ["golang", "error-handling", "best-practices"],
-
"language": "en",
-
"contentWarnings": [],
+
"langs": ["en"],
"createdAt": "2025-01-09T14:30:00Z"
-
}
+
}