Skip to content

Per-Session Recording API Test Report

Attribute Value
Document type Test report
Subject Per-session recording API (POST https://record.pp-cdn.org/api/record/split, see recorder-api.md)
Tested 2026-09-29 (Beijing time)
Method Automated integration tests (against the production endpoint) + manual requests following the doc examples
Environment Production https://record.pp-cdn.org; dedicated test app (appId redacted), simple auth mode
Result Pass: the documented happy path, auth, field validation, status codes and silent no-op all match the implementation; the success path (round-start → round-end actually writing files) was skipped because no stream was online for that app's table during the window

1. Goal

Verify, item by item against recorder-api.md, that the public interface behaves as documented:

  1. The endpoint and HTTP method are available and return the unified {code,msg,data} envelope;
  2. The simple mode signing algorithm and time tolerance window;
  3. Required-field and illegal-character validation (HTTP 400);
  4. Bad signature / expired time (HTTP 401);
  5. "End a session that never started" is a silent no-op success (HTTP 200);
  6. Error-code semantics with no online stream (HTTP 500 + code=50001).

This report covers simple mode only. advance mode (HMAC-SHA256 + nonce) and the 500 req/s rate limit (HTTP 429) require explicit deployment-side enablement, and deliberately triggering rate limiting on a shared production endpoint is inappropriate, so they are out of scope here.

2. Method

  • Automated integration tests: run cases covering the scenarios above against the production endpoint, asserting the HTTP status and envelope code.
  • Manual request checks: build requests by hand using the doc's §7 signing formula (md5(appSecret + time + appId + tableId + [gameRound] + gameId)) and inspect the raw response body, so results don't rely on assertions alone.

Signing baseline (matching doc §4.1):

base = appSecret + time + appId + tableId
if gameRound:  base += gameRound
base += gameId
token = md5(base).hexdigest()

3. Results summary

Scenario Expected Actual Result
Endpoint returns the documented envelope 2xx / 4xx / 5xx as {code,msg,data} Documented envelope PASS
Session start (with an online stream) 200 No online stream → 500 code=50001 SKIP
Session end (never started) 200 silent no-op 200 {"code":200,"msg":"OK","data":null} PASS
Missing Authorization 400 400 PASS
Request body not valid JSON 400 400 PASS
Missing tableId 400 400 missing parameters. PASS
tableId with illegal characters 400 400 ... contain invalid characters. PASS
Bad signature (wrong appSecret) 401 401 invalid token! PASS
time outside the tolerance window 401 401 token expired! PASS
tableId with no online stream 500 code=50001 500 code=50001 PASS
Conflicting owner's round-start 500 No online stream; precondition unmet SKIP
Full round-start → round-end 200 → 200 No online stream; precondition unmet SKIP

Total: 10 executed, 8 PASS, 3 SKIP, 0 FAIL.

4. Key request / response captures

Below are actual responses to manual requests built per doc §7 (time is the Unix second at request construction; Authorization is the 32-char md5 computed by the formula above):

A. End a session that never started (expect silent no-op success)

POST /api/record/split
Authorization: <md5>
{"time":"1759130000","appId":"app_***","tableId":"table","gameId":"itest-never-xxx","gameRound":"gc-itest-xxx"}
HTTP 200 {"code":200,"msg":"OK","data":null}

B. Session start but no stream online for the table (expect 500 + dedicated code)

HTTP 500 {"code":50001,"msg":"stream for app \"app_***\" table \"table\" is not online","data":""}

C. Bad signature (expect 401)

HTTP 401 {"code":401,"msg":"invalid token!","data":""}

D. Missing tableId (expect 400)

HTTP 400 {"code":400,"msg":"missing parameters.","data":""}

E. tableId with illegal characters table/../etc (expect 400)

HTTP 400 {"code":400,"msg":"appId/tableId/gameId/gameRound/appEnv contain invalid characters.","data":""}

F. time one hour ago (outside simple mode's ±30s window, expect 401)

HTTP 401 {"code":401,"msg":"token expired!","data":""}

Confirmed: the two key conventions in doc §5 hold — (1) conflict/business rejections and "no online stream" both use HTTP 500 and can only be told apart by the envelope code (50001 vs others) or msg, not by the HTTP status alone; (2) ending a session that never started succeeds unconditionally, without erroring for a missing round-start.

5. Skipped cases

The following cases' preconditions did not hold during the test window, so they were skipped — this is not an interface defect:

  • Session start / full round-start → round-end: tableId=table had no view publishing at that moment, so round-start returned code=50001 as documented. The success path can be re-run once the table actually starts publishing.
  • Conflicting owner's round-start: requires a prior successful round-start holding the table; precondition unmet.

All other scenarios not depending on an online stream were covered and passed.

6. Conclusion

  • The endpoint, two-phase protocol, simple auth, field validation, status codes and no-op semantics described in recorder-api.md match the deployed service; this re-test passed in full.
  • Integrators should distinguish "no online stream" (50001) from other business rejections using the envelope code / msg (not the HTTP status), and mind the "don't end immediately after start" segment-duration constraint (doc §8).

7. Revision history

Date Revision Notes
2026-09-29 Draft Re-tested against production; success path skipped for lack of an online stream, everything else passed