From 2e7d2d1956744acc3b0a444f1ebec848c9808adc Mon Sep 17 00:00:00 2001 From: phiresky Date: Wed, 20 Sep 2023 10:46:25 +0000 Subject: [PATCH] wait for post api test function, better announce activity id --- api_tests/src/post.spec.ts | 118 ++++++------------ api_tests/src/shared.ts | 13 ++ .../apub/src/activities/community/announce.rs | 13 +- crates/apub/src/activities/mod.rs | 17 ++- 4 files changed, 79 insertions(+), 82 deletions(-) diff --git a/api_tests/src/post.spec.ts b/api_tests/src/post.spec.ts index 228925d06..54faa1714 100644 --- a/api_tests/src/post.spec.ts +++ b/api_tests/src/post.spec.ts @@ -35,7 +35,7 @@ import { unfollows, resolveCommunity, waitUntil, - delay, + waitForPost, } from "./shared"; import { PostView } from "lemmy-js-client/dist/types/PostView"; import { CreatePost } from "lemmy-js-client/dist/types/CreatePost"; @@ -82,11 +82,11 @@ test("Create a post", async () => { expect(postRes.post_view.counts.score).toBe(1); // Make sure that post is liked on beta - const res = await waitUntil( - () => resolvePost(beta, postRes.post_view.post).catch(e => null), - res => res?.post?.counts.score === 1, + const betaPost = await waitForPost( + beta, + postRes.post_view.post, + res => res?.counts.score === 1, ); - let betaPost = res?.post; expect(betaPost).toBeDefined(); expect(betaPost?.community.local).toBe(true); @@ -122,12 +122,12 @@ test("Unlike a post", async () => { expect(unlike2.post_view.counts.score).toBe(0); // Make sure that post is unliked on beta - const betaPost = ( - await waitUntil( - () => resolvePost(beta, postRes.post_view.post), - b => b.post?.counts.score === 0, - ) - ).post; + const betaPost = await waitForPost( + beta, + postRes.post_view.post, + post => post.counts.score === 0, + ); + expect(betaPost).toBeDefined(); expect(betaPost?.community.local).toBe(true); expect(betaPost?.creator.local).toBe(false); @@ -140,26 +140,16 @@ test("Update a post", async () => { throw "Missing beta community"; } let postRes = await createPost(alpha, betaCommunity.community.id); - await waitUntil( - () => resolvePost(beta, postRes.post_view.post), - res => !!res.post, - ); + await waitForPost(beta, postRes.post_view.post); let updatedName = "A jest test federated post, updated"; let updatedPost = await editPost(alpha, postRes.post_view.post); - await waitUntil( - () => resolvePost(beta, postRes.post_view.post), - res => res.post?.post.name === updatedName, - ); expect(updatedPost.post_view.post.name).toBe(updatedName); expect(updatedPost.post_view.community.local).toBe(false); expect(updatedPost.post_view.creator.local).toBe(true); // Make sure that post is updated on beta - let betaPost = (await resolvePost(beta, postRes.post_view.post)).post; - if (!betaPost) { - throw "Missing beta post"; - } + let betaPost = await waitForPost(beta, updatedPost.post_view.post); expect(betaPost.community.local).toBe(true); expect(betaPost.creator.local).toBe(false); expect(betaPost.post.name).toBe(updatedName); @@ -223,26 +213,17 @@ test("Lock a post", async () => { ); let postRes = await createPost(alpha, betaCommunity.community.id); - // wait for federation - await waitUntil( - () => searchPostLocal(beta, postRes.post_view.post), - res => !!res.posts[0], - ); + let betaPost1 = await waitForPost(beta, postRes.post_view.post); // Lock the post - let betaPost1 = (await resolvePost(beta, postRes.post_view.post)).post; - if (!betaPost1) { - throw "Missing beta post1"; - } let lockedPostRes = await lockPost(beta, true, betaPost1.post); expect(lockedPostRes.post_view.post.locked).toBe(true); // Make sure that post is locked on alpha - let searchAlpha = await waitUntil( - () => searchPostLocal(alpha, postRes.post_view.post), - res => res.posts[0]?.post.locked, + let alphaPost1 = await waitForPost( + alpha, + postRes.post_view.post, + post => post.post.locked, ); - let alphaPost1 = searchAlpha.posts[0]; - expect(alphaPost1.post.locked).toBe(true); // Try to make a new comment there, on alpha await expect(createComment(alpha, alphaPost1.post.id)).rejects.toBe("locked"); @@ -252,11 +233,11 @@ test("Lock a post", async () => { expect(unlockedPost.post_view.post.locked).toBe(false); // Make sure that post is unlocked on alpha - let searchAlpha2 = await waitUntil( - () => searchPostLocal(alpha, postRes.post_view.post), - res => !res.posts[0]?.post.locked, + let alphaPost2 = await waitForPost( + alpha, + postRes.post_view.post, + post => !post.post.locked, ); - let alphaPost2 = searchAlpha2.posts[0]; expect(alphaPost2.community.local).toBe(false); expect(alphaPost2.creator.local).toBe(true); expect(alphaPost2.post.locked).toBe(false); @@ -280,21 +261,14 @@ test("Delete a post", async () => { // Make sure lemmy beta sees post is deleted // This will be undefined because of the tombstone - await waitUntil( - () => resolvePost(beta, postRes.post_view.post).catch(e => e), - e => e === "couldnt_find_object", - ); + await waitForPost(beta, postRes.post_view.post, p => !p); // Undelete let undeletedPost = await deletePost(alpha, false, postRes.post_view.post); // Make sure lemmy beta sees post is undeleted - let betaPost2 = ( - await waitUntil( - () => resolvePost(beta, postRes.post_view.post).catch(e => e), - e => e !== "couldnt_find_object", - ) - ).post; + let betaPost2 = await waitForPost(beta, postRes.post_view.post); + if (!betaPost2) { throw "Missing beta post 2"; } @@ -354,11 +328,7 @@ test("Remove a post from admin and community on same instance", async () => { let postRes = await createPost(alpha, betaCommunity.community.id); expect(postRes.post_view.post).toBeDefined(); // Get the id for beta - let searchBeta = await waitUntil( - () => searchPostLocal(beta, postRes.post_view.post), - res => !!res.posts[0], - ); - let betaPost = searchBeta.posts[0]; + let betaPost = await waitForPost(beta, postRes.post_view.post); expect(betaPost).toBeDefined(); // The beta admin removes it (the community lives on beta) @@ -366,24 +336,26 @@ test("Remove a post from admin and community on same instance", async () => { expect(removePostRes.post_view.post.removed).toBe(true); // Make sure lemmy alpha sees post is removed - let alphaPost = await waitUntil( - () => getPost(alpha, postRes.post_view.post.id), - p => p.post_view.post.removed, + let alphaPost = await waitForPost( + alpha, + postRes.post_view.post, + p => p.post.removed, ); - expect(alphaPost.post_view.post.removed).toBe(true); - assertPostFederation(alphaPost.post_view, removePostRes.post_view); + expect(alphaPost.post.removed).toBe(true); + assertPostFederation(alphaPost, removePostRes.post_view); // Undelete let undeletedPost = await removePost(beta, false, betaPost.post); expect(undeletedPost.post_view.post.removed).toBe(false); // Make sure lemmy alpha sees post is undeleted - let alphaPost2 = await waitUntil( - () => getPost(alpha, postRes.post_view.post.id), - p => !p.post_view.post.removed, + let alphaPost2 = await waitForPost( + alpha, + postRes.post_view.post, + p => !p.post.removed, ); - expect(alphaPost2.post_view.post.removed).toBe(false); - assertPostFederation(alphaPost2.post_view, undeletedPost.post_view); + expect(alphaPost2.post.removed).toBe(false); + assertPostFederation(alphaPost2, undeletedPost.post_view); await unfollowRemotes(alpha); }); @@ -424,11 +396,7 @@ test("Enforce site ban for federated user", async () => { // alpha makes post in beta community, it federates to beta instance let postRes1 = await createPost(alpha_user, betaCommunity.community.id); - let searchBeta1 = await waitUntil( - () => searchPostLocal(beta, postRes1.post_view.post), - res => !!res.posts[0], - ); - expect(searchBeta1.posts[0]).toBeDefined(); + let searchBeta1 = await waitForPost(beta, postRes1.post_view.post); // ban alpha from its instance let banAlpha = await banPersonFromSite( @@ -447,7 +415,7 @@ test("Enforce site ban for federated user", async () => { expect(alphaUserOnBeta1.person?.person.banned).toBe(true); // existing alpha post should be removed on beta - let searchBeta2 = await getPost(beta, searchBeta1.posts[0].post.id); + let searchBeta2 = await getPost(beta, searchBeta1.post.id); expect(searchBeta2.post_view.post.removed).toBe(true); // Unban alpha @@ -461,11 +429,7 @@ test("Enforce site ban for federated user", async () => { // alpha makes new post in beta community, it federates let postRes2 = await createPost(alpha_user, betaCommunity.community.id); - let searchBeta3 = await waitUntil( - () => searchPostLocal(beta, postRes2.post_view.post), - e => !!e.posts[0], - ); - expect(searchBeta3.posts[0]).toBeDefined(); + let searchBeta3 = await waitForPost(beta, postRes2.post_view.post); let alphaUserOnBeta2 = await resolvePerson(beta, alphaUserActorId); expect(alphaUserOnBeta2.person?.person.banned).toBe(false); diff --git a/api_tests/src/shared.ts b/api_tests/src/shared.ts index b3f9f637f..1166b5134 100644 --- a/api_tests/src/shared.ts +++ b/api_tests/src/shared.ts @@ -4,6 +4,7 @@ import { GetUnreadCount, GetUnreadCountResponse, LemmyHttp, + PostView, } from "lemmy-js-client"; import { CreatePost } from "lemmy-js-client/dist/types/CreatePost"; import { DeletePost } from "lemmy-js-client/dist/types/DeletePost"; @@ -318,6 +319,18 @@ export async function searchPostLocal( return api.client.search(form); } +/// wait for a post to appear locally without pulling it +export async function waitForPost( + api: API, + post: Post, + checker: (t: PostView) => boolean = p => !!p, +) { + return waitUntil( + () => searchPostLocal(api, post).then(p => p.posts[0] as PostView), + checker, + ); +} + export async function getPost( api: API, post_id: number, diff --git a/crates/apub/src/activities/community/announce.rs b/crates/apub/src/activities/community/announce.rs index 5939c023a..ab82eb1de 100644 --- a/crates/apub/src/activities/community/announce.rs +++ b/crates/apub/src/activities/community/announce.rs @@ -1,6 +1,7 @@ use crate::{ activities::{ generate_activity_id, + generate_announce_activity_id, send_lemmy_activity, verify_is_public, verify_person_in_community, @@ -75,16 +76,20 @@ impl AnnounceActivity { community: &ApubCommunity, context: &Data, ) -> Result { + let inner_kind = object + .other + .get("type") + .and_then(|e| e.as_str()) + .unwrap_or("other"); + let id = + generate_announce_activity_id(inner_kind, &context.settings().get_protocol_and_hostname())?; Ok(AnnounceActivity { actor: community.id().into(), to: vec![public()], object: IdOrNestedObject::NestedObject(object), cc: vec![community.followers_url.clone().into()], kind: AnnounceType::Announce, - id: generate_activity_id( - &AnnounceType::Announce, - &context.settings().get_protocol_and_hostname(), - )?, + id, }) } diff --git a/crates/apub/src/activities/mod.rs b/crates/apub/src/activities/mod.rs index 81bf806a6..2e26e0678 100644 --- a/crates/apub/src/activities/mod.rs +++ b/crates/apub/src/activities/mod.rs @@ -28,7 +28,7 @@ use crate::{ use activitypub_federation::{ config::Data, fetch::object_id::ObjectId, - kinds::public, + kinds::{activity::AnnounceType, public}, protocol::context::WithContext, traits::{ActivityHandler, Actor}, }; @@ -185,6 +185,21 @@ where Url::parse(&id) } +/// like generate_activity_id but also add the inner kind for easier debugging +fn generate_announce_activity_id( + inner_kind: &str, + protocol_and_hostname: &str, +) -> Result { + let id = format!( + "{}/activities/{}/{}/{}", + protocol_and_hostname, + AnnounceType::Announce.to_string().to_lowercase(), + inner_kind, + Uuid::new_v4() + ); + Url::parse(&id) +} + pub(crate) trait GetActorType { fn actor_type(&self) -> ActorType; }