9dfa06ffee
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
Signed-off-by: cls_宁波本机 <908705107@qq.com>
624 lines
20 KiB
Markdown
624 lines
20 KiB
Markdown
# buzz-cli Live Testing Guide
|
|
|
|
Manual testing runbook for verifying every CLI command against a local relay.
|
|
An agent or developer follows this step by step, running each command and
|
|
checking the output.
|
|
|
|
---
|
|
|
|
## 1. Prerequisites
|
|
|
|
Docker services running and healthy:
|
|
|
|
```bash
|
|
docker compose ps
|
|
# buzz-postgres healthy
|
|
# buzz-redis healthy
|
|
```
|
|
|
|
If not running: `just setup` from the repo root.
|
|
|
|
Tools: `jq`, `curl`, Rust toolchain.
|
|
|
|
---
|
|
|
|
## 2. Build the CLI
|
|
|
|
```bash
|
|
cargo build -p buzz-cli
|
|
```
|
|
|
|
Use `cargo run -p buzz-cli --` or the built binary at `target/debug/buzz`.
|
|
|
|
---
|
|
|
|
## 3. Start the Relay
|
|
|
|
In a separate terminal:
|
|
|
|
```bash
|
|
cd REPOS/buzz-nostr
|
|
set -a && source .env && set +a
|
|
cargo run -p buzz-relay
|
|
```
|
|
|
|
Verify:
|
|
|
|
```bash
|
|
curl -s http://localhost:3000/_liveness
|
|
# "ok" or 200 status
|
|
```
|
|
|
|
The `.env` should have `BUZZ_REQUIRE_AUTH_TOKEN=false` for local dev.
|
|
|
|
---
|
|
|
|
## 4. Mint Test Credentials
|
|
|
|
### Option A: buzz-admin (full scopes including admin)
|
|
|
|
This mints a token with all CLI-relevant scopes (including `admin:channels`)
|
|
via direct DB access. Use this for testing admin operations (archive,
|
|
delete-channel, add/remove-channel-member).
|
|
|
|
```bash
|
|
DATABASE_URL="${DATABASE_URL:?set DATABASE_URL for the local Buzz database}" \
|
|
cargo run -p buzz-admin -- mint-token \
|
|
--name "cli-test" \
|
|
--scopes "messages:read,messages:write,channels:read,channels:write,users:read,users:write,files:read,files:write,admin:channels"
|
|
```
|
|
|
|
This generates a keypair and prints:
|
|
- **Private key (nsec)** — save for `BUZZ_PRIVATE_KEY` testing
|
|
|
|
Export:
|
|
|
|
```bash
|
|
export BUZZ_RELAY_URL="http://localhost:3000"
|
|
export BUZZ_PRIVATE_KEY="nsec1..." # from the mint output
|
|
```
|
|
|
|
### Scope reference
|
|
|
|
| Scope | Self-mintable | Needed for |
|
|
|-------|:---:|------------|
|
|
| `messages:read` | ✅ | `messages get`, `messages thread`, `messages search`, `feed get` |
|
|
| `messages:write` | ✅ | `messages send`, `messages edit`, `messages delete`, `reactions`, `messages vote` |
|
|
| `channels:read` | ✅ | `channels list`, `channels get`, `channels members` |
|
|
| `channels:write` | ✅ | `channels create`, `channels update`, `channels join`, `channels leave`, `channels topic`, `channels purpose` |
|
|
| `users:read` | ✅ | `users get`, `users presence` |
|
|
| `users:write` | ✅ | `users set-profile`, `users set-presence`, `users set-status` |
|
|
| `files:read` | ✅ | — |
|
|
| `files:write` | ✅ | — |
|
|
| `admin:channels` | ❌ | `channels archive`, `channels unarchive`, `channels delete`, `channels add-member`, `channels remove-member` |
|
|
|
|
---
|
|
|
|
## 5. Unit Tests
|
|
|
|
```bash
|
|
cargo test -p buzz-cli
|
|
# Expected: see cargo test -p buzz-cli for current count
|
|
|
|
cargo clippy -p buzz-cli -- -D warnings
|
|
# Expected: zero warnings
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Live Testing — Command by Command
|
|
|
|
Run each command, verify exit code 0 and check output. Most commands
|
|
return JSON (pipe through `jq .` to validate). Commands are ordered so
|
|
earlier ones create resources that later ones need.
|
|
|
|
### 6.1 Channels
|
|
|
|
```bash
|
|
# channels create (stream)
|
|
buzz channels create --name "test-stream" --type stream --visibility open \
|
|
--description "CLI test channel" | jq .
|
|
# Save the channel ID:
|
|
CHANNEL_ID=$(buzz channels create --name "test-cli" --type stream --visibility open | jq -r '.channel_id')
|
|
# Expected: {"event_id":"...","accepted":true,"message":"...","channel_id":"<uuid>"}
|
|
|
|
# channels create (forum) — needed for messages vote later
|
|
FORUM_ID=$(buzz channels create --name "test-forum" --type forum --visibility open | jq -r '.channel_id')
|
|
|
|
# channels list
|
|
buzz channels list | jq .
|
|
# Expected: [{"channel_id":"...","name":"...","description":"...","created_at":N}]
|
|
buzz channels list --visibility open | jq .
|
|
buzz channels list --member | jq .
|
|
|
|
# channels get
|
|
buzz channels get --channel "$CHANNEL_ID" | jq .
|
|
# Expected: {"channel_id":"...","name":"...","description":"...","created_at":N,"pubkey":"..."} or null
|
|
|
|
# channels update
|
|
buzz channels update --channel "$CHANNEL_ID" --name "test-cli-updated" \
|
|
--description "Updated" | jq .
|
|
# Expected: {"event_id":"...","accepted":true,"message":"..."}
|
|
|
|
# channels topic
|
|
buzz channels topic --channel "$CHANNEL_ID" --topic "Test topic" | jq .
|
|
# Expected: {"event_id":"...","accepted":true,"message":"..."}
|
|
|
|
# channels purpose
|
|
buzz channels purpose --channel "$CHANNEL_ID" --purpose "Testing" | jq .
|
|
# Expected: {"event_id":"...","accepted":true,"message":"..."}
|
|
|
|
# channels join (may already be a member from create)
|
|
buzz channels join --channel "$CHANNEL_ID" | jq .
|
|
# Expected: {"event_id":"...","accepted":true,"message":"..."}
|
|
|
|
# channels leave
|
|
# NOTE: Fails with 400 "cannot remove the last owner" if this identity is the
|
|
# sole owner (which it is after channels create). To test leave successfully,
|
|
# first add-member a second pubkey as owner. The relay enforces ≥1 owner.
|
|
buzz channels leave --channel "$CHANNEL_ID" | jq .
|
|
# Expected: {"event_id":"...","accepted":true,"message":"..."} (or 400 if last owner)
|
|
|
|
# Re-join so we can send messages
|
|
buzz channels join --channel "$CHANNEL_ID" | jq .
|
|
# Expected: {"event_id":"...","accepted":true,"message":"..."}
|
|
|
|
# channels archive (requires admin:channels scope)
|
|
buzz channels archive --channel "$CHANNEL_ID" | jq .
|
|
# Expected: {"event_id":"...","accepted":true,"message":"..."}
|
|
|
|
# channels unarchive
|
|
buzz channels unarchive --channel "$CHANNEL_ID" | jq .
|
|
# Expected: {"event_id":"...","accepted":true,"message":"..."}
|
|
```
|
|
|
|
### 6.2 Canvas
|
|
|
|
```bash
|
|
# canvas set
|
|
buzz canvas set --channel "$CHANNEL_ID" --content "# Test Canvas" | jq .
|
|
|
|
# canvas set from stdin
|
|
echo "# Canvas from stdin" | buzz canvas set --channel "$CHANNEL_ID" --content - | jq .
|
|
|
|
# canvas get
|
|
buzz canvas get --channel "$CHANNEL_ID"
|
|
# Expected: raw markdown string, or: null
|
|
```
|
|
|
|
### 6.3 Messages
|
|
|
|
```bash
|
|
# messages send
|
|
MSG=$(buzz messages send --channel "$CHANNEL_ID" --content "Hello from CLI test" | jq .)
|
|
echo "$MSG"
|
|
EVENT_ID=$(echo "$MSG" | jq -r '.event_id')
|
|
|
|
# messages send with reply + broadcast
|
|
REPLY=$(buzz messages send --channel "$CHANNEL_ID" --content "Reply" \
|
|
--reply-to "$EVENT_ID" --broadcast | jq .)
|
|
echo "$REPLY"
|
|
REPLY_ID=$(echo "$REPLY" | jq -r '.event_id')
|
|
|
|
# messages send with mentions — @name in content is auto-resolved, no flag needed
|
|
buzz messages send --channel "$CHANNEL_ID" --content "Hey @someone" | jq .
|
|
|
|
# messages send with NIP-27 nostr:npub1… inline mention — auto-resolved to p-tag
|
|
buzz messages send --channel "$CHANNEL_ID" \
|
|
--content "Check with nostr:npub10elfcs4fr0l0r8af98jlmgdh9c8tcxjvz9qkw038js35mp4dma8qzvjptg on this" | jq .
|
|
|
|
# messages send from stdin — safe path for content with shell metacharacters
|
|
# (backticks, $vars, code blocks) that would otherwise be expanded by the shell.
|
|
echo 'Body with `backticks` and $vars stays literal.' \
|
|
| buzz messages send --channel "$CHANNEL_ID" --content - | jq .
|
|
|
|
# messages get
|
|
buzz messages get --channel "$CHANNEL_ID" | jq .
|
|
buzz messages get --channel "$CHANNEL_ID" --limit 5 | jq .
|
|
|
|
# messages thread
|
|
buzz messages thread --channel "$CHANNEL_ID" --event "$EVENT_ID" | jq .
|
|
|
|
# messages search
|
|
buzz messages search --query "Hello" | jq .
|
|
buzz messages search --query "CLI test" --limit 5 | jq .
|
|
|
|
# messages edit
|
|
buzz messages edit --event "$EVENT_ID" --content "Edited by CLI test" | jq .
|
|
|
|
# messages delete
|
|
buzz messages delete --event "$REPLY_ID" | jq .
|
|
```
|
|
|
|
### 6.4 Diff Messages
|
|
|
|
```bash
|
|
# messages send-diff from stdin
|
|
echo '--- a/foo.rs
|
|
+++ b/foo.rs
|
|
@@ -1,3 +1,3 @@
|
|
-fn old() {}
|
|
+fn new() {}' | buzz messages send-diff \
|
|
--channel "$CHANNEL_ID" \
|
|
--diff - \
|
|
--repo "https://github.com/example/repo" \
|
|
--commit "abcdef1234567890abcdef1234567890abcdef12" | jq .
|
|
|
|
# messages send-diff with metadata
|
|
echo "diff content" | buzz messages send-diff \
|
|
--channel "$CHANNEL_ID" \
|
|
--diff - \
|
|
--repo "https://github.com/example/repo" \
|
|
--commit "abcdef1234567890abcdef1234567890abcdef12" \
|
|
--file "src/main.rs" \
|
|
--lang "rust" \
|
|
--description "Refactored main" | jq .
|
|
|
|
# messages send-diff with branch + PR metadata
|
|
echo "diff content" | buzz messages send-diff \
|
|
--channel "$CHANNEL_ID" \
|
|
--diff - \
|
|
--repo "https://github.com/example/repo" \
|
|
--commit "abcdef1234567890abcdef1234567890abcdef12" \
|
|
--parent-commit "1234567890abcdef1234567890abcdef12345678" \
|
|
--source-branch "feature/cli" \
|
|
--target-branch "main" \
|
|
--pr 42 | jq .
|
|
```
|
|
|
|
### 6.5 Reactions
|
|
|
|
```bash
|
|
# Send a message to react to
|
|
REACT_MSG=$(buzz messages send --channel "$CHANNEL_ID" --content "React to this")
|
|
REACT_ID=$(echo "$REACT_MSG" | jq -r '.event_id')
|
|
|
|
# reactions add
|
|
buzz reactions add --event "$REACT_ID" --emoji "👍" | jq .
|
|
|
|
# reactions get
|
|
buzz reactions get --event "$REACT_ID" | jq .
|
|
# Expected: {"reactions":[{"emoji":"...","count":N,"pubkeys":["..."]}]}
|
|
|
|
# reactions remove
|
|
buzz reactions remove --event "$REACT_ID" --emoji "👍" | jq .
|
|
```
|
|
|
|
### 6.6 DMs
|
|
|
|
```bash
|
|
# dms list
|
|
buzz dms list | jq .
|
|
# Expected: [{"dm_id":"...","participants":["..."],"created_at":N}]
|
|
|
|
# dms open (needs a real pubkey — use your own or a test one)
|
|
# Get your own pubkey first:
|
|
MY_PUBKEY=$(buzz users get | jq -r '.[0].pubkey // empty')
|
|
echo "My pubkey: $MY_PUBKEY"
|
|
|
|
# dms open with a synthetic pubkey (relay will create the user)
|
|
DM_RESULT=$(buzz dms open --pubkey "0000000000000000000000000000000000000000000000000000000000000001")
|
|
echo "$DM_RESULT" | jq .
|
|
# Expected: {"event_id":"...","accepted":true,"message":"...","dm_id":"<uuid>"}
|
|
DM_ID=$(echo "$DM_RESULT" | jq -r '.dm_id')
|
|
|
|
# dms add-member (requires messages:write scope — NOT admin:channels)
|
|
buzz dms add-member --channel "$DM_ID" \
|
|
--pubkey "0000000000000000000000000000000000000000000000000000000000000002" | jq .
|
|
```
|
|
|
|
### 6.7 Users & Presence
|
|
|
|
```bash
|
|
# users get — own profile (0 pubkeys)
|
|
buzz users get | jq .
|
|
# Expected: [{...profile...}] — always returns an array, even for single results
|
|
|
|
# users get — single pubkey
|
|
buzz users get --pubkey "$MY_PUBKEY" | jq .
|
|
|
|
# users get — batch (2+ pubkeys)
|
|
buzz users get --pubkey "$MY_PUBKEY" --pubkey "$MY_PUBKEY" | jq .
|
|
|
|
# users set-profile
|
|
buzz users set-profile --name "CLI Test Agent" --about "Testing buzz-cli" | jq .
|
|
|
|
# users presence
|
|
buzz users presence --pubkeys "$MY_PUBKEY" | jq .
|
|
|
|
# users set-presence
|
|
buzz users set-presence --status online | jq .
|
|
buzz users set-presence --status away | jq .
|
|
buzz users set-presence --status offline | jq .
|
|
# Note: set-presence may fail — kind:20001 is ephemeral and rejected by the HTTP bridge
|
|
|
|
# users set-status — NIP-38 kind:30315 on the d:general coordinate
|
|
buzz users set-status --text "reviewing PRs" --emoji "🔍" | jq .
|
|
buzz users set-status --text "no emoji this time" | jq .
|
|
|
|
# users set-status — emoji-only status (intentional: text is blank, emoji is kept)
|
|
buzz users set-status --text "" --emoji "🎶" | jq .
|
|
|
|
# users set-status --clear — removes the status (empty content, d:general only)
|
|
buzz users set-status --clear | jq .
|
|
|
|
# --clear is mutually exclusive with --text/--emoji
|
|
buzz users set-status --clear --text "nope" 2>&1; echo "exit: $?"
|
|
# Expected: exit 1 — clap conflict error
|
|
```
|
|
|
|
### 6.8 Channel Members (add/remove require admin:channels)
|
|
|
|
```bash
|
|
# channels add-member
|
|
buzz channels add-member --channel "$CHANNEL_ID" \
|
|
--pubkey "0000000000000000000000000000000000000000000000000000000000000001" \
|
|
--role member | jq .
|
|
|
|
# channels members
|
|
buzz channels members --channel "$CHANNEL_ID" | jq .
|
|
# Expected: [{"pubkey":"...","role":"..."}]
|
|
|
|
# channels remove-member
|
|
buzz channels remove-member --channel "$CHANNEL_ID" \
|
|
--pubkey "0000000000000000000000000000000000000000000000000000000000000001" | jq .
|
|
```
|
|
|
|
### 6.9 Workflows
|
|
|
|
```bash
|
|
# workflows create
|
|
# NOTE: trigger uses `on:` tag (serde internally tagged enum).
|
|
# Valid triggers: message_posted, reaction_added, diff_posted, schedule, webhook
|
|
# Steps use `action:` tag: send_message, send_dm, set_channel_topic, add_reaction, etc.
|
|
WF=$(buzz workflows create --channel "$CHANNEL_ID" \
|
|
--yaml 'name: test-wf
|
|
trigger:
|
|
on: webhook
|
|
steps:
|
|
- id: step1
|
|
action: send_message
|
|
text: "Hello from workflow"' | jq .)
|
|
echo "$WF"
|
|
WF_ID=$(echo "$WF" | jq -r '.workflow_id')
|
|
|
|
# workflows list
|
|
buzz workflows list --channel "$CHANNEL_ID" | jq .
|
|
|
|
# workflows get
|
|
buzz workflows get --workflow "$WF_ID" | jq .
|
|
# Expected: {"workflow_id":"...","content":"<yaml>","created_at":N,"pubkey":"..."} or null
|
|
|
|
# workflows update (requires --channel)
|
|
buzz workflows update --channel "$CHANNEL_ID" --workflow "$WF_ID" \
|
|
--yaml 'name: test-wf-updated
|
|
trigger:
|
|
on: webhook
|
|
steps:
|
|
- id: step1
|
|
action: send_message
|
|
text: "Updated"' | jq .
|
|
|
|
# workflows trigger
|
|
# NOTE: May return 400 "workflow not found" — the relay indexes workflow
|
|
# definitions into a DB table asynchronously. If the definition event hasn't
|
|
# been indexed yet, the trigger handler won't find it.
|
|
buzz workflows trigger --workflow "$WF_ID" | jq .
|
|
|
|
# workflows runs
|
|
buzz workflows runs --workflow "$WF_ID" | jq .
|
|
# Expected: [] — relay stores runs in DB, not as Nostr events; empty is normal
|
|
|
|
# workflows approve — requires a workflow run waiting for approval
|
|
# This is hard to test ad-hoc without a workflow that has an approval gate.
|
|
# Test the validation instead:
|
|
buzz workflows approve --token "00000000-0000-0000-0000-000000000000" 2>&1 || true
|
|
# Should fail with relay error (token not found), not a validation error
|
|
# To test the deny path: buzz workflows approve --token <UUID> --approved false
|
|
|
|
# workflows delete
|
|
buzz workflows delete --workflow "$WF_ID" | jq .
|
|
```
|
|
|
|
### 6.10 Feed
|
|
|
|
```bash
|
|
buzz feed get | jq .
|
|
buzz feed get --limit 5 | jq .
|
|
# Expected: [{id,pubkey,kind,content,created_at,tags}] — sig-stripped, sorted newest-first
|
|
```
|
|
|
|
### 6.11 Forum & Voting
|
|
|
|
```bash
|
|
# Send a forum post (kind 45001) to the forum channel
|
|
FORUM_POST=$(buzz messages send --channel "$FORUM_ID" \
|
|
--content "Forum post for vote testing" --kind 45001 | jq .)
|
|
echo "$FORUM_POST"
|
|
FORUM_EVENT_ID=$(echo "$FORUM_POST" | jq -r '.event_id')
|
|
|
|
# messages vote (up)
|
|
buzz messages vote --event "$FORUM_EVENT_ID" --direction up | jq .
|
|
|
|
# messages vote (down)
|
|
buzz messages vote --event "$FORUM_EVENT_ID" --direction down | jq .
|
|
```
|
|
|
|
### 6.12 Notes (NIP-23 long-form, kind:30023)
|
|
|
|
Editable team-knowledge notes keyed by `(kind:30023, you, d=slug)`. `set` is an
|
|
idempotent upsert; `rm` is a NIP-09 a-tag deletion. Output is plain text (refs),
|
|
not JSON — except `get`/`ls`, which emit JSON.
|
|
|
|
```bash
|
|
# set (first publish — --title required, body from stdin)
|
|
cat <<'EOF' | buzz notes set --name dco-check --title "DCO Check" \
|
|
--summary "How we verify DCO" --tag dco --tag ci --content -
|
|
Run `git log --format='%(trailers:key=Signed-off-by)'` ...
|
|
EOF
|
|
# → prints event_id / naddr / coordinate / slug / title
|
|
|
|
# set (edit — omit --title to carry it forward; published_at preserved)
|
|
echo "Updated body." | buzz notes set --name dco-check --content -
|
|
|
|
# get by name (own author resolves directly; cross-author #d query otherwise)
|
|
buzz notes get --name dco-check | jq .
|
|
buzz notes get --name dco-check --content-only
|
|
|
|
# get by naddr (exact coordinate; paste the naddr from a set/get above)
|
|
buzz notes get --naddr "$NADDR" | jq .
|
|
|
|
# ls (own by default; --author all across the team; --tag filters)
|
|
buzz notes ls | jq .
|
|
buzz notes ls --tag dco | jq .
|
|
buzz notes ls --author all --limit 10 | jq .
|
|
|
|
# rm (NIP-09 a-tag deletion; subsequent get must 404)
|
|
buzz notes rm --name dco-check
|
|
# → prints deleted <coordinate> / deletion <event-id>
|
|
buzz notes get --name dco-check # exits non-zero: not found
|
|
|
|
# rm of a slug you never published → NotFound, no kind:5 emitted
|
|
buzz notes rm --name does-not-exist # exits non-zero
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Error Path Testing
|
|
|
|
Verify the CLI produces correct JSON on stderr and correct exit codes.
|
|
|
|
```bash
|
|
# Exit 1: Invalid UUID
|
|
buzz channels get --channel "not-a-uuid" 2>&1; echo "exit: $?"
|
|
# stderr: {"error":"user_error","message":"invalid UUID: not-a-uuid"}
|
|
# exit: 1
|
|
|
|
# Exit 1: Invalid hex64
|
|
buzz messages delete --event "not-hex" 2>&1; echo "exit: $?"
|
|
# stderr: {"error":"user_error","message":"must be a 64-character hex string: not-hex"}
|
|
# exit: 1
|
|
|
|
# Exit 1: Invalid --type value (clap validates the enum — multi-line error)
|
|
buzz channels create --name x --type invalid --visibility open 2>&1; echo "exit: $?"
|
|
# stderr: {"error":"user_error","message":"error: invalid value 'invalid' for '--type <CHANNEL_TYPE>'\n [possible values: stream, forum]\n..."}
|
|
# exit: 1
|
|
|
|
# Exit 1: Invalid --direction value
|
|
buzz messages vote --event "$(printf '0%.0s' {1..64})" \
|
|
--direction sideways 2>&1; echo "exit: $?"
|
|
# exit: 1
|
|
|
|
# Exit 1: Empty body guard
|
|
buzz users set-profile 2>&1; echo "exit: $?"
|
|
# exit: 1 (at least one field required)
|
|
|
|
# Exit 3: No auth configured
|
|
env -u BUZZ_PRIVATE_KEY \
|
|
cargo run -p buzz-cli -- channels list 2>&1; echo "exit: $?"
|
|
# stderr: {"error":"auth_error","message":"auth error: BUZZ_PRIVATE_KEY is required (use --private-key or set env var)"}
|
|
# exit: 3
|
|
|
|
# Not-found returns null, not an error (exit 0)
|
|
buzz channels get --channel "00000000-0000-0000-0000-000000000000"
|
|
# stdout: null
|
|
# exit: 0
|
|
```
|
|
|
|
---
|
|
|
|
## 8. Auth Testing
|
|
|
|
Test authentication.
|
|
|
|
```bash
|
|
# Private key (BUZZ_PRIVATE_KEY)
|
|
BUZZ_PRIVATE_KEY="nsec1..." buzz channels list | jq .
|
|
# Should succeed
|
|
|
|
# No auth → exit 3
|
|
env -u BUZZ_PRIVATE_KEY \
|
|
cargo run -p buzz-cli -- channels list 2>&1; echo "exit: $?"
|
|
# stderr: {"error":"auth_error","message":"auth error: BUZZ_PRIVATE_KEY is required (use --private-key or set env var)"}
|
|
# exit: 3
|
|
```
|
|
|
|
---
|
|
|
|
## 9. Cleanup
|
|
|
|
```bash
|
|
# Delete test channels
|
|
buzz channels delete --channel "$CHANNEL_ID" | jq .
|
|
buzz channels delete --channel "$FORUM_ID" | jq .
|
|
```
|
|
|
|
---
|
|
|
|
## 10. Checklist
|
|
|
|
| # | Command | Tested | Notes |
|
|
|---|---------|:------:|-------|
|
|
| 1 | `messages send` | ☐ | Basic, reply, broadcast, mentions, stdin |
|
|
| 2 | `messages send-diff` | ☐ | Stdin, metadata, branch/PR |
|
|
| 3 | `messages edit` | ☐ | |
|
|
| 4 | `messages delete` | ☐ | |
|
|
| 5 | `messages get` | ☐ | With limit |
|
|
| 6 | `messages thread` | ☐ | |
|
|
| 7 | `messages search` | ☐ | With limit |
|
|
| 8 | `messages vote` | ☐ | Up and down |
|
|
| 9 | `channels list` | ☐ | With visibility, member |
|
|
| 10 | `channels get` | ☐ | |
|
|
| 11 | `channels create` | ☐ | Stream and forum |
|
|
| 12 | `channels update` | ☐ | |
|
|
| 13 | `channels topic` | ☐ | |
|
|
| 14 | `channels purpose` | ☐ | |
|
|
| 15 | `channels join` | ☐ | |
|
|
| 16 | `channels leave` | ☐ | |
|
|
| 17 | `channels archive` | ☐ | Needs admin:channels |
|
|
| 18 | `channels unarchive` | ☐ | Needs admin:channels |
|
|
| 19 | `channels delete` | ☐ | Needs admin:channels |
|
|
| 20 | `channels members` | ☐ | |
|
|
| 21 | `channels add-member` | ☐ | Needs admin:channels |
|
|
| 22 | `channels remove-member` | ☐ | Needs admin:channels |
|
|
| 23 | `canvas get` | ☐ | |
|
|
| 24 | `canvas set` | ☐ | Direct and stdin |
|
|
| 25 | `reactions add` | ☐ | |
|
|
| 26 | `reactions remove` | ☐ | |
|
|
| 27 | `reactions get` | ☐ | |
|
|
| 28 | `dms list` | ☐ | |
|
|
| 29 | `dms open` | ☐ | |
|
|
| 30 | `dms add-member` | ☐ | Needs messages:write |
|
|
| 31 | `users get` | ☐ | Self, single, batch |
|
|
| 32 | `users set-profile` | ☐ | |
|
|
| 33 | `users presence` | ☐ | |
|
|
| 34 | `users set-presence` | ☐ | online, away, offline |
|
|
| 35 | `workflows list` | ☐ | |
|
|
| 36 | `workflows create` | ☐ | |
|
|
| 37 | `workflows update` | ☐ | |
|
|
| 38 | `workflows delete` | ☐ | |
|
|
| 39 | `workflows trigger` | ☐ | |
|
|
| 40 | `workflows runs` | ☐ | |
|
|
| 41 | `workflows get` | ☐ | |
|
|
| 42 | `workflows approve` | ☐ | Validation only (needs approval gate); bare = approve, `--approved false` = deny |
|
|
| 43 | `feed get` | ☐ | |
|
|
| 44 | `social publish` | ☐ | |
|
|
| 45 | `social set-contacts` | ☐ | |
|
|
| 46 | `social event` | ☐ | |
|
|
| 47 | `social notes` | ☐ | |
|
|
| 48 | `social contacts` | ☐ | |
|
|
| 49 | `repos create` | ☐ | |
|
|
| 50 | `repos get` | ☐ | |
|
|
| 51 | `repos list` | ☐ | |
|
|
| 52 | `repos protect list` | ☐ | Empty/populated rules; unknown rules visible; malformed rule reported in validation_error |
|
|
| 53 | `repos protect set` | ☐ | Create and replace complete exact-ref rule; verify metadata is preserved |
|
|
| 54 | `repos protect remove` | ☐ | Remove exact ref; missing rule → NotFound |
|
|
| 55 | `upload file` | ☐ | |
|
|
| 56 | `pack validate` | ☐ | Local, no relay |
|
|
| 57 | `pack inspect` | ☐ | Local, no relay |
|
|
| 58 | `notes set` | ☐ | First publish, edit/carry, --clear-tags, ambiguity, empty-stdin guard |
|
|
| 59 | `notes get` | ☐ | By name, by naddr, --content-only, cross-author, ambiguous → exit 1 |
|
|
| 60 | `notes ls` | ☐ | Own, --author all, --tag, --limit |
|
|
| 61 | `notes rm` | ☐ | Delete→get 404, double-delete idempotent, missing slug → NotFound |
|
|
| 62 | `users set-status` | ☐ | Text+emoji, text only, emoji-only (`--text ""`), `--clear`, `--clear` + `--text` → exit 1 |
|