wait for post api test function, better announce activity id

add_federation_worker_index
phiresky 2023-09-20 10:46:25 +00:00
parent c25734e4ca
commit 2e7d2d1956
4 changed files with 79 additions and 82 deletions

View File

@ -35,7 +35,7 @@ import {
unfollows, unfollows,
resolveCommunity, resolveCommunity,
waitUntil, waitUntil,
delay, waitForPost,
} from "./shared"; } from "./shared";
import { PostView } from "lemmy-js-client/dist/types/PostView"; import { PostView } from "lemmy-js-client/dist/types/PostView";
import { CreatePost } from "lemmy-js-client/dist/types/CreatePost"; 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); expect(postRes.post_view.counts.score).toBe(1);
// Make sure that post is liked on beta // Make sure that post is liked on beta
const res = await waitUntil( const betaPost = await waitForPost(
() => resolvePost(beta, postRes.post_view.post).catch(e => null), beta,
res => res?.post?.counts.score === 1, postRes.post_view.post,
res => res?.counts.score === 1,
); );
let betaPost = res?.post;
expect(betaPost).toBeDefined(); expect(betaPost).toBeDefined();
expect(betaPost?.community.local).toBe(true); expect(betaPost?.community.local).toBe(true);
@ -122,12 +122,12 @@ test("Unlike a post", async () => {
expect(unlike2.post_view.counts.score).toBe(0); expect(unlike2.post_view.counts.score).toBe(0);
// Make sure that post is unliked on beta // Make sure that post is unliked on beta
const betaPost = ( const betaPost = await waitForPost(
await waitUntil( beta,
() => resolvePost(beta, postRes.post_view.post), postRes.post_view.post,
b => b.post?.counts.score === 0, post => post.counts.score === 0,
) );
).post;
expect(betaPost).toBeDefined(); expect(betaPost).toBeDefined();
expect(betaPost?.community.local).toBe(true); expect(betaPost?.community.local).toBe(true);
expect(betaPost?.creator.local).toBe(false); expect(betaPost?.creator.local).toBe(false);
@ -140,26 +140,16 @@ test("Update a post", async () => {
throw "Missing beta community"; throw "Missing beta community";
} }
let postRes = await createPost(alpha, betaCommunity.community.id); let postRes = await createPost(alpha, betaCommunity.community.id);
await waitUntil( await waitForPost(beta, postRes.post_view.post);
() => resolvePost(beta, postRes.post_view.post),
res => !!res.post,
);
let updatedName = "A jest test federated post, updated"; let updatedName = "A jest test federated post, updated";
let updatedPost = await editPost(alpha, postRes.post_view.post); 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.post.name).toBe(updatedName);
expect(updatedPost.post_view.community.local).toBe(false); expect(updatedPost.post_view.community.local).toBe(false);
expect(updatedPost.post_view.creator.local).toBe(true); expect(updatedPost.post_view.creator.local).toBe(true);
// Make sure that post is updated on beta // Make sure that post is updated on beta
let betaPost = (await resolvePost(beta, postRes.post_view.post)).post; let betaPost = await waitForPost(beta, updatedPost.post_view.post);
if (!betaPost) {
throw "Missing beta post";
}
expect(betaPost.community.local).toBe(true); expect(betaPost.community.local).toBe(true);
expect(betaPost.creator.local).toBe(false); expect(betaPost.creator.local).toBe(false);
expect(betaPost.post.name).toBe(updatedName); expect(betaPost.post.name).toBe(updatedName);
@ -223,26 +213,17 @@ test("Lock a post", async () => {
); );
let postRes = await createPost(alpha, betaCommunity.community.id); let postRes = await createPost(alpha, betaCommunity.community.id);
// wait for federation let betaPost1 = await waitForPost(beta, postRes.post_view.post);
await waitUntil(
() => searchPostLocal(beta, postRes.post_view.post),
res => !!res.posts[0],
);
// Lock the 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); let lockedPostRes = await lockPost(beta, true, betaPost1.post);
expect(lockedPostRes.post_view.post.locked).toBe(true); expect(lockedPostRes.post_view.post.locked).toBe(true);
// Make sure that post is locked on alpha // Make sure that post is locked on alpha
let searchAlpha = await waitUntil( let alphaPost1 = await waitForPost(
() => searchPostLocal(alpha, postRes.post_view.post), alpha,
res => res.posts[0]?.post.locked, 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 // Try to make a new comment there, on alpha
await expect(createComment(alpha, alphaPost1.post.id)).rejects.toBe("locked"); 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); expect(unlockedPost.post_view.post.locked).toBe(false);
// Make sure that post is unlocked on alpha // Make sure that post is unlocked on alpha
let searchAlpha2 = await waitUntil( let alphaPost2 = await waitForPost(
() => searchPostLocal(alpha, postRes.post_view.post), alpha,
res => !res.posts[0]?.post.locked, postRes.post_view.post,
post => !post.post.locked,
); );
let alphaPost2 = searchAlpha2.posts[0];
expect(alphaPost2.community.local).toBe(false); expect(alphaPost2.community.local).toBe(false);
expect(alphaPost2.creator.local).toBe(true); expect(alphaPost2.creator.local).toBe(true);
expect(alphaPost2.post.locked).toBe(false); expect(alphaPost2.post.locked).toBe(false);
@ -280,21 +261,14 @@ test("Delete a post", async () => {
// Make sure lemmy beta sees post is deleted // Make sure lemmy beta sees post is deleted
// This will be undefined because of the tombstone // This will be undefined because of the tombstone
await waitUntil( await waitForPost(beta, postRes.post_view.post, p => !p);
() => resolvePost(beta, postRes.post_view.post).catch(e => e),
e => e === "couldnt_find_object",
);
// Undelete // Undelete
let undeletedPost = await deletePost(alpha, false, postRes.post_view.post); let undeletedPost = await deletePost(alpha, false, postRes.post_view.post);
// Make sure lemmy beta sees post is undeleted // Make sure lemmy beta sees post is undeleted
let betaPost2 = ( let betaPost2 = await waitForPost(beta, postRes.post_view.post);
await waitUntil(
() => resolvePost(beta, postRes.post_view.post).catch(e => e),
e => e !== "couldnt_find_object",
)
).post;
if (!betaPost2) { if (!betaPost2) {
throw "Missing beta post 2"; 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); let postRes = await createPost(alpha, betaCommunity.community.id);
expect(postRes.post_view.post).toBeDefined(); expect(postRes.post_view.post).toBeDefined();
// Get the id for beta // Get the id for beta
let searchBeta = await waitUntil( let betaPost = await waitForPost(beta, postRes.post_view.post);
() => searchPostLocal(beta, postRes.post_view.post),
res => !!res.posts[0],
);
let betaPost = searchBeta.posts[0];
expect(betaPost).toBeDefined(); expect(betaPost).toBeDefined();
// The beta admin removes it (the community lives on beta) // 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); expect(removePostRes.post_view.post.removed).toBe(true);
// Make sure lemmy alpha sees post is removed // Make sure lemmy alpha sees post is removed
let alphaPost = await waitUntil( let alphaPost = await waitForPost(
() => getPost(alpha, postRes.post_view.post.id), alpha,
p => p.post_view.post.removed, postRes.post_view.post,
p => p.post.removed,
); );
expect(alphaPost.post_view.post.removed).toBe(true); expect(alphaPost.post.removed).toBe(true);
assertPostFederation(alphaPost.post_view, removePostRes.post_view); assertPostFederation(alphaPost, removePostRes.post_view);
// Undelete // Undelete
let undeletedPost = await removePost(beta, false, betaPost.post); let undeletedPost = await removePost(beta, false, betaPost.post);
expect(undeletedPost.post_view.post.removed).toBe(false); expect(undeletedPost.post_view.post.removed).toBe(false);
// Make sure lemmy alpha sees post is undeleted // Make sure lemmy alpha sees post is undeleted
let alphaPost2 = await waitUntil( let alphaPost2 = await waitForPost(
() => getPost(alpha, postRes.post_view.post.id), alpha,
p => !p.post_view.post.removed, postRes.post_view.post,
p => !p.post.removed,
); );
expect(alphaPost2.post_view.post.removed).toBe(false); expect(alphaPost2.post.removed).toBe(false);
assertPostFederation(alphaPost2.post_view, undeletedPost.post_view); assertPostFederation(alphaPost2, undeletedPost.post_view);
await unfollowRemotes(alpha); 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 // alpha makes post in beta community, it federates to beta instance
let postRes1 = await createPost(alpha_user, betaCommunity.community.id); let postRes1 = await createPost(alpha_user, betaCommunity.community.id);
let searchBeta1 = await waitUntil( let searchBeta1 = await waitForPost(beta, postRes1.post_view.post);
() => searchPostLocal(beta, postRes1.post_view.post),
res => !!res.posts[0],
);
expect(searchBeta1.posts[0]).toBeDefined();
// ban alpha from its instance // ban alpha from its instance
let banAlpha = await banPersonFromSite( let banAlpha = await banPersonFromSite(
@ -447,7 +415,7 @@ test("Enforce site ban for federated user", async () => {
expect(alphaUserOnBeta1.person?.person.banned).toBe(true); expect(alphaUserOnBeta1.person?.person.banned).toBe(true);
// existing alpha post should be removed on beta // 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); expect(searchBeta2.post_view.post.removed).toBe(true);
// Unban alpha // Unban alpha
@ -461,11 +429,7 @@ test("Enforce site ban for federated user", async () => {
// alpha makes new post in beta community, it federates // alpha makes new post in beta community, it federates
let postRes2 = await createPost(alpha_user, betaCommunity.community.id); let postRes2 = await createPost(alpha_user, betaCommunity.community.id);
let searchBeta3 = await waitUntil( let searchBeta3 = await waitForPost(beta, postRes2.post_view.post);
() => searchPostLocal(beta, postRes2.post_view.post),
e => !!e.posts[0],
);
expect(searchBeta3.posts[0]).toBeDefined();
let alphaUserOnBeta2 = await resolvePerson(beta, alphaUserActorId); let alphaUserOnBeta2 = await resolvePerson(beta, alphaUserActorId);
expect(alphaUserOnBeta2.person?.person.banned).toBe(false); expect(alphaUserOnBeta2.person?.person.banned).toBe(false);

View File

@ -4,6 +4,7 @@ import {
GetUnreadCount, GetUnreadCount,
GetUnreadCountResponse, GetUnreadCountResponse,
LemmyHttp, LemmyHttp,
PostView,
} from "lemmy-js-client"; } from "lemmy-js-client";
import { CreatePost } from "lemmy-js-client/dist/types/CreatePost"; import { CreatePost } from "lemmy-js-client/dist/types/CreatePost";
import { DeletePost } from "lemmy-js-client/dist/types/DeletePost"; import { DeletePost } from "lemmy-js-client/dist/types/DeletePost";
@ -318,6 +319,18 @@ export async function searchPostLocal(
return api.client.search(form); 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( export async function getPost(
api: API, api: API,
post_id: number, post_id: number,

View File

@ -1,6 +1,7 @@
use crate::{ use crate::{
activities::{ activities::{
generate_activity_id, generate_activity_id,
generate_announce_activity_id,
send_lemmy_activity, send_lemmy_activity,
verify_is_public, verify_is_public,
verify_person_in_community, verify_person_in_community,
@ -75,16 +76,20 @@ impl AnnounceActivity {
community: &ApubCommunity, community: &ApubCommunity,
context: &Data<LemmyContext>, context: &Data<LemmyContext>,
) -> Result<AnnounceActivity, LemmyError> { ) -> Result<AnnounceActivity, LemmyError> {
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 { Ok(AnnounceActivity {
actor: community.id().into(), actor: community.id().into(),
to: vec![public()], to: vec![public()],
object: IdOrNestedObject::NestedObject(object), object: IdOrNestedObject::NestedObject(object),
cc: vec![community.followers_url.clone().into()], cc: vec![community.followers_url.clone().into()],
kind: AnnounceType::Announce, kind: AnnounceType::Announce,
id: generate_activity_id( id,
&AnnounceType::Announce,
&context.settings().get_protocol_and_hostname(),
)?,
}) })
} }

View File

@ -28,7 +28,7 @@ use crate::{
use activitypub_federation::{ use activitypub_federation::{
config::Data, config::Data,
fetch::object_id::ObjectId, fetch::object_id::ObjectId,
kinds::public, kinds::{activity::AnnounceType, public},
protocol::context::WithContext, protocol::context::WithContext,
traits::{ActivityHandler, Actor}, traits::{ActivityHandler, Actor},
}; };
@ -185,6 +185,21 @@ where
Url::parse(&id) 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<Url, ParseError> {
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 { pub(crate) trait GetActorType {
fn actor_type(&self) -> ActorType; fn actor_type(&self) -> ActorType;
} }