Pasture: Vernissage 1.43.0
Vernissage joins the pasture on SQLite with its queues on the shared Redis; scenarios/vernissage.sh: follows both ways, a photo with its alt text, likes, boosts and comments both ways, a deletion, the unfollow and statistics: 19 checks, with no change to PrivaPub. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
1 parent
53158b4cf4
commit
b218768904
6 files changed
+125
No files matched your search
@@ -108,6 +108,11 @@ nodebb.test {
|
||||
reverse_proxy pasture-nodebb:4567
|
||||
}
|
||||
|
||||
vernissage.test {
|
||||
tls internal
|
||||
reverse_proxy pasture-vernissage:8080
|
||||
}
|
||||
|
||||
bookwyrm.test {
|
||||
tls internal
|
||||
reverse_proxy pasture-bookwyrm:8000
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# Vernissage 1.43.0: photo sharing in Swift (Vapor), Pixelfed's neighbour: every top-level post carries photos with
|
||||
# their EXIF (camera, lens, film...), comments thread under them. Its image on SQLite with local storage in its own
|
||||
# volume and its queues on the shared Redis (database 0, the last free one: without queues it federates nothing), as
|
||||
# vernissage.test; its TLS client reads the system's roots, over which the pasture's bundle goes. It seeds an
|
||||
# admin (admin/admin) whose token comes from its login API.
|
||||
VERNISSAGE_IMAGE=${VERNISSAGE_IMAGE:-docker.io/mczachurski/vernissage-server:v1.43.0}
|
||||
|
||||
. "$here/peers/shared.sh"
|
||||
|
||||
vernissage_up() {
|
||||
shared_redis_up
|
||||
podman volume exists pasture-vernissage || podman volume create --label pasture=1 pasture-vernissage >/dev/null
|
||||
podman run -d --replace --name pasture-vernissage --label pasture=1 --network $net -v pasture-vernissage:/data \
|
||||
-e VERNISSAGE_BASEADDRESS=https://vernissage.test -e VERNISSAGE_CONNECTIONSTRING=/data/vernissage.db -e VERNISSAGE_QUEUEURL=redis://redis:6379/0 \
|
||||
-v "$ca/bundle.pem:/etc/ssl/certs/ca-certificates.crt:z,ro" $VERNISSAGE_IMAGE >/dev/null
|
||||
for _ in $(seq 1 60); do
|
||||
site vernissage.test -s -o /dev/null -w '%{http_code}' https://vernissage.test:6443/.well-known/nodeinfo 2>/dev/null | grep -q 200 && break
|
||||
sleep 2
|
||||
done
|
||||
mkdir -p "$here/.state/vernissage"
|
||||
site vernissage.test -s -X POST https://vernissage.test:6443/api/v1/account/login -H 'Content-Type: application/json' \
|
||||
-d '{"userNameOrEmail":"admin","password":"admin"}' \
|
||||
| python3 -c 'import json, sys; print(json.load(sys.stdin).get("accessToken", ""))' > "$here/.state/vernissage/admin.token"
|
||||
echo "vernissage: https://vernissage.test:6443"
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
# Vernissage 1.43.0: follows both ways; a photo post with its alt text and camera reaches alice; her like, boost and
|
||||
# comment land there; her photo post reaches the admin's home and its like and comment come back; a deletion; the
|
||||
# unfollow; statistics. Driven through its API as its seeded admin.
|
||||
VE=https://vernissage.test:6443
|
||||
VT=$(site vernissage.test -s -X POST $VE/api/v1/account/login -H 'Content-Type: application/json' -d '{"userNameOrEmail":"admin","password":"admin"}' | j "print(d['accessToken'])")
|
||||
ve() { site vernissage.test -s -H "Authorization: Bearer $VT" "$@"; }
|
||||
ve_json() { local method=$1 path=$2 body=$3; ve -X "$method" "$VE$path" -H 'Content-Type: application/json' -d "$body"; }
|
||||
# ve_post <json>: a status, waited for when Vernissage says statuses come too often (one every 40 seconds or so)
|
||||
ve_post() {
|
||||
local answer
|
||||
for _ in $(seq 1 12); do
|
||||
answer=$(ve_json POST /api/v1/statuses "$1")
|
||||
echo "$answer" | grep -q statusCreationTooFrequent || break
|
||||
sleep 5
|
||||
done
|
||||
echo "$answer"
|
||||
}
|
||||
p_home_has() { curl -s -H "$PH" "$P/api/v1/timelines/home?limit=40" | j "print(next(((s.get('reblog') or s)['id'] for s in d if '$1' in ((s.get('reblog') or s)['content'] or '')), ''))"; }
|
||||
p_status() { curl -s -H "$PH" "$P/api/v1/statuses/$1" | j "print(d.get('$2'))"; }
|
||||
|
||||
echo "vernissage"
|
||||
[ -n "$VT" ] && ok "Vernissage token for admin" || { ko "Vernissage token"; return 1; }
|
||||
PT=$(privapub_token alice_vern)
|
||||
PH="Authorization: Bearer $PT"
|
||||
[ -n "$PT" ] && ok "PrivaPub token for alice_vern" || { ko "PrivaPub token for alice_vern"; return 1; }
|
||||
run=$(date +%s)
|
||||
|
||||
echo " follows"
|
||||
ve "$VE/api/v1/search?query=alice_vern%40privapub.test&type=users" >/dev/null
|
||||
ve -o /dev/null -X POST "$VE/api/v1/users/alice_vern@privapub.test/follow"
|
||||
until_true 45 '[ "$(curl -s -H "$PH" "$P/api/v1/accounts/verify_credentials" | j "print(d[\"followers_count\"])")" -ge 1 ]' \
|
||||
&& ok "the admin follows alice" || ko "Vernissage's follow never reached alice"
|
||||
ve_on_p=$(curl -s -H "$PH" "$P/api/v2/search?q=admin@vernissage.test&resolve=true&type=accounts" | j "print(d['accounts'][0]['id'])")
|
||||
[ -n "$ve_on_p" ] && ok "PrivaPub resolves Vernissage's admin" || ko "PrivaPub cannot resolve Vernissage's admin"
|
||||
curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/accounts/$ve_on_p/follow"
|
||||
until_true 45 '[ "$(curl -s -H "$PH" "$P/api/v1/accounts/relationships?id[]=$ve_on_p" | j "print(d[0][\"following\"])")" = "True" ]' \
|
||||
&& ok "alice follows the admin (Accept arrived)" || ko "Vernissage's Accept never arrived"
|
||||
|
||||
echo " photos"
|
||||
png="$here/.state/vernissage/photo.png"
|
||||
make_png "$png"
|
||||
# (its upload answers with the attachment, which goes back whole with the alt text and the camera)
|
||||
uploaded=$(ve -X POST "$VE/api/v1/attachments" -F "file=@$png;type=image/png")
|
||||
att=$(echo "$uploaded" | j "print(d['id'])")
|
||||
ve_json PUT "/api/v1/attachments/$att" "$(echo "$uploaded" | j "d.update(description='a red square $run', make='Leica', model='M6'); print(json.dumps(d))")" >/dev/null
|
||||
post=$(ve_post "{\"note\":\"a Vernissage photo $run\",\"visibility\":\"public\",\"sensitive\":false,\"commentsDisabled\":false,\"attachmentIds\":[\"$att\"]}")
|
||||
post_id=$(echo "$post" | j "print(d['id'])")
|
||||
until_true 60 '[ -n "$(p_home_has "a Vernissage photo $run")" ]' && ok "the admin's photo reaches alice's home" || ko "the photo never reached alice ($(echo "$post" | head -c 200))"
|
||||
photo_on_p=$(p_home_has "a Vernissage photo $run")
|
||||
[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$photo_on_p" | j "print(d['media_attachments'][0]['description'] if d['media_attachments'] else None)")" = "a red square $run" ] \
|
||||
&& ok "with its picture and alt text" || ko "the photo arrived without its picture or alt text"
|
||||
curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/statuses/$photo_on_p/favourite"
|
||||
until_true 45 '[ "$(ve "$VE/api/v1/statuses/$post_id" | j "print(d[\"favouritesCount\"])")" = "1" ]' && ok "alice's like counts on Vernissage" || ko "alice's like never counted on Vernissage"
|
||||
curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/statuses/$photo_on_p/reblog"
|
||||
until_true 45 '[ "$(ve "$VE/api/v1/statuses/$post_id" | j "print(d[\"reblogsCount\"])")" = "1" ]' && ok "alice's boost counts on Vernissage" || ko "alice's boost never counted on Vernissage"
|
||||
curl -s -o /dev/null -X POST -H "$PH" $P/api/v1/statuses -d "status=@admin@vernissage.test a PrivaPub comment $run&in_reply_to_id=$photo_on_p&visibility=public"
|
||||
until_true 45 've "$VE/api/v1/statuses/$post_id/context" | grep -q "a PrivaPub comment $run"' && ok "alice's comment threads under the photo" || ko "alice's comment never reached Vernissage"
|
||||
|
||||
echo " alice's photo"
|
||||
upload=$(curl -s -X POST -H "$PH" "$P/api/v2/media" -F "file=@$png;type=image/png" -F "description=a PrivaPub picture $run")
|
||||
p_post=$(curl -s -X POST -H "$PH" $P/api/v1/statuses -d "status=a PrivaPub photo for Vernissage $run&visibility=public&media_ids[]=$(echo "$upload" | j "print(d['id'])")")
|
||||
p_post_id=$(echo "$p_post" | j "print(d['id'])")
|
||||
until_true 60 've "$VE/api/v1/timelines/home?limit=40" | grep -q "a PrivaPub photo for Vernissage $run"' && ok "alice's photo reaches the admin's home" || ko "alice's photo never reached Vernissage"
|
||||
p_on_ve=$(ve "$VE/api/v1/timelines/home?limit=40" | j "print(next((s['id'] for s in d.get('data', d) if 'a PrivaPub photo for Vernissage $run' in (s.get('note') or '')), ''))")
|
||||
ve -o /dev/null -X POST "$VE/api/v1/statuses/$p_on_ve/favourite"
|
||||
until_true 45 '[ "$(p_status $p_post_id favourites_count)" = "1" ]' && ok "the admin's like counts on PrivaPub" || ko "Vernissage's like never counted"
|
||||
ve_post "{\"note\":\"a Vernissage comment $run\",\"visibility\":\"public\",\"sensitive\":false,\"commentsDisabled\":false,\"replyToStatusId\":\"$p_on_ve\",\"attachmentIds\":[]}" >/dev/null
|
||||
until_true 45 '[ "$(curl -s -H "$PH" "$P/api/v1/statuses/$p_post_id/context" | j "print(any(\"a Vernissage comment $run\" in s[\"content\"] for s in d[\"descendants\"]))")" = "True" ]' \
|
||||
&& ok "the admin's comment threads under alice's photo" || ko "Vernissage's comment missing on PrivaPub"
|
||||
|
||||
echo " deletions"
|
||||
ve -o /dev/null -X DELETE "$VE/api/v1/statuses/$post_id"
|
||||
until_true 45 '[ "$(curl -s -o /dev/null -w "%{http_code}" -H "$PH" "$P/api/v1/statuses/$photo_on_p")" = "404" ]' \
|
||||
&& ok "the admin's deletion reaches PrivaPub" || ko "the deleted photo still shows on PrivaPub"
|
||||
|
||||
echo " unfollow"
|
||||
curl -s -o /dev/null -X POST -H "$PH" "$P/api/v1/accounts/$ve_on_p/unfollow"
|
||||
until_true 45 '[ "$(ve "$VE/api/v1/users/admin" | j "print(d[\"followersCount\"])")" = "0" ]' && ok "alice's unfollow reaches Vernissage" || ko "Vernissage still counts alice"
|
||||
|
||||
echo " statistics"
|
||||
stats_check vernissage.test vernissage
|
||||
Reference in new issue
Block a user