Files
peipei-backend/llm/wechat-subsystem-test-matrix.md
irving 985b35cd90
Some checks failed
Build and Push Backend / docker (push) Has been cancelled
test: add wechat integration test suite
- Add llm/wechat-subsystem-test-matrix.md and tests covering Wx controllers/services\n- Make ApiTestDataSeeder personnel group seeding idempotent for full-suite stability
2026-01-12 18:54:14 -05:00

32 KiB

WeChat Subsystem — Characterization / Integration Test Matrix

This document is a behavior pin (characterization) test matrix for the current WeChat-related subsystem. The goal is to lock observable behavior (HTTP + DB + Redis + external calls) so later refactoring can be done safely.

Repo root: /Volumes/main/code/yunpei/peipei-backend

Source Inventory (entry points)

Controllers

  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/controller/WxOauthController.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/controller/WxPlayController.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/controller/WxCommonController.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/controller/WxCustomController.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/controller/WxClerkController.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/controller/WxOrderInfoController.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/controller/WxCouponController.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/controller/WxClerkMediaController.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/controller/WxBlindBoxController.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/controller/WxPkController.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/controller/WxGiftController.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/controller/WxClerkCommodityController.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/controller/WxCommodityController.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/controller/WxLevelController.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/controller/WxShopController.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/controller/WxClerkWagesController.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/controller/WxPersonnelGroupInfoController.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/controller/WxPlayOrderRankingController.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/withdraw/controller/WxWithdrawController.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/withdraw/controller/WxWithdrawPayeeController.java

Services / Cross-cutting

  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/service/WxOauthService.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/service/WxCustomMpService.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/service/WxTokenService.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/service/WxCustomUserService.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/service/WxGiftOrderService.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/service/WxBlindBoxOrderService.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/service/MediaUploadService.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/common/security/filter/JwtAuthenticationTokenFilter.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/common/aspect/CustomUserLoginAspect.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/common/aspect/ClerkUserLoginAspect.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/service/NotificationSender.java
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/java/com/starry/admin/modules/weichat/service/MockNotificationSender.java

DB schema touchpoints

  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/resources/db/migration/V1__init_schema.sql
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/main/resources/db/migration/V17__create_media.sql

Key fields to pin:

  • sys_tenant: tenant_key, app_id, secret, mch_id, mch_key, *_template_id, profitsharing_rate
  • play_custom_user_info: openid, unionid, wei_chat_code, token
  • play_clerk_user_info: openid (NOT NULL), wei_chat_code, token, online_state, onboarding_state, listing_state, clerk_state
  • play_order_info: order_type, pay_method, pay_state, place_type, reward_type, wei_chat_code, profit_sharing_amount
  • play_media / play_clerk_media_asset: status, usage, review_state, deleted, order_index + unique constraint uk_clerk_usage_media

Test Harness Guidelines

