package handler import ( "testing" "time" ) // 查单节流是限制「我们打微信查单接口」频率的唯一闸门:前端支付弹窗 2.5s 轮一次, // 没有它的话单笔订单在 30min TTL 内能打出数百次渠道调用。这里把行为钉死。 func TestAllowQuery_Throttle(t *testing.T) { const id = "test-order-throttle" defer forgetQuery(id) if !allowQuery(id) { t.Fatal("首次查单必须放行——否则用户扫码后要白等一个间隔才确认") } if allowQuery(id) { t.Fatal("间隔内的第二次应被拦下") } // 间隔过后重新放行 lastQuery.Store(id, time.Now().Add(-minQueryInterval-time.Second)) if !allowQuery(id) { t.Fatal("超过 minQueryInterval 后应重新放行") } } // 订单落终态后标记要清掉,否则同一订单号(或长期挂着的 pending)会把 map 撑大。 func TestForgetQuery_And_Prune(t *testing.T) { const id = "test-order-forget" allowQuery(id) forgetQuery(id) if _, ok := lastQuery.Load(id); ok { t.Fatal("forgetQuery 应删除标记") } // 用户扫码前就关掉弹窗的订单不会再被轮询,标记无人清理 —— 靠定时 prune 回收 const stale = "test-order-stale" lastQuery.Store(stale, time.Now().Add(-orderTTL-time.Minute)) const fresh = "test-order-fresh" lastQuery.Store(fresh, time.Now()) defer forgetQuery(fresh) pruneQueryMarks() if _, ok := lastQuery.Load(stale); ok { t.Fatal("超过 orderTTL 的陈旧标记应被回收") } if _, ok := lastQuery.Load(fresh); !ok { t.Fatal("仍在有效期内的标记不该被误删") } }