Each task's tests were run against a reference at its end state; the end states were replayed from master in order with the gate at each step (650 to 762 tests); each skeleton compiles against its tests and fails them. The reference is kept off this machine. Lessons T27 (every wait in a test has a limit) and T28 (mutate the reference before hand-over) come from this work. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
4.1 KiB
M4a task 10: Mattermost's events and REST calls
Branch: m4a (run git switch m4a; git status --short must be empty, otherwise stop)
Commit subject: gatewayd: mm, Mattermost's events and the four REST calls, typed
Goal
Mattermost's JSON, typed, and the REST calls gatewayd makes. This is another program's
format: unknown fields are ignored. But every id we keep ends up in a session id or a URL path,
so every id must be a valid Mattermost id (26 characters of a-z0-9), or the whole post is refused.
Facts from Mattermost's source at the owner's server version, v11.11.0 (checked by the design model; the tests use these shapes):
- A WebSocket event is
{"event", "data", "broadcast", "seq"}. The first ishello.postedcarries the post as a JSON string indata.post(a string holding JSON, not an object), and the channel's type indata.channel_type:Ddirect,Ggroup,Oopen,Pprivate. A reply to one of our requests has noevent. user_typingis a request we send:{"action": "user_typing", "seq": <n>, "data": {"channel_id", "parent_id"}}; it shows the bot as typing in that thread.GET /api/v4/channels/{id}/posts?since=<ms>returns{"order": [ids], "posts": {id: post}}with the posts changed after that time. Only the ids inorderchanged;postsalso holds the roots of their threads, which may be old. Edited and deleted posts come back too. The server takes at most 1000 (SINCE_LIMIT); a full answer may have left some out.- REST errors: 401 or 403 is a refused token, 429 is a rate limit (wait for
X-Ratelimit-Reset), 5xx is worth trying again.
Files
- Copy:
crates/gatewayd/tests/mm_json.rs,crates/gatewayd/tests/mm_rest.rs,crates/gatewayd/tests/support/http_server.rs, and the skeletonscrates/gatewayd/src/mm/mod.rsandcrates/gatewayd/src/mm/rest.rs - Modify:
crates/gatewayd/src/lib.rs(pub mod mm;),docs/implementer-log.md
The skeletons
mm/mod.rs, written: SINCE_LIMIT; MmError (Net, Auth(u16), RateLimited(Duration),
Status(u16, String), Json) and its Display, which quotes a server's body ({:?}) so that
a newline in it cannot forge a log line; Me { id, username }; Post { id, user_id, channel_id, root_id, message, create_at, delete_at, kind } (kind is the JSON type); Event (Hello,
Posted { post, channel_type }, Other(String)); Since { posts, full }; and the private serde
shapes RawEvent and PostList. To fill: Post::check, json, parse_event, typing,
since_list.
mm/rest.rs, written: RETRY_5XX (500 ms), RETRIES (2), BODY_KEPT (200), Client. To fill:
new, connector, token, once, call, me, create_post, posts_since, direct_channel.
The token reaches the wire only in once, as Authorization: Bearer <token>; nowhere else calls
expose().
Steps
- 1. Copy.
git switch m4a, thenmkdir -p crates/gatewayd/src/mm && cp docs/plans/M4a/files/crates/gatewayd/src/mm/mod.rs docs/plans/M4a/files/crates/gatewayd/src/mm/rest.rs crates/gatewayd/src/mm/ && cp docs/plans/M4a/files/crates/gatewayd/tests/mm_json.rs docs/plans/M4a/files/crates/gatewayd/tests/mm_rest.rs crates/gatewayd/tests/ && cp docs/plans/M4a/files/crates/gatewayd/tests/support/http_server.rs crates/gatewayd/tests/support/. Addpub mod mm;tolib.rs. - 2. See it fail.
cargo test -p gatewayd --no-fail-fast --test mm_json --test mm_rest. Expected: it compiles;mm_json6 fail and 1 passes (theDisplaytest),mm_rest10 fail. - 3. Fill
mm/mod.rs, thenmm/rest.rs, one function at a time,cargo check -p gatewaydafter each. - 4. See it pass.
cargo test -p gatewayd --test mm_json --test mm_rest. Expected: 7 and 10 passed.mm_resttakes about 3 s: two tests wait out a rate limit on purpose. - 5. Run the gate.
cargo fmt --all, thenmake gate. Expected last line:gate: ok. - 6. Log and commit.
git add crates/gatewayd docs/implementer-log.md Cargo.lock && git commit
Done when
- Both suites pass;
make gateprintsgate: ok.
Stop and report if
- A test needs a post with an invalid id to be accepted.