a_post=$(acurl -X POST -H "$KH""$AK/api/v1/statuses" -d 'status=Hello PrivaPub from Akkoma&visibility=public')
a_post_id=$(echo"$a_post"| j "print(d['id'])")
until_true 30'[ -n "$(p_home_id "Hello PrivaPub from Akkoma")" ]'&& ok "akuser's post reaches alice_akkoma's home"|| ko "Akkoma's post missing on PrivaPub"
a_post_on_p=$(p_home_id "Hello PrivaPub from Akkoma")
&& ok "akuser's post keeps its published time"|| ko "published time changed on PrivaPub"
cw_uri=$(curl -s -X POST -H "$PH"$P/api/v1/statuses -d 'status=behind a warning&spoiler_text=spoilers&visibility=public'| j "print(d['uri'])")
until_true 30'[ "$(a_status_by_uri "$alice_on_a" "$cw_uri" | j "print(d and d[\"spoiler_text\"]==\"spoilers\" and d[\"sensitive\"])")" = "True" ]'&& ok "a content warning survives to Akkoma"|| ko "content warning lost on Akkoma"
fo_uri=$(curl -s -X POST -H "$PH"$P/api/v1/statuses -d 'status=only for followers&visibility=private'| j "print(d['uri'])")
until_true 30'[ "$(a_status_by_uri "$alice_on_a" "$fo_uri" | j "print(d and d[\"visibility\"])")" = "private" ]'&& ok "a followers-only post reaches Akkoma as private"|| ko "followers-only post missing or widened on Akkoma"
echo" replies"
acurl -o /dev/null -X POST -H "$KH""$AK/api/v1/statuses" -d "status=@alice_akkoma@privapub.test replying from Akkoma&in_reply_to_id=$p_post_on_a&visibility=public"
until_true 30'curl -s -H "$PH" "$P/api/v1/notifications" | j "print(any(n[\"type\"]==\"mention\" for n in d))" | grep -q True'&& ok "akuser's reply notifies alice_akkoma"|| ko "reply did not notify"
until_true 15'[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$p_post_id/context" | j "print(len(d[\"descendants\"]))")" -ge 1 ]'&& ok "the reply threads under alice_akkoma's post"|| ko "reply not threaded on PrivaPub"
curl -s -o /dev/null -X POST -H "$PH"$P/api/v1/statuses -d "status=@akuser@akkoma.test replying from PrivaPub&in_reply_to_id=$a_post_on_p&visibility=public"
until_true 30'[ "$(acurl -H "$KH" "$AK/api/v1/statuses/$a_post_id/context" | j "print(len(d[\"descendants\"]))")" -ge 1 ]'&& ok "alice_akkoma's reply threads under akuser's post"|| ko "outbound reply not threaded on Akkoma"
echo" likes, boosts and reactions"
curl -s -o /dev/null -X POST -H "$PH""$P/api/v1/statuses/$a_post_on_p/favourite"
curl -s -o /dev/null -X POST -H "$PH""$P/api/v1/statuses/$a_post_on_p/reblog"
# Akkoma counts them from its own job queue, which can lag behind under the load of a six-peer run: two minutes
until_true 60'[ "$(acurl -H "$KH" "$AK/api/v1/statuses/$a_post_id" | j "print(d[\"favourites_count\"], d[\"reblogs_count\"])")" = "1 1" ]'&& ok "alice_akkoma's like and boost count on Akkoma"|| ko "like or boost not counted on Akkoma"
curl -s -o /dev/null -X POST -H "$PH""$P/api/v1/statuses/$a_post_on_p/unfavourite"
curl -s -o /dev/null -X POST -H "$PH""$P/api/v1/statuses/$a_post_on_p/unreblog"
until_true 30'[ "$(acurl -H "$KH" "$AK/api/v1/statuses/$a_post_id" | j "print(d[\"favourites_count\"], d[\"reblogs_count\"])")" = "0 0" ]'&& ok "alice_akkoma's unlike and unboost reach Akkoma"|| ko "undo of like or boost not applied on Akkoma"
acurl -o /dev/null -X POST -H "$KH""$AK/api/v1/statuses/$p_post_on_a/favourite"
acurl -o /dev/null -X POST -H "$KH""$AK/api/v1/statuses/$p_post_on_a/reblog"
until_true 30'[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$p_post_id" | j "print(d[\"favourites_count\"], d[\"reblogs_count\"])")" = "1 1" ]'&& ok "akuser's like and boost count on PrivaPub"|| ko "like or boost not counted on PrivaPub"
acurl -o /dev/null -X POST -H "$KH""$AK/api/v1/statuses/$p_post_on_a/unfavourite"
acurl -o /dev/null -X POST -H "$KH""$AK/api/v1/statuses/$p_post_on_a/unreblog"
until_true 30'[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$p_post_id" | j "print(d[\"favourites_count\"], d[\"reblogs_count\"])")" = "0 0" ]'&& ok "akuser's unlike and unboost reach PrivaPub"|| ko "undo of like or boost not applied on PrivaPub"
acurl -o /dev/null -X PUT -H "$KH""$AK/api/v1/pleroma/statuses/$p_post_on_a/reactions/%F0%9F%8E%89"
until_true 30'[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$p_post_id" | j "print(any(r[\"name\"]==\"🎉\" and r[\"count\"]==1 for r in d.get(\"emoji_reactions\") or []))")" = "True" ]'\
&& ok "akuser's 🎉 (EmojiReact) arrives as a reaction"|| ko "Akkoma's reaction missing on PrivaPub"
until_true 30'[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$p_post_id" | j "print(len(d.get(\"emoji_reactions\") or []))")" = "0" ]'&& ok "akuser's withdrawn reaction is gone"|| ko "withdrawn reaction still on PrivaPub"
curl -s -o /dev/null -X PUT -H "$PH""$P/api/v1/pleroma/statuses/$a_post_on_p/reactions/%F0%9F%91%8D"
until_true 30'[ "$(acurl -H "$KH" "$AK/api/v1/statuses/$a_post_id" | j "print(any(r[\"name\"]==\"👍\" and r[\"count\"]==1 for r in (d.get(\"pleroma\") or {}).get(\"emoji_reactions\") or d.get(\"emoji_reactions\") or []))")" = "True" ]'\
&& ok "alice_akkoma's 👍 is a reaction on Akkoma"|| ko "PrivaPub's reaction missing on Akkoma"
until_true 30'[ "$(acurl -H "$KH" "$AK/api/v1/statuses/$a_post_id" | j "print(len((d.get(\"pleroma\") or {}).get(\"emoji_reactions\") or d.get(\"emoji_reactions\") or []))")" = "0" ]'&& ok "alice_akkoma's withdrawn reaction is gone from Akkoma"|| ko "withdrawn reaction still on Akkoma"
echo" direct messages"
curl -s -o /dev/null -X POST -H "$PH"$P/api/v1/statuses -d 'status=@akuser@akkoma.test a secret for Akkoma&visibility=direct'
until_true 30'acurl -H "$KH" "$AK/api/v1/conversations" | grep -q "a secret for Akkoma"'&& ok "alice_akkoma's DM reaches akuser"|| ko "DM missing on Akkoma"
# Akkoma's Linkify never takes @user@host.test for a mention, so its DM names alice with Pleroma's to[] instead
acurl -o /dev/null -X POST -H "$KH""$AK/api/v1/statuses" -d 'status=a secret for PrivaPub&visibility=direct&to[]=alice_akkoma@privapub.test'
until_true 30'curl -s -H "$PH" "$P/api/v1/conversations" | grep -q "a secret for PrivaPub"'&& ok "akuser's DM reaches alice_akkoma"|| ko "DM missing on PrivaPub"
! curl -s "$P/api/v1/timelines/public"| grep -q "a secret for PrivaPub"&& ok "the DM is not on PrivaPub's public timeline"|| ko "DM leaked to the public timeline"
echo" polls"
p_poll_uri=$(curl -s -X POST -H "$PH"$P/api/v1/statuses -d 'status=cats or dogs&visibility=public&poll[options][]=cats&poll[options][]=dogs&poll[expires_in]=3600'| j "print(d['uri'])")
until_true 30'[ "$(a_status_by_uri "$alice_on_a" "$p_poll_uri" | j "print(len(d[\"poll\"][\"options\"]))")" = "2" ]'&& ok "alice_akkoma's poll reaches Akkoma as a poll"|| ko "poll missing on Akkoma"
acurl -o /dev/null -X POST -H "$KH""$AK/api/v1/polls/$p_poll_on_a/votes" -d 'choices[]=1'
until_true 30'[ "$(curl -s -H "$PH" "$P/api/v1/accounts/$alice_self/statuses" | j "print(next(s[\"poll\"][\"options\"][1][\"votes_count\"] for s in d if s[\"uri\"]==\"$p_poll_uri\"))")" = "1" ]'&& ok "akuser's vote counts on PrivaPub"|| ko "vote not counted on PrivaPub"
a_poll=$(acurl -X POST -H "$KH""$AK/api/v1/statuses" -d 'status=tea or coffee, Akkoma asks&visibility=public&poll[options][]=tea&poll[options][]=coffee&poll[expires_in]=3600'| j "print(d['id'])")
until_true 30'curl -s -H "$PH" "$P/api/v1/timelines/home" | j "print(any(s[\"poll\"] and \"Akkoma asks\" in s[\"content\"] for s in d))" | grep -q True'&& ok "akuser's poll reaches PrivaPub as a poll"|| ko "poll missing on PrivaPub"
a_poll_on_p=$(curl -s -H "$PH""$P/api/v1/timelines/home"| j "print(next(s['poll']['id'] for s in d if s['poll'] and 'Akkoma asks' in s['content']))")
curl -s -o /dev/null -X POST -H "$PH""$P/api/v1/polls/$a_poll_on_p/votes" -d 'choices[]=0'
until_true 30'[ "$(acurl -H "$KH" "$AK/api/v1/statuses/$a_poll" | j "print(d[\"poll\"][\"options\"][0][\"votes_count\"])")" = "1" ]'&& ok "alice_akkoma's vote counts on Akkoma"|| ko "vote not counted on Akkoma"
echo" quotes"
a_quote=$(acurl -X POST -H "$KH""$AK/api/v1/statuses" -d "status=quoting PrivaPub&visibility=public"e_id=$p_post_on_a"| j "print(d['id'])")
until_true 30'curl -s -H "$PH" "$P/api/v1/timelines/home" | j "print(any(\"quoting PrivaPub\" in s[\"content\"] and (s.get(\"quote\") or {}).get(\"state\")==\"accepted\" for s in d))" | grep -q True'\
&& ok "akuser's quote arrives as an accepted quote"|| ko "Akkoma's quote not understood"
until_true 30'[ "$(a_status_by_uri "$alice_on_a" "$p_quote_uri" | j "print(d and ((d.get(\"quote\") or {}).get(\"id\") or d.get(\"quote_id\") or (d.get(\"pleroma\") or {}).get(\"quote_id\")) == \"$a_post_id\")")" = "True" ]'\
&& ok "alice_akkoma's quote is a quote on Akkoma"|| ko "quote not understood by Akkoma"
echo" media"
make_png "$work/red.png"
p_media=$(curl -s -X POST -H "$PH""$P/api/v2/media" -F "file=@$work/red.png;type=image/png" -F 'description=a red square'| j "print(d['id'])")
until_true 30'[ "$(a_status_by_uri "$alice_on_a" "$p_media_uri" | j "print(d[\"media_attachments\"][0][\"description\"])")" = "a red square" ]'&& ok "an image with alt text reaches Akkoma"|| ko "image or alt text missing on Akkoma"
a_media=$(acurl -X POST -H "$KH""$AK/api/v1/media" -F "file=@$work/red.png;type=image/png" -F 'description=a red square from Akkoma'| j "print(d['id'])")
acurl -o /dev/null -X POST -H "$KH""$AK/api/v1/statuses" -d "status=a picture from Akkoma&visibility=public&media_ids[]=$a_media"
until_true 30'curl -s -H "$PH" "$P/api/v1/timelines/home" | j "print(any(\"a picture from Akkoma\" in s[\"content\"] and s[\"media_attachments\"] and \"/media/proxy/\" in s[\"media_attachments\"][0][\"url\"] and s[\"media_attachments\"][0][\"description\"]==\"a red square from Akkoma\" for s in d))" | grep -q True'\
&& ok "an image with alt text from Akkoma arrives through our proxy"|| ko "Akkoma's image missing, unproxied or without alt text"
echo" edits and deletes"
curl -s -o /dev/null -X PUT -H "$PH""$P/api/v1/statuses/$p_post_id" -d 'status=Hello Akkoma from PrivaPub, edited'
until_true 30'acurl -H "$KH" "$AK/api/v1/statuses/$p_post_on_a" | grep -q "edited"'&& ok "alice_akkoma's edit reaches Akkoma"|| ko "edit not applied on Akkoma"
acurl -o /dev/null -X PUT -H "$KH""$AK/api/v1/statuses/$a_post_id" -d 'status=Hello PrivaPub from Akkoma, edited'
until_true 30'[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$a_post_on_p/history" | j "print(len(d))")" = "2" ]'&& ok "akuser's edit reaches PrivaPub with its history"|| ko "Akkoma's edit not applied on PrivaPub"
until_true 30'! curl -s -H "$PH" "$P/api/v1/timelines/home" | grep -q "Akkoma asks"'&& ok "akuser's delete reaches PrivaPub"|| ko "Akkoma's delete not applied on PrivaPub"
echo" blocks and unfollows"
curl -s -o /dev/null -X POST -H "$PH""$P/api/v1/accounts/$ak_on_p/unfollow"
until_true 30'[ "$(acurl -H "$KH" "$AK/api/v1/accounts/relationships?id[]=$alice_on_a" | j "print(d[0][\"followed_by\"])")" = "False" ]'&& ok "alice_akkoma's unfollow reaches Akkoma"|| ko "unfollow not applied on Akkoma"
curl -s -o /dev/null -X POST -H "$PH""$P/api/v1/accounts/$ak_on_p/block"
# Akkoma never reports a remote blocker as blocked_by, so the block is read from its user_relationships (1 is a block)
a_blocked(){ podman exec pasture-postgres psql -U pasture -d akkoma -tAc "select count(*) from user_relationships r join users a on a.id=r.source_id join users b on b.id=r.target_id where r.relationship_type=1 and a.nickname='alice_akkoma@privapub.test' and b.nickname='akuser'";}
until_true 30'[ "$(a_blocked)" = "1" ]'&& ok "alice_akkoma's block reaches Akkoma"|| ko "block not applied on Akkoma"
curl -s -o /dev/null -X POST -H "$PH""$P/api/v1/accounts/$ak_on_p/unblock"
until_true 30'[ "$(a_blocked)" = "0" ]'&& ok "alice_akkoma's unblock reaches Akkoma"|| ko "unblock not applied on Akkoma"