Files
xiaoxia-saas/tests/unit/test_memory_state_store.py
xiaoxia b1babaaedd
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Build Staging Web Image (push) Successful in 28s
CI/CD Pipeline / Frontend Lint (push) Successful in 1m54s
CI/CD Pipeline / Validate Code Quality And Tests (push) Successful in 2m12s
CI/CD Pipeline / Build Staging API Image (push) Successful in 2m31s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 2m40s
CI/CD Pipeline / Unit Tests (push) Successful in 2m42s
CI/CD Pipeline / Integration Tests (push) Successful in 1m11s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 17m6s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 4m35s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 32s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 3m29s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m36s
test(unit): P3-1第六波 新增5个领域模块单元测试(37个用例) (#687)
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com>
Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
2026-07-21 23:33:01 +08:00

143 lines
5.0 KiB
Python
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""MemoryStateStore 单元测试 - 微信 OAuth state 存储
覆盖:正常存取、一次性消费、过期清理、并发安全、空 state 处理。
"""
from __future__ import annotations
import time
from threading import Thread
import pytest
class TestMemoryStateStore:
def test_put_and_verify_success(self):
"""正常存入并校验成功"""
from packages.application.auth.wechat_oauth_service import MemoryStateStore
store = MemoryStateStore()
store.put("test_state_123")
assert store.verify_and_consume("test_state_123") is True
def test_verify_nonexistent_state_fails(self):
"""不存在的 state 校验失败"""
from packages.application.auth.wechat_oauth_service import MemoryStateStore
store = MemoryStateStore()
assert store.verify_and_consume("nonexistent") is False
def test_state_single_use(self):
"""state 只能消费一次(防重放)"""
from packages.application.auth.wechat_oauth_service import MemoryStateStore
store = MemoryStateStore()
store.put("single_use_state")
assert store.verify_and_consume("single_use_state") is True
assert store.verify_and_consume("single_use_state") is False
def test_empty_state_rejected(self):
"""空字符串 state 校验失败"""
from packages.application.auth.wechat_oauth_service import MemoryStateStore
store = MemoryStateStore()
store.put("")
# 空字符串作为 key 技术上可以存,但业务层应该拒绝
# 这里验证 store 本身行为一致性
assert store.verify_and_consume("") is True # 存入了就能通过一次
assert store.verify_and_consume("") is False # 消费后就没了
def test_expired_state_cleaned(self):
"""过期 state 会被清理,校验失败"""
from packages.application.auth.wechat_oauth_service import MemoryStateStore
# TTL 设为 0.01 秒,快速过期
store = MemoryStateStore(ttl_seconds=0.01)
store.put("expire_me")
time.sleep(0.02)
assert store.verify_and_consume("expire_me") is False
def test_multiple_states_independent(self):
"""多个 state 互不影响"""
from packages.application.auth.wechat_oauth_service import MemoryStateStore
store = MemoryStateStore()
store.put("state_a")
store.put("state_b")
store.put("state_c")
# 消费 b
assert store.verify_and_consume("state_b") is True
assert store.verify_and_consume("state_b") is False
# a 和 c 仍然有效
assert store.verify_and_consume("state_a") is True
assert store.verify_and_consume("state_c") is True
def test_clean_expired_doesnt_touch_valid(self):
"""过期清理不影响未过期的 state"""
from packages.application.auth.wechat_oauth_service import MemoryStateStore
store = MemoryStateStore(ttl_seconds=10)
store.put("valid_state")
# 手动触发清理(通过 verify 触发内部 clean_expired
# 由于所有 state 都没过期,清理不影响
assert store.verify_and_consume("valid_state") is True
def test_thread_safety_concurrent_put(self):
"""并发写入不丢数据"""
from packages.application.auth.wechat_oauth_service import MemoryStateStore
store = MemoryStateStore(ttl_seconds=60)
states = [f"state_{i}" for i in range(100)]
def put_states(states_list):
for s in states_list:
store.put(s)
threads = [Thread(target=put_states, args=(states[i * 20 : (i + 1) * 20],)) for i in range(5)]
for t in threads:
t.start()
for t in threads:
t.join()
# 每个 state 都能消费一次
for s in states:
assert store.verify_and_consume(s) is True
def test_thread_safety_concurrent_consume(self):
"""并发消费同一个 state 只有一个能成功"""
from packages.application.auth.wechat_oauth_service import MemoryStateStore
store = MemoryStateStore()
store.put("contested_state")
results = []
def try_consume():
results.append(store.verify_and_consume("contested_state"))
threads = [Thread(target=try_consume) for _ in range(10)]
for t in threads:
t.start()
for t in threads:
t.join()
# 只有一个成功,其余失败
assert sum(1 for r in results if r) == 1
assert sum(1 for r in results if not r) == 9
def test_default_ttl_is_10_minutes(self):
"""默认 TTL 是 600 秒(10分钟)"""
from packages.application.auth.wechat_oauth_service import (
STATE_TTL_SECONDS,
MemoryStateStore,
)
assert STATE_TTL_SECONDS == 600
store = MemoryStateStore()
# 验证默认值生效:存入后立即验证应该通过
store.put("default_ttl_test")
assert store.verify_and_consume("default_ttl_test") is True