mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-05 19:28:25 +00:00
test(marmot): read the JSON shapes MDK 0.9.x actually emits
The harness was parsing a wire format `wn` no longer speaks, and every
mismatch failed silently as "nothing arrived".
`wn --json groups invites` now answers
`{"ok":true,"result":{"account_id":…,"invites":[…],"npub":…}}`. The
harness iterated `(.result // .) | .[]?`, which walks that object's three
VALUES — two strings and an array — so `jq_group_id` matched nothing on
every poll and the pending count printed 3 forever. Test 02 reported "B
never received invite" for welcomes that had in fact arrived.
Named collections moved the same way (`members`, `admins`, `messages`),
per-entry id fields were renamed (`member_id`, `admin_id`,
`message_id`), the decrypted body is `plaintext` rather than `content`,
the group display name lives in the profile component
(`.group.profile.name`), and `keys check` nests its event id under
`.key_package`.
Adds two helpers so this is fixed in one place rather than at 20 call
sites: `jq_list <name>` peels the envelope and names the collection, and
`jq_member_ids` reads whichever id field the collection uses. `jq_group_id`
now searches `.result.group_id`, `.result.group.group_id` and the bare
element shape, keeping the older serde encodings so a run against an
older `wn` still reports a real mismatch instead of an empty string.
Also fixes test 05, which fed wn's MLS group id to `amy marmot message
send`; amy indexes by the MIP-01 nostr_group_id, which it only learns
from its own `await group`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016kCuA6tc4JQzHPCDd39GHq
This commit is contained in:
+60
-28
@@ -145,36 +145,66 @@ expect_contains() {
|
|||||||
|
|
||||||
# ------- JSON helpers --------------------------------------------------------
|
# ------- JSON helpers --------------------------------------------------------
|
||||||
|
|
||||||
# Extract MLS group ID as lowercase hex from wn JSON output.
|
# Extract an MLS group id as lowercase hex from `wn --json` output.
|
||||||
# Handles both formats:
|
#
|
||||||
# - plain hex string (from `groups list`)
|
# MDK 0.9.x settled on one envelope, `{"ok":true,"result":{...}}`, but the
|
||||||
# - {"value":{"vec":[...]}} serde struct (from `groups create`)
|
# group id sits at a different place per verb:
|
||||||
# - flat byte array [n, ...] (from some responses)
|
# groups create -> .result.group_id
|
||||||
# Plus the three wrapper shapes wn actually uses:
|
# groups accept / rename -> .result.group.group_id
|
||||||
# - {"result": {"mls_group_id": ...}} (groups create)
|
# groups invites[] -> .group_id (an element, already peeled)
|
||||||
# - {"group": {"mls_group_id": ...}, "membership": ...} (groups invites[0])
|
# groups members/admins -> .result.group_id
|
||||||
# - {"mls_group_id": ...} (bare)
|
# Older builds wrapped the id as a serde `{"value":{"vec":[...]}}` struct or a
|
||||||
# Input: JSON string via stdin; optional 2nd arg = field name (default: mls_group_id)
|
# bare byte array; both are still decoded so a run against an older `wn` binary
|
||||||
|
# reports a real mismatch instead of an empty string.
|
||||||
|
#
|
||||||
|
# Input: JSON on stdin. Optional 1st arg overrides the field name.
|
||||||
jq_group_id() {
|
jq_group_id() {
|
||||||
local field="${1:-mls_group_id}"
|
local field="${1:-group_id}"
|
||||||
jq -r --arg f "$field" '
|
jq -r --arg f "$field" '
|
||||||
def byte2hex:
|
def byte2hex:
|
||||||
. as $n |
|
. as $n |
|
||||||
[($n / 16 | floor), ($n % 16)] |
|
[($n / 16 | floor), ($n % 16)] |
|
||||||
map(if . < 10 then (48 + .) else (87 + .) end) |
|
map(if . < 10 then (48 + .) else (87 + .) end) |
|
||||||
implode;
|
implode;
|
||||||
(.group // .result // .) |
|
def as_hex:
|
||||||
(.group // .) |
|
if type == "string" then .
|
||||||
.[$f] |
|
elif (type == "object" and (.value.vec != null)) then
|
||||||
if type == "string" then .
|
[.value.vec[] | byte2hex] | join("")
|
||||||
elif (type == "object" and (.value.vec != null)) then
|
elif type == "array" then
|
||||||
[.value.vec[] | byte2hex] | join("")
|
[.[] | byte2hex] | join("")
|
||||||
elif type == "array" then
|
else empty end;
|
||||||
[.[] | byte2hex] | join("")
|
[ (.result? // empty), (.result?.group? // empty), (.group? // empty), . ]
|
||||||
else empty end
|
| map(select(type == "object") | .[$f]? // empty | as_hex)
|
||||||
|
| map(select(. != null and . != ""))
|
||||||
|
| first // empty
|
||||||
' 2>/dev/null || true
|
' 2>/dev/null || true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Peel MDK 0.9.x's `{"ok":true,"result":{...}}` envelope and hand back the
|
||||||
|
# named collection as a JSON array. MDK moved every list one level in and gave
|
||||||
|
# it a name (`invites`, `members`, `admins`, `messages`), so a bare
|
||||||
|
# `(.result // .) | .[]?` now iterates the RESULT OBJECT'S VALUES — three
|
||||||
|
# scalars where the harness expected invite objects. That failure is silent:
|
||||||
|
# every poll simply never matches, and the test reports "never received
|
||||||
|
# invite" for a welcome that arrived and was accepted.
|
||||||
|
#
|
||||||
|
# Input: JSON on stdin, collection name as $1.
|
||||||
|
jq_list() {
|
||||||
|
local name="$1"
|
||||||
|
jq -c --arg n "$name" '
|
||||||
|
[ (.result?[$n]? // empty), (.[$n]? // empty), (.result? // empty), . ]
|
||||||
|
| map(select(type == "array"))
|
||||||
|
| (first // [])
|
||||||
|
| .[]
|
||||||
|
' 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
|
# npub or hex pubkey of one member/admin entry. MDK names the field per
|
||||||
|
# collection: members carry `member_id`, admins carry `admin_id`.
|
||||||
|
jq_member_ids() {
|
||||||
|
jq -r '.member_id? // .admin_id? // .pubkey? // .public_key? // empty' 2>/dev/null || true
|
||||||
|
}
|
||||||
|
|
||||||
# ------- polling helpers -----------------------------------------------------
|
# ------- polling helpers -----------------------------------------------------
|
||||||
|
|
||||||
# Snapshot currently-pending invites on <B|C> as a comma-separated list of
|
# Snapshot currently-pending invites on <B|C> as a comma-separated list of
|
||||||
@@ -197,7 +227,7 @@ snapshot_invites() {
|
|||||||
local g
|
local g
|
||||||
g=$(printf '%s' "$one" | jq_group_id)
|
g=$(printf '%s' "$one" | jq_group_id)
|
||||||
[[ -n "$g" ]] && gids+=("$g")
|
[[ -n "$g" ]] && gids+=("$g")
|
||||||
done < <(printf '%s' "$raw" | jq -c '(.result // .) | .[]?' 2>/dev/null)
|
done < <(printf '%s' "$raw" | jq_list invites)
|
||||||
# bash 3.2 (stock macOS) treats "${gids[*]}" on an empty array as an
|
# bash 3.2 (stock macOS) treats "${gids[*]}" on an empty array as an
|
||||||
# unbound reference under `set -u`, so guard the expansion.
|
# unbound reference under `set -u`, so guard the expansion.
|
||||||
if (( ${#gids[@]} > 0 )); then
|
if (( ${#gids[@]} > 0 )); then
|
||||||
@@ -228,9 +258,10 @@ wait_for_invite() {
|
|||||||
deadline=$(( start + timeout ))
|
deadline=$(( start + timeout ))
|
||||||
last_hb=$start
|
last_hb=$start
|
||||||
while [[ $(date +%s) -lt $deadline ]]; do
|
while [[ $(date +%s) -lt $deadline ]]; do
|
||||||
# Post-v0.2 `wn --json groups invites` returns `{"result": [...]}`
|
# MDK 0.9.x returns `{"ok":true,"result":{"invites":[...], …}}`.
|
||||||
# (older builds returned the bare array). Peel the wrapper when
|
# `jq_list` peels the envelope AND names the collection; iterating
|
||||||
# present so a pending invite is actually detected.
|
# `.result` directly walks the sibling scalars instead and never
|
||||||
|
# matches.
|
||||||
local raw
|
local raw
|
||||||
raw=$("$wnfn" --json groups invites 2>/dev/null || true)
|
raw=$("$wnfn" --json groups invites 2>/dev/null || true)
|
||||||
# Walk every pending invite (not just .[0]) so we skip past stales.
|
# Walk every pending invite (not just .[0]) so we skip past stales.
|
||||||
@@ -242,14 +273,14 @@ wait_for_invite() {
|
|||||||
printf '%s\n' "$gid"
|
printf '%s\n' "$gid"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
done < <(printf '%s' "$raw" | jq -c '(.result // .) | .[]?' 2>/dev/null)
|
done < <(printf '%s' "$raw" | jq_list invites)
|
||||||
|
|
||||||
# Heartbeat every ~10s.
|
# Heartbeat every ~10s.
|
||||||
local now=$(date +%s)
|
local now=$(date +%s)
|
||||||
if (( now - last_hb >= 10 )); then
|
if (( now - last_hb >= 10 )); then
|
||||||
local elapsed=$(( now - start )) remaining=$(( deadline - now ))
|
local elapsed=$(( now - start )) remaining=$(( deadline - now ))
|
||||||
local pending
|
local pending
|
||||||
pending=$(printf '%s' "$raw" | jq '(.result // .) | length' 2>/dev/null || echo "?")
|
pending=$(printf '%s' "$raw" | jq_list invites | wc -l | tr -d ' ')
|
||||||
local recent=""
|
local recent=""
|
||||||
if [[ -f "$data_dir/logs/stderr.log" ]]; then
|
if [[ -f "$data_dir/logs/stderr.log" ]]; then
|
||||||
recent=$(tail -n 200 "$data_dir/logs/stderr.log" 2>/dev/null \
|
recent=$(tail -n 200 "$data_dir/logs/stderr.log" 2>/dev/null \
|
||||||
@@ -277,9 +308,10 @@ wait_for_message() {
|
|||||||
else
|
else
|
||||||
payload=$(wn_c_json messages list "$gid" --limit 20 2>/dev/null || true)
|
payload=$(wn_c_json messages list "$gid" --limit 20 2>/dev/null || true)
|
||||||
fi
|
fi
|
||||||
|
# MDK 0.9.x: `.result.messages[]`, decrypted body in `plaintext`.
|
||||||
if [[ -n "${payload:-}" ]] && \
|
if [[ -n "${payload:-}" ]] && \
|
||||||
printf '%s' "$payload" | jq -e --arg n "$needle" \
|
printf '%s' "$payload" | jq_list messages | jq -e --arg n "$needle" \
|
||||||
'(.result // .) | .[]? | select((.content // .text // "") | contains($n))' \
|
'select((.plaintext // .content // .text // "") | contains($n))' \
|
||||||
>/dev/null 2>&1; then
|
>/dev/null 2>&1; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -184,12 +184,19 @@ test_05_b_adds_a_existing() {
|
|||||||
record_result "$id" fail "wn add-members A failed"; return
|
record_result "$id" fail "wn add-members A failed"; return
|
||||||
}
|
}
|
||||||
|
|
||||||
# A joins
|
# A joins. `gid` is wn's MLS group id; amy indexes by the MIP-01
|
||||||
if ! amy_json marmot await group --name "Interop-05" --timeout 30 >/dev/null; then
|
# nostr_group_id, which only exists locally once A has processed the
|
||||||
|
# welcome — so take amy's id from its own await, never wn's.
|
||||||
|
local a_out a_gid
|
||||||
|
a_out=$(amy_json marmot await group --name "Interop-05" --timeout 30) || {
|
||||||
record_result "$id" fail "A never received invite to Interop-05"; return
|
record_result "$id" fail "A never received invite to Interop-05"; return
|
||||||
|
}
|
||||||
|
a_gid=$(printf '%s' "$a_out" | jq -r '.group_id // empty')
|
||||||
|
if [[ -z "$a_gid" ]]; then
|
||||||
|
record_result "$id" fail "A joined Interop-05 but reported no group_id"; return
|
||||||
fi
|
fi
|
||||||
|
|
||||||
amy_json marmot message send "$gid" "joined from amethyst" >/dev/null || {
|
amy_json marmot message send "$a_gid" "joined from amethyst" >/dev/null || {
|
||||||
record_result "$id" fail "amy send failed"; return
|
record_result "$id" fail "amy send failed"; return
|
||||||
}
|
}
|
||||||
if wait_for_message B "$gid" "joined from amethyst" 90 \
|
if wait_for_message B "$gid" "joined from amethyst" 90 \
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ test_09_reply_react_unreact() {
|
|||||||
# B anchors. Needs a member to be present — if Test 11 already ran and A left,
|
# B anchors. Needs a member to be present — if Test 11 already ran and A left,
|
||||||
# skip cleanly so we don't double-fail.
|
# skip cleanly so we don't double-fail.
|
||||||
if ! wn_b --json groups members "$mls_gid" 2>/dev/null \
|
if ! wn_b --json groups members "$mls_gid" 2>/dev/null \
|
||||||
| jq -e --arg p "$A_HEX" '(.result // .) | .[]? | select((.pubkey // .public_key) == $p)' \
|
| jq_list members | jq -e --arg p "$A_HEX" \
|
||||||
|
'select((.member_id // .pubkey // .public_key) == $p)' \
|
||||||
>/dev/null 2>&1; then
|
>/dev/null 2>&1; then
|
||||||
record_result "$id" skip "A already left GROUP_02"; return
|
record_result "$id" skip "A already left GROUP_02"; return
|
||||||
fi
|
fi
|
||||||
@@ -26,7 +27,9 @@ test_09_reply_react_unreact() {
|
|||||||
sleep 3
|
sleep 3
|
||||||
local msg_id
|
local msg_id
|
||||||
msg_id=$(wn_b --json messages list "$mls_gid" --limit 10 2>/dev/null \
|
msg_id=$(wn_b --json messages list "$mls_gid" --limit 10 2>/dev/null \
|
||||||
| jq -r '[(.result // .) | .[]? | select((.content // .text // "") == "anchor for reactions")][0].id // empty')
|
| jq_list messages \
|
||||||
|
| jq -r 'select((.plaintext // .content // .text // "") == "anchor for reactions")
|
||||||
|
| (.message_id // .id)' | head -n 1)
|
||||||
if [[ -z "$msg_id" || "$msg_id" == "null" ]]; then
|
if [[ -z "$msg_id" || "$msg_id" == "null" ]]; then
|
||||||
record_result "$id" fail "couldn't find anchor message id"; return
|
record_result "$id" fail "couldn't find anchor message id"; return
|
||||||
fi
|
fi
|
||||||
@@ -47,7 +50,9 @@ test_09_reply_react_unreact() {
|
|||||||
sleep 3
|
sleep 3
|
||||||
local a_anchor_id
|
local a_anchor_id
|
||||||
a_anchor_id=$(amy_json marmot message list "$gid" --limit 50 2>/dev/null \
|
a_anchor_id=$(amy_json marmot message list "$gid" --limit 50 2>/dev/null \
|
||||||
| jq -r '[.messages[]? | select((.content // "") == "anchor for reactions")][0].event_id // empty')
|
| jq_list messages \
|
||||||
|
| jq -r 'select((.plaintext // .content // "") == "anchor for reactions")
|
||||||
|
| (.message_id // .event_id)' | head -n 1)
|
||||||
if [[ -z "$a_anchor_id" || "$a_anchor_id" == "null" ]]; then
|
if [[ -z "$a_anchor_id" || "$a_anchor_id" == "null" ]]; then
|
||||||
record_result "$id" fail "amy couldn't find anchor message in local log"; return
|
record_result "$id" fail "amy couldn't find anchor message in local log"; return
|
||||||
fi
|
fi
|
||||||
@@ -67,7 +72,7 @@ test_09_reply_react_unreact() {
|
|||||||
payload=$(wn_b_json messages list "$mls_gid" --limit 50 2>/dev/null || true)
|
payload=$(wn_b_json messages list "$mls_gid" --limit 50 2>/dev/null || true)
|
||||||
if [[ -n "$payload" ]] && \
|
if [[ -n "$payload" ]] && \
|
||||||
printf '%s' "$payload" \
|
printf '%s' "$payload" \
|
||||||
| jq -e '(.result // .) | .[]? | (.reactions.by_emoji // {}) | keys[]?' \
|
| jq_list messages | jq -e '(.reactions.by_emoji // {}) | keys[]?' \
|
||||||
2>/dev/null \
|
2>/dev/null \
|
||||||
| grep -qF '"🍕"'; then
|
| grep -qF '"🍕"'; then
|
||||||
saw=1; break
|
saw=1; break
|
||||||
@@ -92,7 +97,8 @@ test_10_concurrent_commits() {
|
|||||||
record_result "$id" skip "no GROUP_02"; return
|
record_result "$id" skip "no GROUP_02"; return
|
||||||
fi
|
fi
|
||||||
if ! wn_b --json groups members "$mls_gid" 2>/dev/null \
|
if ! wn_b --json groups members "$mls_gid" 2>/dev/null \
|
||||||
| jq -e --arg p "$A_HEX" '(.result // .) | .[]? | select((.pubkey // .public_key) == $p)' \
|
| jq_list members | jq -e --arg p "$A_HEX" \
|
||||||
|
'select((.member_id // .pubkey // .public_key) == $p)' \
|
||||||
>/dev/null 2>&1; then
|
>/dev/null 2>&1; then
|
||||||
record_result "$id" skip "A already left GROUP_02"; return
|
record_result "$id" skip "A already left GROUP_02"; return
|
||||||
fi
|
fi
|
||||||
@@ -110,7 +116,8 @@ test_10_concurrent_commits() {
|
|||||||
# whitenoise-rs ≥ v0.2.x wraps the group payload one level deeper as
|
# whitenoise-rs ≥ v0.2.x wraps the group payload one level deeper as
|
||||||
# `{"result": {"group": {…name…}}}`; the older shape was a bare group
|
# `{"result": {"group": {…name…}}}`; the older shape was a bare group
|
||||||
# object under `.result`. Accept both.
|
# object under `.result`. Accept both.
|
||||||
b_name=$(wn_b --json groups show "$mls_gid" 2>/dev/null | jq -r '(.result // .) | (.group // .) | .name // empty')
|
b_name=$(wn_b --json groups show "$mls_gid" 2>/dev/null \
|
||||||
|
| jq -r '(.result // .) | (.group // .) | (.profile.name // .name) // empty')
|
||||||
local a_name
|
local a_name
|
||||||
a_name=$(amy_field '.name' marmot group show "$gid" 2>/dev/null || echo "")
|
a_name=$(amy_field '.name' marmot group show "$gid" 2>/dev/null || echo "")
|
||||||
|
|
||||||
@@ -194,7 +201,8 @@ test_13_keypackage_rotation() {
|
|||||||
local id="13 keypackage rotation"
|
local id="13 keypackage rotation"
|
||||||
|
|
||||||
local before
|
local before
|
||||||
before=$(wn_b --json keys check "$A_NPUB" 2>/dev/null | jq -r '.result.event_id // empty')
|
before=$(wn_b --json keys check "$A_NPUB" 2>/dev/null \
|
||||||
|
| jq -r '.result.key_package.key_package_event_id // .result.event_id // empty')
|
||||||
if [[ -z "$before" ]]; then
|
if [[ -z "$before" ]]; then
|
||||||
record_result "$id" fail "no prior KP for A"; return
|
record_result "$id" fail "no prior KP for A"; return
|
||||||
fi
|
fi
|
||||||
@@ -205,7 +213,8 @@ test_13_keypackage_rotation() {
|
|||||||
|
|
||||||
local deadline=$(( $(date +%s) + 60 )) after=""
|
local deadline=$(( $(date +%s) + 60 )) after=""
|
||||||
while [[ $(date +%s) -lt $deadline ]]; do
|
while [[ $(date +%s) -lt $deadline ]]; do
|
||||||
after=$(wn_b --json keys check "$A_NPUB" 2>/dev/null | jq -r '.result.event_id // empty')
|
after=$(wn_b --json keys check "$A_NPUB" 2>/dev/null \
|
||||||
|
| jq -r '.result.key_package.key_package_event_id // .result.event_id // empty')
|
||||||
[[ -n "$after" && "$after" != "$before" ]] && break
|
[[ -n "$after" && "$after" != "$before" ]] && break
|
||||||
sleep 3
|
sleep 3
|
||||||
done
|
done
|
||||||
@@ -323,9 +332,9 @@ test_15_wn_member_leaves() {
|
|||||||
local show
|
local show
|
||||||
show=$(amy_json marmot group show "$a_gid" 2>/dev/null) || { sleep 3; continue; }
|
show=$(amy_json marmot group show "$a_gid" 2>/dev/null) || { sleep 3; continue; }
|
||||||
local c_still
|
local c_still
|
||||||
c_still=$(printf '%s' "$show" | jq --arg p "$C_HEX" '[.members[]? | select(.pubkey == $p)] | length')
|
c_still=$(printf '%s' "$show" | jq --arg p "$C_HEX" '[.members[]? | select((.pubkey // .member_id) == $p)] | length')
|
||||||
local a_still
|
local a_still
|
||||||
a_still=$(printf '%s' "$show" | jq --arg p "$A_HEX" '[.members[]? | select(.pubkey == $p)] | length')
|
a_still=$(printf '%s' "$show" | jq --arg p "$A_HEX" '[.members[]? | select((.pubkey // .member_id) == $p)] | length')
|
||||||
if [[ "$c_still" == "0" && "$a_still" == "1" ]]; then
|
if [[ "$c_still" == "0" && "$a_still" == "1" ]]; then
|
||||||
ok=1; break
|
ok=1; break
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ test_06_member_removal() {
|
|||||||
local deadline=$(( $(date +%s) + 120 )) removed=0
|
local deadline=$(( $(date +%s) + 120 )) removed=0
|
||||||
while [[ $(date +%s) -lt $deadline ]]; do
|
while [[ $(date +%s) -lt $deadline ]]; do
|
||||||
if ! wn_c --json groups members "$mls_gid" 2>/dev/null \
|
if ! wn_c --json groups members "$mls_gid" 2>/dev/null \
|
||||||
| jq -e --arg p "$C_HEX" '(.result // .) | .[]? | select((.pubkey // .public_key) == $p)' \
|
| jq_list members | jq -e --arg p "$C_HEX" \
|
||||||
|
'select((.member_id // .pubkey // .public_key) == $p)' \
|
||||||
>/dev/null 2>&1; then
|
>/dev/null 2>&1; then
|
||||||
removed=1; break
|
removed=1; break
|
||||||
fi
|
fi
|
||||||
@@ -78,7 +79,10 @@ test_07_metadata_rename() {
|
|||||||
# `{"result": {"group": {…name…}}}`; older builds returned the bare
|
# `{"result": {"group": {…name…}}}`; older builds returned the bare
|
||||||
# group object under `.result`. Probe both shapes so the test survives
|
# group object under `.result`. Probe both shapes so the test survives
|
||||||
# either schema.
|
# either schema.
|
||||||
seen=$(wn_b --json groups show "$mls_gid" 2>/dev/null | jq -r '(.result // .) | (.group // .) | .name // empty')
|
# MDK 0.9.x keeps the display name in the profile component, not a
|
||||||
|
# top-level `name`: `.result.group.profile.name`.
|
||||||
|
seen=$(wn_b --json groups show "$mls_gid" 2>/dev/null \
|
||||||
|
| jq -r '(.result // .) | (.group // .) | (.profile.name // .name) // empty')
|
||||||
[[ "$seen" == "Interop-02-renamed" ]] && break
|
[[ "$seen" == "Interop-02-renamed" ]] && break
|
||||||
sleep 3
|
sleep 3
|
||||||
done
|
done
|
||||||
@@ -151,7 +155,7 @@ test_08_admin_promote_demote() {
|
|||||||
|
|
||||||
local admins
|
local admins
|
||||||
admins=$(wn_b --json groups admins "$mls_gid" 2>/dev/null \
|
admins=$(wn_b --json groups admins "$mls_gid" 2>/dev/null \
|
||||||
| jq -r '(.result // .) | .[]?.pubkey // .[]?.public_key // .[]?' | tr '\n' ' ')
|
| jq_list admins | jq_member_ids | tr '\n' ' ')
|
||||||
if [[ "$admins" == *"$A_HEX"* ]]; then
|
if [[ "$admins" == *"$A_HEX"* ]]; then
|
||||||
record_result "$id" fail "A still admin after demote"
|
record_result "$id" fail "A still admin after demote"
|
||||||
else
|
else
|
||||||
@@ -177,7 +181,8 @@ test_11_leave_group() {
|
|||||||
local deadline=$(( $(date +%s) + 120 )) gone=0
|
local deadline=$(( $(date +%s) + 120 )) gone=0
|
||||||
while [[ $(date +%s) -lt $deadline ]]; do
|
while [[ $(date +%s) -lt $deadline ]]; do
|
||||||
if ! wn_b --json groups members "$mls_gid" 2>/dev/null \
|
if ! wn_b --json groups members "$mls_gid" 2>/dev/null \
|
||||||
| jq -e --arg p "$A_HEX" '(.result // .) | .[]? | select((.pubkey // .public_key) == $p)' \
|
| jq_list admins | jq -e --arg p "$A_HEX" \
|
||||||
|
'select((.admin_id // .pubkey // .public_key) == $p)' \
|
||||||
>/dev/null 2>&1; then
|
>/dev/null 2>&1; then
|
||||||
gone=1; break
|
gone=1; break
|
||||||
fi
|
fi
|
||||||
@@ -218,7 +223,8 @@ test_17_group_image_commit() {
|
|||||||
# Skip cleanly if A is no longer a member of GROUP_02 (a later test may have removed
|
# Skip cleanly if A is no longer a member of GROUP_02 (a later test may have removed
|
||||||
# A) — this test only makes sense while A can still commit to the group.
|
# A) — this test only makes sense while A can still commit to the group.
|
||||||
if ! wn_b --json groups members "$mls_gid" 2>/dev/null \
|
if ! wn_b --json groups members "$mls_gid" 2>/dev/null \
|
||||||
| jq -e --arg p "$A_HEX" '(.result // .) | .[]? | select((.pubkey // .public_key) == $p)' \
|
| jq_list members | jq -e --arg p "$A_HEX" \
|
||||||
|
'select((.member_id // .pubkey // .public_key) == $p)' \
|
||||||
>/dev/null 2>&1; then
|
>/dev/null 2>&1; then
|
||||||
record_result "$id" skip "A not in GROUP_02"; return
|
record_result "$id" skip "A not in GROUP_02"; return
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user