Required runtime surfaces to observe

  1. HTTP: status code + response schema (normalized) for every /wx/** route.
  2. DB: before/after snapshots of rows touched by the route (focus tables above).
  3. Redis: keys under:
    • TENANT_INFO:*
    • login_codes:*
    • PK keys under PkRedisKeyConstants (if enabled)
  4. External calls: record interactions with:
    • WxMpService / WeChat MP template message service
    • WxPayService (unified order + profitsharing)
    • IOssFileService
    • SmsUtils
    • background tasks like OverdueOrderHandlerTask

Profiles

  • Prefer running integration tests under apitest profile (seeded DB + mock notifier).
  • For tests that must hit real async behavior, use deterministic executors in test config (or replace ThreadPoolTaskExecutor with inline executor via @MockBean).

Normalization rules (avoid flaky tests)

  • Normalize dynamic fields: timestamps, random IDs (UUID), and generated nonces.
  • For money: always compare as BigDecimal with explicit scale/rounding.
  • For lists: assert stable ordering only when the endpoint guarantees ordering.

1) Gateway / Tenant / AuthN (Filter + AOP)

ID Surface Route / Component Scenario Setup Mocks Assertions
GW-001 HTTP JwtAuthenticationTokenFilter /wx/** without tenantkey header on a login-required route none none response is error (pin: code/body shape + status)
GW-002 HTTP JwtAuthenticationTokenFilter /wx/** without tenantkey on a no-login whitelist route none none response is error (pin: JSON body written by filter)
GW-003 HTTP JwtAuthenticationTokenFilter /wx/pay/jsCallback bypasses auth and does not require tenantkey none none handler executes and returns success string
GW-004 HTTP/Redis filter getTenantId with tenantkey only (no token) tenant exists ISysTenantService real or stub SecurityUtils.getTenantId() set; request proceeds
GW-005 HTTP/Redis filter getTenantId with clerk token seed clerk with token + tenantId none tenantId resolved from DB; TENANT_INFO:{userId} read does not break flow
GW-006 HTTP/Redis filter getTenantId with custom token seed customer with token + tenantId none tenantId resolved from DB
AOP-001 HTTP @CustomUserLogin endpoints missing customusertoken header none none 401 token为空
AOP-002 HTTP @ClerkUserLogin endpoints missing clerkusertoken header none none 401 token为空
AOP-003 HTTP CustomUserLoginAspect invalid token format/signature none none 401 获取用户信息异常
AOP-004 HTTP CustomUserLoginAspect token ok but DB token mismatch seed user with different token none 401 token异常
AOP-005 HTTP ClerkUserLoginAspect ensureClerkSessionIsValid rejects seed clerk state invalid none 401 message matches current CustomException message
TOK-001 unit/contract WxTokenService token generated and parsed (with/without Bearer ) config secret + expireTime none same userId extracted
TOK-002 unit/contract WxTokenService expired token fails short expireTime none parsing throws; upstream maps to 401

2) WeChat OAuth (WxOauthController + WxOauthService)

ID Surface Route Scenario Setup Mocks Assertions
OAUTH-001 HTTP POST /wx/oauth2/getConfigAddress url omitted -> uses default callback valid tenant mock WxMpService signature signature returned; default URL pinned
OAUTH-002 HTTP POST /wx/oauth2/getConfigAddress url provided -> overrides default valid tenant mock signature uses provided URL
OAUTH-003 HTTP POST /wx/oauth2/getClerkLoginAddress returns auth URL with scope snsapi_userinfo valid tenant mock OAuth2 service build URL response contains expected scope
OAUTH-004 HTTP POST /wx/oauth2/getCustomLoginAddress same as clerk valid tenant mock OAuth2 service response contains expected scope
OAUTH-005 HTTP/DB/Redis POST /wx/oauth2/custom/login success -> returns token payload + persists token seed tenant + seeded customer openid mock WxMpService.getOAuth2Service().getAccessToken/getUserInfo response includes tokenValue/tokenName/loginDate; DB token updated; Redis TENANT_INFO:{id} set
OAUTH-006 HTTP POST /wx/oauth2/custom/login upstream WeChat oauth fails -> unauthorized none mock WxMpService.getOAuth2Service().getAccessToken to throw response code=401 (and success=false)
OAUTH-007 HTTP/DB/Redis POST /wx/oauth2/clerk/login success -> token persisted + tenant cached; pcData present seed a clerk with sysUserId="" to avoid PC login dependency mock WxMpService.getOAuth2Service().getAccessToken/getUserInfo response includes pcData.token/role (empty strings); DB token updated; Redis TENANT_INFO:{id} set
OAUTH-008 HTTP/DB GET /wx/oauth2/custom/logout token invalidated seed user + token none DB token set to empty; subsequent access 401
OAUTH-009 service/DB WxOauthService.customUserLogin first login creates new user with registrationTime empty DB mock MP OAuth2 row inserted with expected fields
OAUTH-010 service/DB WxOauthService.clerkUserLogin deleted clerk restored seed clerk deleted=true mock MP OAuth2 deleted=false; default states filled; token/online reset
OAUTH-011 HTTP GET /wx/oauth2/checkSubscribe returns boolean subscribe state logged-in customer mock WxMpService.getUserService().userInfo response data is true/false

3) WeChat Pay Recharge + Callback + Profit Sharing (WxPlayController)

ID Surface Route Scenario Setup Mocks Assertions
PAY-001 HTTP GET /wx/pay/custom/getCustomPaymentAmount money empty -> 500 logged-in customer none error message pinned
PAY-002 HTTP GET /wx/pay/custom/getCustomPaymentAmount money valid -> BigDecimal returned logged-in customer none response number pinned (scale/rounding)
PAY-003 HTTP/DB GET /wx/pay/custom/createOrder money < 1 -> 500 logged-in customer none error message pinned
PAY-004 HTTP/DB GET /wx/pay/custom/createOrder creates recharge order + returns JSAPI pay params logged-in customer + tenant with mch config mock WxPayService.unifiedOrder and SignUtils inputs via capturing request order row created (type/pay_state); response has required fields; unifiedOrder request fields pinned
PAY-005 HTTP GET /wx/pay/custom/createOrder subscribe check fails -> error customer openid + tenant mock WxCustomMpService.checkSubscribeThrowsExp to throw HTTP error pinned
PAY-006 HTTP/DB POST/GET /wx/pay/jsCallback invalid XML -> still returns success string, no DB changes existing DB none response equals success; no order updates
PAY-007 HTTP/DB /wx/pay/jsCallback unknown out_trade_no -> no changes none none no DB changes
PAY-008 HTTP/DB /wx/pay/jsCallback order_type!=0 OR pay_state!=0 -> no reprocessing seed paid/non-recharge order none no balance change; no state change
PAY-009 HTTP/DB/Redis /wx/pay/jsCallback happy path updates pay_state and balance seed recharge order pay_state=0 + tenant attach mock customAccountBalanceRecharge if needed or assert real side-effects pay_state becomes 1; balance updated; template message called
PAY-010 HTTP/DB /wx/pay/jsCallback replay same callback twice is idempotent seed recharge order none balance does not double-add; profit_sharing_amount not duplicated
PAY-011 HTTP/DB profitSharing profitsharing_rate<=0 -> no call and no write tenant rate=0 mock WxPay profitSharing service no API call; no DB update
PAY-012 HTTP/DB profitSharing rate>0 and computed amount=0 -> no call tiny amount mock no call
PAY-013 HTTP/DB profitSharing rate>0 -> writes profit_sharing_amount tenant rate set mock profitSharing result DB field set to expected BigDecimal

4) WeChat MP Notifications (WxCustomMpService)

ID Surface Component Scenario Setup Mocks Assertions
MP-001 unit/contract proxyWxMpService missing tenantId -> CustomException tenantId unset none exception message pinned
MP-002 unit/contract getWxPay tenant missing mch_id -> CustomException tenant has empty mchId none message pinned
MP-003 integration sendCreateOrderMessage template data fields mapping tenant has templateId + tenantKey mock template msg service short_thing5 label resolved; URL pinned
MP-004 integration sendCreateOrderMessageBatch filters offboarded/delisted clerks clerk list mix deterministic executor + mock template only eligible clerks called
MP-005 integration sendBalanceMessage sends recharge success template order + tenant + customer mock template data keys pinned
MP-006 integration sendOrderFinishMessage only placeType "1"/"2" triggers orders with other placeType mock template no calls when not matched
MP-007 integration async wrappers exceptions inside async do not bubble throw in underlying send deterministic executor caller does not fail
MP-008 integration subscribe checks subscribe=false -> ServiceException message pinned mock WxMpUser.subscribe=false mock user service message pinned

5) Common WeChat Tools (WxCommonController + WxFileUtils)

ID Surface Route Scenario Setup Mocks Assertions
COM-001 HTTP GET /wx/common/area/tree returns area tree tenantKey only mock area service or real response schema pinned
COM-002 HTTP GET /wx/common/setting/info returns global UI config (NOT tenant-scoped) call with two different X-Tenant values real service both responses share same data.id
COM-003 HTTP POST /wx/common/file/upload uploads to OSS returns URL multipart file mock IOssFileService.upload returned URL pinned
COM-004 HTTP GET /wx/common/audio/upload mediaId empty -> error none none error message pinned
COM-005 HTTP GET /wx/common/audio/upload successful path uploads mp3 provide accessToken + temp audio stream mock WxAccessTokenService, stub WxFileUtils.getTemporaryMaterial (via wrapper or test seam), mock OSS returns URL; temp files cleaned
COM-006 unit/contract WxFileUtils.audioConvert2Mp3 invalid source -> throws empty file none error message pinned

6) Customer (WxCustomController) — Orders, Gifts, Complaints, Follow, Leave Msg

ID Surface Route Scenario Setup Mocks Assertions
CUS-001 HTTP GET /wx/custom/queryClerkDetailedById not logged in still works tenantKey only none response pinned (no crash)
CUS-002 HTTP/DB GET /wx/custom/queryById returns clerkState=1 when openid matches clerk seed custom+clerk share openid none response clerkState pinned
CUS-003 HTTP/DB POST /wx/custom/updateHideLevelState ignores client id and uses session id logged-in custom none DB update on session row only
CUS-004 HTTP/DB POST /wx/custom/order/reward creates completed reward order logged-in custom + balance none order row fields pinned; ledger/balance delta pinned
CUS-005 HTTP/DB POST /wx/custom/order/gift calls WxGiftOrderService and increments gift counts logged-in custom + gift seeded none order created; both gift counters incremented
CUS-006 HTTP/DB POST /wx/custom/order/commodity creates specified order pending logged-in custom + clerk + commodity mock pricing if needed order fields pinned
CUS-007 HTTP/DB POST /wx/custom/order/random success triggers notification + overdue task logged-in custom + clerks eligible mock WxCustomMpService, mock OverdueOrderHandlerTask expected calls + order fields pinned
CUS-008 HTTP/DB POST /wx/custom/order/random insufficient balance fails and no order created set balance=0 none error code pinned; no DB insert
CUS-009 HTTP POST /wx/custom/order/queryByPage only returns self purchaserBy seed orders for multiple users none result contains only self
CUS-010 HTTP/DB GET /wx/custom/order/end state transition invoked seed order none order status moved (pin)
CUS-011 HTTP/DB POST /wx/custom/order/cancellation pins cancellation refund record (images ignored) seed pending/accepted order + send non-empty images none order canceled; refund record has refundReason; images stays null; order refundReason stays null
CUS-012 HTTP/DB POST /wx/custom/order/evaluate/add non-purchaser cannot evaluate order purchaser different none error message pinned
CUS-013 HTTP GET /wx/custom/order/evaluate/queryByOrderId not evaluated -> error seed order no eval none 当前订单未评价
CUS-014 HTTP/DB POST /wx/custom/order/complaint/add non-purchaser cannot complain order purchaser different none error message pinned
CUS-015 HTTP/DB POST /wx/custom/leave/add creates leave msg; response message pinned logged-in custom none DB insert; response message currently "取消成功"
CUS-016 HTTP GET /wx/custom/leave/queryPermission permission true/false schema pinned set conditions none response JSON has permission boolean and msg
CUS-017 HTTP/DB POST /wx/custom/followState/update idempotency and correctness seed follow relation none follow state pinned
CUS-018 HTTP POST /wx/custom/follow/queryByPage paging/filters pinned seed relations none page schema pinned

7) Clerk (WxClerkController) — Apply, Profile Review, Order Ops, Privacy Rules

ID Surface Route Scenario Setup Mocks Assertions
CLK-001 HTTP POST /wx/clerk/user/queryPerformanceInfo date normalize behavior pinned seed orders none output stable for same input
CLK-002 HTTP GET /wx/clerk/user/queryLevelInfo hardcoded levelAndRanking list pinned logged-in clerk none list size/content pinned
CLK-003 HTTP/Redis POST /wx/clerk/user/sendCode writes redis key with TTL and returns code logged-in clerk none redis key format + TTL; response contains code
CLK-004 HTTP/Redis/DB POST /wx/clerk/user/bindCode wrong code -> error seed redis code none 验证码错误
CLK-005 HTTP/Redis/DB POST /wx/clerk/user/bindCode success updates phone and clears redis seed redis code none DB phone updated; redis deleted
CLK-006 HTTP/DB POST /wx/clerk/user/add already clerk -> error seed clerkState=1 none message pinned
CLK-007 HTTP/DB POST /wx/clerk/user/add already has pending review -> error seed reviewState=0 none message pinned
CLK-008 HTTP POST /wx/clerk/user/add subscribe required mock subscribe=false mock WxCustomMpService.checkSubscribeThrowsExp error message pinned
CLK-009 HTTP/DB POST /wx/clerk/user/updateNickname creates data review row with correct type and content logged-in clerk none DB insert pinned
CLK-010 HTTP/DB POST /wx/clerk/user/updateAlbum empty album -> error logged-in clerk none 最少上传一张照片
CLK-011 HTTP/DB POST /wx/clerk/user/updateAlbum invalid new media -> error seed play_media with mismatched owner/tenant/status none error message pinned
CLK-012 HTTP/DB POST /wx/clerk/user/updateAlbum legacy IDs not found -> should not fail (current behavior) album includes missing IDs none request succeeds; review content contains legacy strings
CLK-013 HTTP/DB GET /wx/clerk/order/queryById privacy: non-owner clears weiChatCode seed order acceptBy other clerk none weiChatCode empty
CLK-014 HTTP/DB GET /wx/clerk/order/queryById canceled order clears weiChatCode seed orderStatus=4 none weiChatCode empty
CLK-015 HTTP GET /wx/clerk/order/accept subscribe required mock subscribe=false mock WxCustomMpService fails
CLK-016 HTTP/DB GET /wx/clerk/order/start state transition pinned seed order none state updated
CLK-017 HTTP/DB POST /wx/clerk/order/complete sysUserId missing -> error seed clerk no sysUserId none message pinned
CLK-018 HTTP/DB POST /wx/clerk/order/complete permission resolution pinned (admin vs group leader) seed sysUser mapping none correct operatorType chosen or error
CLK-019 HTTP/DB POST /wx/clerk/order/cancellation cancellation state pinned seed order none status/cancel fields updated
CLK-020 HTTP POST /wx/clerk/user/queryEvaluateByPage forces hidden=VISIBLE seed hidden evaluations none response excludes hidden

8) Orders (WxOrderInfoController) — Continuation + Random Order Masking

ID Surface Route Scenario Setup Mocks Assertions
ORD-001 HTTP/DB POST /wx/order/clerk/continue non-owner cannot continue order acceptBy != clerk none message pinned
ORD-002 HTTP/DB POST /wx/order/clerk/continue second continuation blocked seed continue record none message pinned
ORD-003 HTTP GET /wx/order/clerk/selectRandomOrderById masking for non-owner pinned seed random order accepted by other none fields blanked as implemented
ORD-004 HTTP/DB POST /wx/order/custom/updateReviewState reviewedState != 0 -> error seed reviewedState=1 none 续单已处理
ORD-005 HTTP/DB POST /wx/order/custom/continueListByPage customId forced to session seed multiple users none only self results

9) Coupons (WxCouponController)

ID Surface Route Scenario Setup Mocks Assertions
CP-001 HTTP GET /wx/coupon/custom/obtainCoupon id empty -> error message pinned logged-in custom none error message pinned
CP-002 HTTP/DB obtain coupon not eligible -> returns reason seed coupon restrictions none response contains reason
CP-003 HTTP/DB obtain coupon eligible -> claim succeeds seed coupon inventory none coupon_details inserted; response success
CP-004 HTTP query all whitelist hides coupons from non-whitelisted seed coupon whitelist none coupon not present
CP-005 HTTP query by order clerkId+levelId both empty -> error none none message pinned
CP-006 HTTP/DB query by order unavailable coupon includes reasonForUnavailableUse seed coupon restrictions none available=0 and reason set
CP-007 HTTP/DB query by order exceptions inside loop are swallowed (current behavior) seed one broken coupon none endpoint still returns 200 with remaining coupons

10) Media (WxClerkMediaController + MediaUploadService)

ID Surface Route Scenario Setup Mocks Assertions
MED-001 HTTP POST /wx/clerk/media/upload missing file -> error logged-in clerk none message pinned
MED-002 HTTP/DB upload image creates play_media + play_clerk_media_asset image multipart mock OSS DB rows inserted; kind=image; owner=clerk
MED-003 HTTP/DB upload video too large exceeds 30MB -> error video > limit none error message pinned
MED-004 HTTP/DB upload video too long duration>45s -> error long video none message pinned
MED-005 HTTP/DB PUT /wx/clerk/media/order distinct mediaIds and ordering pinned seed assets none order_index updates pinned; duplicates removed
MED-006 HTTP/DB DELETE /wx/clerk/media/{id} marks review_state=rejected and sets play_media.status=rejected (asset deleted stays 0 currently) seed media + asset none asset review_state becomes rejected; play_media.status becomes rejected; asset.deleted remains 0
MED-007 HTTP GET /wx/clerk/media/list returns only draft/pending/rejected seed assets states none filtering pinned
MED-008 HTTP GET /wx/clerk/media/approved returns only approved seed assets none filtering pinned
MED-009 DB constraint uk_clerk_usage_media duplicate submit behavior pinned seed duplicate row none error or ignore (pin current)

11) Blind Box (WxBlindBoxController + WxBlindBoxOrderService)

ID Surface Route Scenario Setup Mocks Assertions
BB-001 HTTP GET /wx/blind-box/config/list not logged in -> error none none message pinned
BB-002 HTTP list configs only active configs for tenant seed configs none list content pinned
BB-003 HTTP/DB POST /wx/blind-box/order/purchase tenant mismatch -> “not found” (TenantLine current behavior) config tenant != user tenant none message pinned (盲盒不存在)
BB-004 HTTP/DB purchase creates completed order + reward seed config + balance none order type pinned; reward row created
BB-005 HTTP/DB POST /wx/blind-box/reward/{id}/dispatch reward not found -> error none none message pinned
BB-006 HTTP/DB dispatch status transition pinned seed reward none status updated; response view pinned
BB-007 HTTP GET /wx/blind-box/reward/list status filter pinned seed rewards none filter results pinned
BB-008 HTTP/DB POST /wx/blind-box/order/purchase insufficient balance -> error and no new order customer balance < config price none message pinned; no new order inserted

12) PK (WxPkController)

ID Surface Route Scenario Setup Mocks Assertions
PK-001 HTTP GET /wx/pk/clerk/live clerkId missing -> error none none message pinned
PK-002 HTTP live no pk -> inactive dto seed none none returns inactive dto
PK-003 HTTP live pk exists but status!=IN_PROGRESS -> inactive seed pk none inactive
PK-004 HTTP/Redis upcoming tenant missing -> error no tenant context none message pinned
PK-005 HTTP/Redis upcoming redis hit/miss produces stable behavior seed redis keys none response pinned
PK-006 HTTP schedule/history limit/page normalization pinned none none safeLimit behavior pinned

13) Shop + Articles + Misc

ID Surface Route Scenario Setup Mocks Assertions
SHOP-001 HTTP GET /wx/shop/custom/getShopHomeCarouseInfo returns carousel list seed carousel none mapping pinned
SHOP-002 HTTP/DB GET /wx/shop/clerk/readShopArticleInfo visitsNumber increments seed article none visitsNumber +1 persisted
ART-001 HTTP/DB POST /wx/article/clerk/add creates article with clerkId from session logged-in clerk none DB insert pinned
ART-002 HTTP/DB GET /wx/article/clerk/deleteById deletes clerk article + custom article links seed both none rows removed/soft-deleted pinned
ART-003 HTTP/DB POST /wx/article/custom/updateGreedState pins current toggle behavior (not strictly idempotent) seed article none at least one row flips to endorseState=0 after toggle
ART-004 HTTP/DB POST /wx/article/custom/updateFollowState same for follow seed article none record updated

14) Wages + Withdraw (WxClerkWagesController + WxWithdrawController)

ID Surface Route Scenario Setup Mocks Assertions
WAGE-001 HTTP/DB GET /wx/wages/clerk/queryUnsettledWages sums orders correctly seed settlement_state=0 orders none totals pinned
WAGE-002 HTTP GET /wx/wages/clerk/queryCurrentPeriodWages missing wages row returns constructed zeros no wages row none response has zeros and dates set
WAGE-003 HTTP POST /wx/wages/clerk/queryHistoricalWages current hard-coded page meta pinned seed some rows none total=5,size=10,pages=1 pinned
WD-001 HTTP GET /wx/withdraw/balance returns available/pending/nextUnlock seed earnings lines none values pinned
WD-002 HTTP GET /wx/withdraw/earnings time parsing supports multiple formats seed earnings none filter correctness pinned
WD-003 HTTP/DB POST /wx/withdraw/requests amount<=0 error none none message pinned
WD-004 HTTP/DB create request creates withdrawal request and reserves lines seed available lines none statuses pinned
WD-005 HTTP request logs non-owner forbidden seed request other clerk none 无权查看
PAYEE-001 HTTP GET /wx/withdraw/payee no profile returns null data (current behavior) none none response pinned
PAYEE-002 HTTP/DB POST /wx/withdraw/payee missing qrCodeUrl -> error none none message pinned
PAYEE-003 HTTP/DB upsert defaulting defaults channel/displayName seed clerk none stored defaults pinned
PAYEE-004 HTTP/DB confirm requires qrCodeUrl no profile none error message pinned

Coverage Checklist (for “done”)

  • Every @RequestMapping("/wx...") route has at least:
    • 1 happy-path integration test
    • 1 auth/tenant gating test (where applicable)
    • 1 validation failure test (where applicable)
    • 1 DB side-effect snapshot assertion for routes that mutate state
  • WeChat Pay callback has:
    • replay/idempotency tests
    • malformed XML test
    • missing attach test
  • Media pipeline has:
    • type detection + size/duration limits pinned
    • DB uniqueness behavior pinned

Test Case ID Naming Convention (important)

  • In this doc, case IDs are written like OAUTH-007.
  • In Java test method names, we normalize them as OAUTH_007 because - is not valid in Java identifiers.

Implemented Coverage (current)

  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/test/java/com/starry/admin/api/WxOauthControllerApiTest.java: OAUTH-001..008, OAUTH-011
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/test/java/com/starry/admin/modules/weichat/service/WxOauthServiceTest.java: OAUTH-009, OAUTH-010
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/test/java/com/starry/admin/api/WxPayControllerApiTest.java: PAY-001..011
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/test/java/com/starry/admin/api/WxAuthAspectApiTest.java: AOP-001..005
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/test/java/com/starry/admin/modules/weichat/service/WxTokenServiceTest.java: TOK-001..002
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/test/java/com/starry/admin/api/WxClerkMediaControllerEndpointsApiTest.java: MED-005..008 (note: MED-006 currently keeps asset.deleted=0)
  • /Volumes/main/code/yunpei/peipei-backend/play-admin/src/test/java/com/starry/admin/api/WxCommonControllerAudioUploadApiTest.java: covers audio upload behavior (see MED-* section for alignment)