feat: add optimistic locking and improve type safety
- Implement optimistic locking for deposit balance updates - Prevent race conditions in concurrent deposit requests - Add automatic retry with exponential backoff (max 3 attempts) - Add version column to user_deposits table - Improve type safety across codebase - Add explicit types for Namecheap API responses - Add typed function arguments (ManageDepositArgs, etc.) - Remove `any` types from deposit-agent and tool files - Add reconciliation job for balance integrity verification - Compare user_deposits.balance vs SUM(confirmed transactions) - Alert admin on discrepancy detection - Set up test environment with Vitest + Miniflare - Add 50+ test cases for deposit system - Add helper functions for test data creation - Update documentation - Add migration guide for version columns - Document optimistic locking patterns Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
228
tests/README.md
Normal file
228
tests/README.md
Normal file
@@ -0,0 +1,228 @@
|
||||
# Unit Tests for telegram-bot-workers
|
||||
|
||||
이 디렉토리는 Cloudflare Workers 환경에서 실행되는 Telegram Bot의 단위 테스트를 포함합니다.
|
||||
|
||||
## 테스트 프레임워크
|
||||
|
||||
- **Vitest**: 빠르고 현대적인 테스트 프레임워크
|
||||
- **Miniflare**: Cloudflare Workers 로컬 시뮬레이터 (D1, KV 지원)
|
||||
- **Coverage**: V8 Coverage Provider
|
||||
|
||||
## 설치
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
필요한 의존성:
|
||||
- `vitest` - 테스트 러너
|
||||
- `miniflare` - Workers 환경 시뮬레이션
|
||||
- `@cloudflare/vitest-pool-workers` - Vitest Workers 통합
|
||||
- `@vitest/coverage-v8` - 커버리지 리포트
|
||||
|
||||
## 실행
|
||||
|
||||
```bash
|
||||
# 모든 테스트 실행
|
||||
npm test
|
||||
|
||||
# Watch 모드 (파일 변경 감지)
|
||||
npm run test:watch
|
||||
|
||||
# 커버리지 리포트 생성
|
||||
npm run test:coverage
|
||||
```
|
||||
|
||||
## 테스트 파일
|
||||
|
||||
### `deposit-agent.test.ts`
|
||||
|
||||
**예치금 시스템 (deposit-agent.ts) 테스트**
|
||||
|
||||
**커버리지**:
|
||||
- ✅ **get_balance**: 신규 사용자 0원, 기존 잔액 조회
|
||||
- ✅ **get_account_info**: 은행 계좌 정보 반환
|
||||
- ✅ **request_deposit**: 음수/0원 거부, 7글자 매칭, 자동/수동 처리
|
||||
- ✅ **get_transactions**: 거래 내역 조회, 정렬, LIMIT 처리
|
||||
- ✅ **cancel_transaction**: 본인/관리자 권한, 상태 검증
|
||||
- ✅ **confirm_deposit**: 잔액 증가, Batch 실패 처리
|
||||
- ✅ **reject_deposit**: 거래 거절
|
||||
- ✅ **get_pending_list**: 관리자 전용
|
||||
- ✅ **Concurrency**: 동시 요청 처리, Race condition
|
||||
- ✅ **Edge Cases**: 큰 금액, 특수문자, 짧은 이름
|
||||
|
||||
**테스트 수**: 50+개
|
||||
|
||||
### `setup.ts`
|
||||
|
||||
**테스트 환경 초기화 및 헬퍼 함수**
|
||||
|
||||
**기능**:
|
||||
- D1 Database 스키마 초기화 (in-memory SQLite)
|
||||
- 각 테스트 후 데이터 정리 (스키마 유지)
|
||||
- 테스트 데이터 생성 헬퍼 함수
|
||||
|
||||
**헬퍼 함수**:
|
||||
```typescript
|
||||
createTestUser(telegramId, username)
|
||||
createBankNotification(depositorName, amount)
|
||||
createDepositTransaction(userId, amount, status, depositorName?)
|
||||
getTestDB()
|
||||
```
|
||||
|
||||
## 테스트 작성 가이드
|
||||
|
||||
### 기본 구조
|
||||
|
||||
```typescript
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { executeDepositFunction } from '../src/deposit-agent';
|
||||
import { createTestUser, getTestDB } from './setup';
|
||||
|
||||
describe('Feature Name', () => {
|
||||
let testUserId: number;
|
||||
|
||||
beforeEach(async () => {
|
||||
testUserId = await createTestUser('123456789', 'testuser');
|
||||
});
|
||||
|
||||
it('should do something', async () => {
|
||||
const result = await executeDepositFunction('function_name', {
|
||||
param: 'value'
|
||||
}, {
|
||||
userId: testUserId,
|
||||
telegramUserId: '123456789',
|
||||
isAdmin: false,
|
||||
db: getTestDB()
|
||||
});
|
||||
|
||||
expect(result).toHaveProperty('success', true);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Mock 전략
|
||||
|
||||
**D1 Database**: Miniflare가 자동으로 in-memory SQLite 제공
|
||||
|
||||
**환경 변수**: `vitest.config.ts`에서 설정
|
||||
```typescript
|
||||
environmentOptions: {
|
||||
bindings: {
|
||||
BOT_TOKEN: 'test-bot-token',
|
||||
WEBHOOK_SECRET: 'test-webhook-secret',
|
||||
DEPOSIT_ADMIN_ID: '999999999',
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**외부 API Mock**: `vi.fn()` 사용
|
||||
```typescript
|
||||
const mockFetch = vi.fn().mockResolvedValue({
|
||||
ok: true,
|
||||
json: async () => ({ data: 'mocked' })
|
||||
});
|
||||
```
|
||||
|
||||
### Batch 실패 시뮬레이션
|
||||
|
||||
```typescript
|
||||
const originalBatch = testContext.db.batch;
|
||||
testContext.db.batch = vi.fn().mockResolvedValue([
|
||||
{ success: true, meta: { changes: 1 } },
|
||||
{ success: false, meta: { changes: 0 } }, // 실패
|
||||
]);
|
||||
|
||||
await expect(someFunction()).rejects.toThrow('처리 실패');
|
||||
|
||||
// 복원
|
||||
testContext.db.batch = originalBatch;
|
||||
```
|
||||
|
||||
## 디버깅
|
||||
|
||||
### Verbose 모드
|
||||
|
||||
```bash
|
||||
npm test -- --reporter=verbose
|
||||
```
|
||||
|
||||
### 특정 테스트만 실행
|
||||
|
||||
```bash
|
||||
# 파일명으로 필터링
|
||||
npm test deposit-agent
|
||||
|
||||
# 테스트 설명으로 필터링
|
||||
npm test -- -t "should reject negative amounts"
|
||||
```
|
||||
|
||||
### 로그 출력
|
||||
|
||||
테스트 내에서 `console.log` 사용 가능:
|
||||
```typescript
|
||||
it('debugging test', async () => {
|
||||
console.log('Debug info:', result);
|
||||
expect(result).toBeDefined();
|
||||
});
|
||||
```
|
||||
|
||||
## CI/CD 통합
|
||||
|
||||
**GitHub Actions 예시**:
|
||||
```yaml
|
||||
- name: Run tests
|
||||
run: npm test
|
||||
|
||||
- name: Upload coverage
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: ./coverage/coverage-final.json
|
||||
```
|
||||
|
||||
## 향후 계획
|
||||
|
||||
- [ ] `openai-service.ts` - Function Calling 도구 테스트
|
||||
- [ ] `summary-service.ts` - 프로필 시스템 테스트
|
||||
- [ ] Integration Tests - 전체 워크플로우 테스트
|
||||
- [ ] E2E Tests - Telegram Bot API 통합 테스트
|
||||
|
||||
## 문제 해결
|
||||
|
||||
### "Cannot find module" 에러
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
### D1 스키마 초기화 실패
|
||||
|
||||
`setup.ts`에서 `schema.sql` 경로 확인:
|
||||
```typescript
|
||||
const schemaPath = join(__dirname, '../schema.sql');
|
||||
```
|
||||
|
||||
### Miniflare 버전 충돌
|
||||
|
||||
`package.json`에서 버전 확인:
|
||||
```json
|
||||
{
|
||||
"miniflare": "^3.20231030.0",
|
||||
"@cloudflare/vitest-pool-workers": "^0.1.0"
|
||||
}
|
||||
```
|
||||
|
||||
### 테스트 타임아웃
|
||||
|
||||
`vitest.config.ts`에서 타임아웃 증가:
|
||||
```typescript
|
||||
test: {
|
||||
testTimeout: 10000, // 기본 5초 → 10초
|
||||
}
|
||||
```
|
||||
|
||||
## 참고 자료
|
||||
|
||||
- [Vitest 공식 문서](https://vitest.dev/)
|
||||
- [Miniflare 공식 문서](https://miniflare.dev/)
|
||||
- [Cloudflare Workers Testing](https://developers.cloudflare.com/workers/testing/)
|
||||
Reference in New Issue
Block a user