create-dp-koa 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. package/README.md +50 -0
  2. package/index.mjs +97 -0
  3. package/package.json +33 -0
  4. package/template/.env.development +9 -0
  5. package/template/.env.production +12 -0
  6. package/template/.github/workflows/ci-cd.yml +182 -0
  7. package/template/.trae/documents/controller_development_plan.md +386 -0
  8. package/template/.trae/skills/00-backend-core.skill.md +50 -0
  9. package/template/.trae/skills/01-backend-skill-router.skill.md +55 -0
  10. package/template/.trae/skills/10-backend-api.skill.md +54 -0
  11. package/template/.trae/skills/11-backend-controller-recipes.skill.md +107 -0
  12. package/template/.trae/skills/20-backend-repository.skill.md +25 -0
  13. package/template/.trae/skills/21-backend-service.skill.md +135 -0
  14. package/template/.trae/skills/25-backend-comments-and-doc.skill.md +97 -0
  15. package/template/.trae/skills/30-backend-validation.skill.md +320 -0
  16. package/template/.trae/skills/40-backend-error-logging.skill.md +21 -0
  17. package/template/.trae/skills/50-backend-bootstrap-lifecycle.skill.md +90 -0
  18. package/template/.trae/skills/60-backend-router-registration.skill.md +71 -0
  19. package/template/.trae/skills/70-backend-middleware.skill.md +98 -0
  20. package/template/.trae/skills/80-backend-utils-and-libs.skill.md +90 -0
  21. package/template/.trae/skills/85-backend-plugins.rule.md +64 -0
  22. package/template/.trae/skills/90-backend-testing.skill.md +29 -0
  23. package/template/.trae/skills/README.md +49 -0
  24. package/template/.vscode/launch.json +38 -0
  25. package/template/.vscode/settings.json +1 -0
  26. package/template/Dockerfile +36 -0
  27. package/template/README.md +229 -0
  28. package/template/docker-compose.yml +135 -0
  29. package/template/docs/API_DOCUMENTATION.md +837 -0
  30. package/template/docs/ARCHITECTURE_REFACTOR.md +109 -0
  31. package/template/docs/CACHE_MIGRATION_GUIDE.md +142 -0
  32. package/template/docs/DEPLOYMENT_GUIDE.md +1062 -0
  33. package/template/docs/DEVELOPMENT_GUIDE.md +1097 -0
  34. package/template/docs/DOCUMENTATION_CLEANUP_REPORT.md +166 -0
  35. package/template/docs/DOCUMENTATION_COMPLETION_REPORT.md +223 -0
  36. package/template/docs/DOCUMENTATION_INDEX.md +294 -0
  37. package/template/docs/DOCUMENTATION_STRUCTURE.md +221 -0
  38. package/template/docs/ENTERPRISE_ANNOTATION_SYSTEM_GUIDE.md +2069 -0
  39. package/template/docs/ENTERPRISE_DATABASE_ARCHITECTURE.md +318 -0
  40. package/template/docs/ENTERPRISE_DEPLOYMENT_GUIDE.md +547 -0
  41. package/template/docs/ENTERPRISE_ERROR_HANDLING_GUIDE.md +357 -0
  42. package/template/docs/ENTERPRISE_LOGGING_SYSTEM_GUIDE.md +494 -0
  43. package/template/docs/ENVIRONMENT_CONFIG_EXAMPLE.md +69 -0
  44. package/template/docs/FINAL_IMPLEMENTATION_SUMMARY.md +206 -0
  45. package/template/docs/HEALTH_CHECK_ROUTE_FIX.md +134 -0
  46. package/template/docs/IMPLEMENTATION_CHECKLIST.md +204 -0
  47. package/template/docs/INSTALLATION_GUIDE.md +611 -0
  48. package/template/docs/INTERCEPTOR_TESTING_REPORT.md +226 -0
  49. package/template/docs/INTERCEPTOR_TESTING_SCRIPTS.md +143 -0
  50. package/template/docs/LOGGING_OPTIMIZATION_GUIDE.md +126 -0
  51. package/template/docs/MEMORY_DATABASE_GUIDE.md +212 -0
  52. package/template/docs/NEW_ROUTER_INTEGRATION_GUIDE.md +345 -0
  53. package/template/docs/NEW_ROUTER_INTEGRATION_SUMMARY.md +259 -0
  54. package/template/docs/NEW_ROUTER_USAGE_GUIDE.md +364 -0
  55. package/template/docs/QUICK_START.md +268 -0
  56. package/template/docs/ROUTE_SLASH_COMPATIBILITY_FIX.md +191 -0
  57. package/template/docs/SERVICE_INTERCEPTOR_GUIDE.md +243 -0
  58. package/template/docs/SERVICE_LAYER_INDEX.md +205 -0
  59. package/template/docs/SERVICE_PATTERN_GUIDE.md +270 -0
  60. package/template/docs/SERVICE_RETURN_VALUE_SPECIFICATION.md +466 -0
  61. package/template/docs/SWAGGER_DEBUG_MODE_GUIDE.md +80 -0
  62. package/template/docs/SWAGGER_INTEGRATION_GUIDE.md +416 -0
  63. package/template/docs/TRANSACTION_MANAGER_USAGE.md +360 -0
  64. package/template/docs/TROUBLESHOOTING.md +869 -0
  65. package/template/env.production.example +62 -0
  66. package/template/jest.config.js +34 -0
  67. package/template/package-lock.json +13240 -0
  68. package/template/package.json +119 -0
  69. package/template/patches/typeorm+0.3.25.patch +22 -0
  70. package/template/scripts/sync-template.mjs +84 -0
  71. package/template/scripts/test-annotation-system.sh +48 -0
  72. package/template/scripts/test-core-functionality.sh +28 -0
  73. package/template/src/annotations/decorators/ConfigManagement.ts +9 -0
  74. package/template/src/annotations/decorators/DistributedTracing.ts +9 -0
  75. package/template/src/annotations/decorators/EnterprisePerformance.ts +9 -0
  76. package/template/src/annotations/decorators/PerformanceMonitor.ts +32 -0
  77. package/template/src/annotations/decorators/SecurityAudit.ts +9 -0
  78. package/template/src/annotations/index.ts +50 -0
  79. package/template/src/annotations/processors/ConfigManagementProcessor.ts +369 -0
  80. package/template/src/annotations/processors/DistributedTracingProcessor.ts +288 -0
  81. package/template/src/annotations/processors/EnterprisePerformanceProcessor.ts +189 -0
  82. package/template/src/annotations/processors/PerformanceMonitorProcessor.ts +101 -0
  83. package/template/src/annotations/processors/SecurityAuditProcessor.ts +345 -0
  84. package/template/src/annotations/processors/SwaggerProcessor.ts +612 -0
  85. package/template/src/annotations/processors/index.ts +10 -0
  86. package/template/src/app.ts +123 -0
  87. package/template/src/controllers/base.controller.ts +41 -0
  88. package/template/src/controllers/cacheManagement.controller.ts +131 -0
  89. package/template/src/controllers/captcha.controller.ts +57 -0
  90. package/template/src/controllers/demo/AnnotationDemoController.ts +118 -0
  91. package/template/src/controllers/example/EnterpriseExampleController.ts +297 -0
  92. package/template/src/controllers/example/ExampleController.ts +110 -0
  93. package/template/src/controllers/example/NewAnnotationExampleController.ts +159 -0
  94. package/template/src/controllers/example/SwaggerExampleController.ts +205 -0
  95. package/template/src/controllers/example/TransactionExample.controller.ts +336 -0
  96. package/template/src/controllers/health.controller.ts +235 -0
  97. package/template/src/controllers/home/register.controller.ts +58 -0
  98. package/template/src/controllers/home/ytGoods.controller.ts +92 -0
  99. package/template/src/controllers/home/ytShop.controller.ts +135 -0
  100. package/template/src/controllers/home/ytUser.controller.ts +89 -0
  101. package/template/src/controllers/logManagement.controller.ts +396 -0
  102. package/template/src/controllers/public/emailSend.controller.ts +65 -0
  103. package/template/src/controllers/public/ytUserAuth.controller.ts +174 -0
  104. package/template/src/controllers/testData.controller.ts +253 -0
  105. package/template/src/dto/controller/example/NewAnnotationExampleController.dto.ts +73 -0
  106. package/template/src/dto/controller/home/emailSend.controller.dto.ts +40 -0
  107. package/template/src/dto/controller/home/register.controller.dto.ts +45 -0
  108. package/template/src/dto/controller/home/ytGoods.controller.dto.ts +55 -0
  109. package/template/src/dto/controller/home/ytShop.controller.dto.ts +69 -0
  110. package/template/src/dto/controller/home/ytUser.controller.dto.ts +44 -0
  111. package/template/src/dto/controller/public/ytUserAuth.controller.dto.ts +63 -0
  112. package/template/src/dto/goods.dto.ts +212 -0
  113. package/template/src/dto/service/ytService.dto.ts +13 -0
  114. package/template/src/dto/user.dto.ts +177 -0
  115. package/template/src/entity/base.entity.ts +13 -0
  116. package/template/src/entity/columnTypes.ts +13 -0
  117. package/template/src/entity/goodsImagesUnlockKey.entity.ts +33 -0
  118. package/template/src/entity/goodsUnlocker.entity.ts +34 -0
  119. package/template/src/entity/index.ts +15 -0
  120. package/template/src/entity/shop.entity.ts +52 -0
  121. package/template/src/entity/shopUser.entity.ts +41 -0
  122. package/template/src/entity/ytGoods.entity.ts +94 -0
  123. package/template/src/entity/ytUser.entity.ts +96 -0
  124. package/template/src/examples/InterceptorExampleRunner.ts +284 -0
  125. package/template/src/examples/ServiceInterceptorExample.ts +214 -0
  126. package/template/src/examples/SwaggerProcessorExample.ts +169 -0
  127. package/template/src/examples/TransactionManagerDemo.ts +377 -0
  128. package/template/src/examples/cacheExamples.ts +155 -0
  129. package/template/src/framework/decorator/controller.ts +311 -0
  130. package/template/src/framework/decorator/processor/AnnotationDecorators.ts +100 -0
  131. package/template/src/framework/decorator/processor/AnnotationProcessor.ts +156 -0
  132. package/template/src/framework/decorator/processor/AnnotationProcessorConfig.ts +45 -0
  133. package/template/src/framework/decorator/processor/AnnotationRegistry.ts +117 -0
  134. package/template/src/framework/decorator/processor/AnnotationSystemInitializer.ts +95 -0
  135. package/template/src/framework/decorator/processor/ProcessorManager.ts +76 -0
  136. package/template/src/framework/decorator/processor/processors/CustomProcessors.ts +126 -0
  137. package/template/src/framework/decorator/processor/processors/DefaultProcessors.ts +207 -0
  138. package/template/src/framework/decorator/refactored/DecoratorFactory.ts +99 -0
  139. package/template/src/framework/decorator/refactored/DecoratorMetadataManager.ts +125 -0
  140. package/template/src/framework/decorator/refactored/DecoratorValidator.ts +128 -0
  141. package/template/src/framework/decorator/refactored/TypeSafeDecorators.ts +139 -0
  142. package/template/src/framework/decorator/refactored/index.ts +98 -0
  143. package/template/src/framework/decorator/swagger.ts +150 -0
  144. package/template/src/framework/interceptors/AdvancedServiceCallInterceptor.ts +375 -0
  145. package/template/src/framework/interceptors/ServiceCallInterceptor.ts +348 -0
  146. package/template/src/framework/interceptors/index.ts +19 -0
  147. package/template/src/framework/plugins/registry.ts +63 -0
  148. package/template/src/framework/plugins/types.ts +15 -0
  149. package/template/src/framework/types/ServiceResult.ts +151 -0
  150. package/template/src/framework/types/index.ts +16 -0
  151. package/template/src/framework/utils/CacheManager.ts +430 -0
  152. package/template/src/framework/utils/CacheService.ts +248 -0
  153. package/template/src/framework/utils/DtoValidator.ts +164 -0
  154. package/template/src/framework/utils/MigrationHelper.ts +179 -0
  155. package/template/src/framework/utils/MigrationManager.ts +256 -0
  156. package/template/src/framework/utils/NewRouter.ts +207 -0
  157. package/template/src/framework/utils/TransactionManager.ts +172 -0
  158. package/template/src/framework/utils/bootstrap.ts +445 -0
  159. package/template/src/framework/utils/cache.ts +269 -0
  160. package/template/src/framework/utils/databaseConfig.ts +148 -0
  161. package/template/src/framework/utils/db.ts +39 -0
  162. package/template/src/framework/utils/dbMonitor.ts +106 -0
  163. package/template/src/framework/utils/dynamicSwagger.ts +410 -0
  164. package/template/src/framework/utils/function.ts +61 -0
  165. package/template/src/framework/utils/gracefulShutdown.ts +131 -0
  166. package/template/src/framework/utils/logger.ts +388 -0
  167. package/template/src/framework/utils/metrics.ts +182 -0
  168. package/template/src/framework/utils/router.ts +417 -0
  169. package/template/src/framework/utils/swagger.ts +184 -0
  170. package/template/src/framework/utils/testDb.ts +19 -0
  171. package/template/src/framework/utils/token.ts +23 -0
  172. package/template/src/framework/utils/transform.ts +17 -0
  173. package/template/src/libs/aokEmailSender.ts +42 -0
  174. package/template/src/libs/captcha.ts +37 -0
  175. package/template/src/libs/cos.ts +45 -0
  176. package/template/src/libs/mCache.ts +7 -0
  177. package/template/src/libs/serviceValidate.ts +3 -0
  178. package/template/src/libs/tecentSms.ts +51 -0
  179. package/template/src/middlewares/a.middleware.ts +6 -0
  180. package/template/src/middlewares/error.middleware.ts +14 -0
  181. package/template/src/middlewares/logging.middleware.ts +187 -0
  182. package/template/src/middlewares/static.middleware.ts +79 -0
  183. package/template/src/middlewares/swagger.middleware.ts +70 -0
  184. package/template/src/middlewares/token.middleware.ts +32 -0
  185. package/template/src/migrations/1700000000000-InitialDatabaseStructure.ts +172 -0
  186. package/template/src/migrations/index.ts +6 -0
  187. package/template/src/plugins/weboffice/core/context.ts +47 -0
  188. package/template/src/plugins/weboffice/core/errors.ts +51 -0
  189. package/template/src/plugins/weboffice/core/types.ts +63 -0
  190. package/template/src/plugins/weboffice/core/utils.ts +7 -0
  191. package/template/src/plugins/weboffice/entities/index.ts +3 -0
  192. package/template/src/plugins/weboffice/entities/webofficeFile.entity.ts +28 -0
  193. package/template/src/plugins/weboffice/entities/webofficeFileVersion.entity.ts +29 -0
  194. package/template/src/plugins/weboffice/http/routes.ts +179 -0
  195. package/template/src/plugins/weboffice/index.ts +23 -0
  196. package/template/src/plugins/weboffice/services/webofficeCallback.service.ts +274 -0
  197. package/template/src/repository/UserRepository.ts +122 -0
  198. package/template/src/repository/base/BaseRepository.ts +124 -0
  199. package/template/src/repository/interfaces/IBaseRepository.ts +67 -0
  200. package/template/src/routers/index.ts +49 -0
  201. package/template/src/service/base.service.ts +116 -0
  202. package/template/src/service/paramValidateTest.service.ts +139 -0
  203. package/template/src/service/ytGoods.service.ts +42 -0
  204. package/template/src/service/ytShop.service.ts +90 -0
  205. package/template/src/service/ytUser.service.ts +451 -0
  206. package/template/src/test/swaggerParameterTest.ts +90 -0
  207. package/template/src/utils/testDataInitializer.ts +296 -0
  208. package/template/static/output.json +15203 -0
  209. package/template/test/controllers/controllers.test.ts +173 -0
  210. package/template/test/controllers/example/ExampleController.test.ts +222 -0
  211. package/template/test/controllers/example/NewAnnotationExampleController.test.ts +200 -0
  212. package/template/test/framework/TransactionManagerDemo.test.ts +363 -0
  213. package/template/test/framework/annotation/AnnotationDecorators.test.ts +222 -0
  214. package/template/test/framework/annotation/AnnotationExecutor.test.ts +246 -0
  215. package/template/test/framework/annotation/AnnotationProcessor.test.ts +179 -0
  216. package/template/test/framework/annotation/CustomProcessors.test.ts +313 -0
  217. package/template/test/framework/annotation/DefaultProcessors.test.ts +371 -0
  218. package/template/test/framework/annotation/NewRouter.test.ts +272 -0
  219. package/template/test/framework/annotation/ProcessorManager.test.ts +248 -0
  220. package/template/test/framework/annotation/setup.ts +26 -0
  221. package/template/test/framework/cache.test.ts +101 -0
  222. package/template/test/framework/databaseConfig.test.ts +142 -0
  223. package/template/test/integration/integration.test.ts +153 -0
  224. package/template/test/plugins/weboffice/http.routes.int.test.ts +61 -0
  225. package/template/test/service/business.test.ts +87 -0
  226. package/template/test/service/paramValidateTest.service.test.ts +184 -0
  227. package/template/test/service/ytUser.service.test.ts +566 -0
  228. package/template/test/setup.ts +20 -0
  229. package/template/test/setupAfterEnv.ts +14 -0
  230. package/template/test/utils/testHelpers.ts +220 -0
  231. package/template/test_output.txt +0 -0
  232. package/template/tsconfig.build.json +17 -0
  233. package/template/tsconfig.json +31 -0
  234. package/template/webpack.config.js +71 -0
  235. package/template/yarn.lock +7354 -0
@@ -0,0 +1,313 @@
1
+ import { LoggingProcessor, PermissionProcessor, RateLimitProcessor } from '../../../src/framework/decorator/processor/processors/CustomProcessors';
2
+ import { Context } from 'koa';
3
+
4
+ // 模拟 Koa Context
5
+ const createMockContext = (): Context => ({
6
+ status: 200,
7
+ body: null,
8
+ request: {
9
+ body: {},
10
+ headers: {},
11
+ query: {}
12
+ },
13
+ params: {},
14
+ state: {},
15
+ ip: '127.0.0.1',
16
+ set: jest.fn(),
17
+ throw: jest.fn()
18
+ } as any);
19
+
20
+ describe('自定义处理器测试', () => {
21
+ let mockContext: Context;
22
+
23
+ beforeEach(() => {
24
+ mockContext = createMockContext();
25
+ jest.clearAllMocks();
26
+ // 清空控制台输出
27
+ jest.spyOn(console, 'log').mockImplementation(() => {});
28
+ });
29
+
30
+ afterEach(() => {
31
+ jest.restoreAllMocks();
32
+ });
33
+
34
+ describe('LoggingProcessor', () => {
35
+ let processor: LoggingProcessor;
36
+
37
+ beforeEach(() => {
38
+ processor = new LoggingProcessor();
39
+ });
40
+
41
+ test('应该正确设置名称和优先级', () => {
42
+ expect(processor.name).toBe('Logging');
43
+ expect(processor.priority).toBe(10);
44
+ });
45
+
46
+ test('应该记录请求开始日志', async () => {
47
+ const mockController = {
48
+ constructor: { name: 'TestController' }
49
+ };
50
+
51
+ const result = await processor.process(
52
+ mockContext,
53
+ mockController,
54
+ 'testMethod',
55
+ null,
56
+ [{ id: 1 }]
57
+ );
58
+
59
+ expect(result).toBe(true);
60
+ expect(console.log).toHaveBeenCalledWith(
61
+ '[Logging] 开始处理请求: TestController.testMethod'
62
+ );
63
+ expect(console.log).toHaveBeenCalledWith(
64
+ '[Logging] 请求参数:',
65
+ [{ id: 1 }]
66
+ );
67
+ expect(mockContext.state.loggingStartTime).toBeDefined();
68
+ });
69
+
70
+ test('logResponse静态方法应该记录响应日志', () => {
71
+ mockContext.state.loggingStartTime = Date.now() - 100; // 100ms前
72
+
73
+ LoggingProcessor.logResponse(
74
+ mockContext,
75
+ { constructor: { name: 'TestController' } },
76
+ 'testMethod',
77
+ { data: 'test' }
78
+ );
79
+
80
+ expect(console.log).toHaveBeenCalledWith(
81
+ '[Logging] 完成处理请求: TestController.testMethod'
82
+ );
83
+ expect(console.log).toHaveBeenCalledWith(
84
+ '[Logging] 响应数据:',
85
+ { data: 'test' }
86
+ );
87
+ expect(console.log).toHaveBeenCalledWith(
88
+ expect.stringMatching(/\[Logging\] 处理耗时: \d+ms/)
89
+ );
90
+ });
91
+ });
92
+
93
+ describe('PermissionProcessor', () => {
94
+ let processor: PermissionProcessor;
95
+
96
+ beforeEach(() => {
97
+ processor = new PermissionProcessor();
98
+ });
99
+
100
+ test('应该正确设置名称和优先级', () => {
101
+ expect(processor.name).toBe('Permission');
102
+ expect(processor.priority).toBe(5);
103
+ });
104
+
105
+ test('没有用户信息时应该返回false', async () => {
106
+ mockContext.state = {};
107
+
108
+ const result = await processor.process(
109
+ mockContext,
110
+ {},
111
+ 'testMethod',
112
+ null,
113
+ []
114
+ );
115
+
116
+ expect(result).toBe(false);
117
+ expect(mockContext.status).toBe(401);
118
+ expect(mockContext.body).toEqual({ error: '未授权访问' });
119
+ });
120
+
121
+ test('有用户信息但没有权限要求时应该返回true', async () => {
122
+ mockContext.state = {
123
+ user: { id: 1, name: 'test' }
124
+ };
125
+
126
+ const result = await processor.process(
127
+ mockContext,
128
+ {},
129
+ 'testMethod',
130
+ null,
131
+ []
132
+ );
133
+
134
+ expect(result).toBe(true);
135
+ });
136
+
137
+ test('用户有足够权限时应该返回true', async () => {
138
+ mockContext.state = {
139
+ user: {
140
+ id: 1,
141
+ name: 'test',
142
+ permissions: ['read:data', 'write:data']
143
+ }
144
+ };
145
+
146
+ const result = await processor.process(
147
+ mockContext,
148
+ {},
149
+ 'testMethod',
150
+ { requiredPermission: 'read:data' },
151
+ []
152
+ );
153
+
154
+ expect(result).toBe(true);
155
+ });
156
+
157
+ test('用户权限不足时应该返回false', async () => {
158
+ mockContext.state = {
159
+ user: {
160
+ id: 1,
161
+ name: 'test',
162
+ permissions: ['read:data']
163
+ }
164
+ };
165
+
166
+ const result = await processor.process(
167
+ mockContext,
168
+ {},
169
+ 'testMethod',
170
+ { requiredPermission: 'write:data' },
171
+ []
172
+ );
173
+
174
+ expect(result).toBe(false);
175
+ expect(mockContext.status).toBe(403);
176
+ expect(mockContext.body).toEqual({ error: '权限不足' });
177
+ });
178
+
179
+ test('用户没有权限数组时应该返回false', async () => {
180
+ mockContext.state = {
181
+ user: {
182
+ id: 1,
183
+ name: 'test'
184
+ }
185
+ };
186
+
187
+ const result = await processor.process(
188
+ mockContext,
189
+ {},
190
+ 'testMethod',
191
+ { requiredPermission: 'read:data' },
192
+ []
193
+ );
194
+
195
+ expect(result).toBe(false);
196
+ expect(mockContext.status).toBe(403);
197
+ expect(mockContext.body).toEqual({ error: '权限不足' });
198
+ });
199
+ });
200
+
201
+ describe('RateLimitProcessor', () => {
202
+ let processor: RateLimitProcessor;
203
+
204
+ beforeEach(() => {
205
+ processor = new RateLimitProcessor();
206
+ // 清空静态属性
207
+ (RateLimitProcessor as any).requestCounts.clear();
208
+ });
209
+
210
+ test('应该正确设置名称和优先级', () => {
211
+ expect(processor.name).toBe('RateLimit');
212
+ expect(processor.priority).toBe(15);
213
+ });
214
+
215
+ test('没有注解数据时应该返回true', async () => {
216
+ const result = await processor.process(
217
+ mockContext,
218
+ {},
219
+ 'testMethod',
220
+ null,
221
+ []
222
+ );
223
+
224
+ expect(result).toBe(true);
225
+ });
226
+
227
+ test('请求次数在限制内时应该返回true', async () => {
228
+ const result = await processor.process(
229
+ mockContext,
230
+ {},
231
+ 'testMethod',
232
+ { maxRequests: 10, windowMs: 60000 },
233
+ []
234
+ );
235
+
236
+ expect(result).toBe(true);
237
+ });
238
+
239
+ test('请求次数超过限制时应该返回false', async () => {
240
+ const annotationData = { maxRequests: 2, windowMs: 60000 };
241
+
242
+ // 第一次请求
243
+ await processor.process(mockContext, {}, 'testMethod', annotationData, []);
244
+
245
+ // 第二次请求
246
+ await processor.process(mockContext, {}, 'testMethod', annotationData, []);
247
+
248
+ // 第三次请求应该被限制
249
+ const result = await processor.process(mockContext, {}, 'testMethod', annotationData, []);
250
+
251
+ expect(result).toBe(false);
252
+ expect(mockContext.status).toBe(429);
253
+ expect(mockContext.body).toEqual({ error: '请求过于频繁,请稍后再试' });
254
+ });
255
+
256
+ test('应该使用默认限制参数', async () => {
257
+ const result = await processor.process(
258
+ mockContext,
259
+ {},
260
+ 'testMethod',
261
+ {},
262
+ []
263
+ );
264
+
265
+ expect(result).toBe(true);
266
+ });
267
+
268
+ test('不同客户端应该有独立的限制', async () => {
269
+ const context1 = createMockContext();
270
+ context1.ip = '192.168.1.1';
271
+
272
+ const context2 = createMockContext();
273
+ context2.ip = '192.168.1.2';
274
+
275
+ const annotationData = { maxRequests: 1, windowMs: 60000 };
276
+
277
+ // 客户端1的请求
278
+ await processor.process(context1, {}, 'testMethod', annotationData, []);
279
+
280
+ // 客户端2的请求应该不受影响
281
+ const result = await processor.process(context2, {}, 'testMethod', annotationData, []);
282
+
283
+ expect(result).toBe(true);
284
+ });
285
+
286
+ test('不同方法应该有独立的限制', async () => {
287
+ const annotationData = { maxRequests: 1, windowMs: 60000 };
288
+
289
+ // 方法1的请求
290
+ await processor.process(mockContext, { constructor: { name: 'Controller' } }, 'method1', annotationData, []);
291
+
292
+ // 方法2的请求应该不受影响
293
+ const result = await processor.process(mockContext, { constructor: { name: 'Controller' } }, 'method2', annotationData, []);
294
+
295
+ expect(result).toBe(true);
296
+ });
297
+
298
+ test('时间窗口过期后应该重置计数器', async () => {
299
+ const annotationData = { maxRequests: 1, windowMs: 1 }; // 1ms窗口
300
+
301
+ // 第一次请求
302
+ await processor.process(mockContext, {}, 'testMethod', annotationData, []);
303
+
304
+ // 等待窗口过期
305
+ await new Promise(resolve => setTimeout(resolve, 10));
306
+
307
+ // 第二次请求应该成功
308
+ const result = await processor.process(mockContext, {}, 'testMethod', annotationData, []);
309
+
310
+ expect(result).toBe(true);
311
+ });
312
+ });
313
+ });
@@ -0,0 +1,371 @@
1
+ import { ParameterValidationProcessor, ResponseValidationProcessor, CacheProcessor, ResponseCodeProcessor, ResponseHeaderProcessor } from '../../../src/framework/decorator/processor/processors/DefaultProcessors';
2
+ import { Context } from 'koa';
3
+ import { validate } from 'class-validator';
4
+
5
+ // 模拟 class-validator
6
+ jest.mock('class-validator', () => ({
7
+ validate: jest.fn()
8
+ }));
9
+
10
+ // 模拟 Koa Context
11
+ const createMockContext = (): Context => ({
12
+ status: 200,
13
+ body: null,
14
+ request: {
15
+ body: { name: 'test', email: 'test@example.com' },
16
+ headers: { 'content-type': 'application/json' },
17
+ query: { id: '123' }
18
+ },
19
+ params: { userId: '456' },
20
+ state: { user: { id: 1, name: 'test' } },
21
+ set: jest.fn(),
22
+ throw: jest.fn()
23
+ } as any);
24
+
25
+ // 测试用的验证类
26
+ class TestValidationClass {
27
+ name: string;
28
+ email: string;
29
+ }
30
+
31
+ describe('默认处理器测试', () => {
32
+ let mockContext: Context;
33
+
34
+ beforeEach(() => {
35
+ mockContext = createMockContext();
36
+ jest.clearAllMocks();
37
+ });
38
+
39
+ describe('ParameterValidationProcessor', () => {
40
+ let processor: ParameterValidationProcessor;
41
+
42
+ beforeEach(() => {
43
+ processor = new ParameterValidationProcessor();
44
+ });
45
+
46
+ test('应该正确设置名称和优先级', () => {
47
+ expect(processor.name).toBe('ParameterValidation');
48
+ expect(processor.priority).toBe(100);
49
+ });
50
+
51
+ test('没有参数信息时应该返回true', async () => {
52
+ const mockController = {};
53
+
54
+ const result = await processor.process(
55
+ mockContext,
56
+ mockController,
57
+ 'testMethod',
58
+ null,
59
+ []
60
+ );
61
+
62
+ expect(result).toBe(true);
63
+ });
64
+
65
+ test('没有验证类时应该返回true', async () => {
66
+ const mockController = {
67
+ $_MethdosParamInfo: new Map([
68
+ ['testMethod', [{ type: 'Body', validate: null }]]
69
+ ])
70
+ };
71
+
72
+ const result = await processor.process(
73
+ mockContext,
74
+ mockController,
75
+ 'testMethod',
76
+ [{ type: 'Body', validate: null }],
77
+ [{ name: 'test' }]
78
+ );
79
+
80
+ expect(result).toBe(true);
81
+ });
82
+
83
+ test('验证通过时应该返回true', async () => {
84
+ (validate as jest.Mock).mockResolvedValue([]);
85
+
86
+ const mockController = {
87
+ $_MethdosParamInfo: new Map([
88
+ ['testMethod', [{ type: 'Body', validate: TestValidationClass }]]
89
+ ])
90
+ };
91
+
92
+ const result = await processor.process(
93
+ mockContext,
94
+ mockController,
95
+ 'testMethod',
96
+ [{ type: 'Body', validate: TestValidationClass }],
97
+ [{ name: 'test', email: 'test@example.com' }]
98
+ );
99
+
100
+ expect(result).toBe(true);
101
+ expect(validate).toHaveBeenCalled();
102
+ });
103
+
104
+ test('验证失败时应该返回false并设置响应', async () => {
105
+ const validationErrors = [{ property: 'email', constraints: { isEmail: 'email格式不正确' } }];
106
+ (validate as jest.Mock).mockResolvedValue(validationErrors);
107
+
108
+ const mockController = {
109
+ $_MethdosParamInfo: new Map([
110
+ ['testMethod', [{ type: 'Body', validate: TestValidationClass }]]
111
+ ])
112
+ };
113
+
114
+ const result = await processor.process(
115
+ mockContext,
116
+ mockController,
117
+ 'testMethod',
118
+ [{ type: 'Body', validate: TestValidationClass }],
119
+ [{ name: 'test', email: 'invalid-email' }]
120
+ );
121
+
122
+ expect(result).toBe(false);
123
+ expect(mockContext.status).toBe(400);
124
+ expect(mockContext.body).toEqual(validationErrors);
125
+ });
126
+ });
127
+
128
+ describe('ResponseValidationProcessor', () => {
129
+ let processor: ResponseValidationProcessor;
130
+
131
+ beforeEach(() => {
132
+ processor = new ResponseValidationProcessor();
133
+ });
134
+
135
+ test('应该正确设置名称和优先级', () => {
136
+ expect(processor.name).toBe('ResponseValidation');
137
+ expect(processor.priority).toBe(200);
138
+ });
139
+
140
+ test('process方法应该返回true', async () => {
141
+ const result = await processor.process(
142
+ mockContext,
143
+ {},
144
+ 'testMethod',
145
+ null,
146
+ []
147
+ );
148
+
149
+ expect(result).toBe(true);
150
+ });
151
+
152
+ test('validateResponse方法应该处理ResponseValidateIf注解', async () => {
153
+ (validate as jest.Mock).mockResolvedValue([]);
154
+
155
+ const mockController = {
156
+ $_ResponseValidateIf: new Map([
157
+ ['testMethod', {
158
+ fn: jest.fn().mockReturnValue({ name: 'test' }),
159
+ clas: TestValidationClass
160
+ }]
161
+ ])
162
+ };
163
+
164
+ const errors = await processor.validateResponse(
165
+ mockController,
166
+ 'testMethod',
167
+ { name: 'test' }
168
+ );
169
+
170
+ expect(errors).toEqual([]);
171
+ expect(validate).toHaveBeenCalled();
172
+ });
173
+
174
+ test('validateResponse方法应该处理ResponseValidator注解', async () => {
175
+ (validate as jest.Mock).mockResolvedValue([]);
176
+
177
+ const mockController = {
178
+ $_ResponseValidator: new Map([
179
+ ['testMethod', {
180
+ clas: TestValidationClass,
181
+ objectKey: 'data'
182
+ }]
183
+ ])
184
+ };
185
+
186
+ const errors = await processor.validateResponse(
187
+ mockController,
188
+ 'testMethod',
189
+ { data: { name: 'test' } }
190
+ );
191
+
192
+ expect(errors).toEqual([]);
193
+ expect(validate).toHaveBeenCalled();
194
+ });
195
+
196
+ test('没有验证注解时应该返回空数组', async () => {
197
+ const mockController = {};
198
+
199
+ const errors = await processor.validateResponse(
200
+ mockController,
201
+ 'testMethod',
202
+ { name: 'test' }
203
+ );
204
+
205
+ expect(errors).toEqual([]);
206
+ });
207
+ });
208
+
209
+ describe('CacheProcessor', () => {
210
+ let processor: CacheProcessor;
211
+
212
+ beforeEach(() => {
213
+ processor = new CacheProcessor();
214
+ });
215
+
216
+ test('应该正确设置名称和优先级', () => {
217
+ expect(processor.name).toBe('Cache');
218
+ expect(processor.priority).toBe(50);
219
+ });
220
+
221
+ test('没有缓存注解时应该返回true', async () => {
222
+ const mockController = {};
223
+
224
+ const result = await processor.process(
225
+ mockContext,
226
+ mockController,
227
+ 'testMethod',
228
+ null,
229
+ []
230
+ );
231
+
232
+ expect(result).toBe(true);
233
+ });
234
+
235
+ test('缓存禁用时应该返回true', async () => {
236
+ const mockController = {
237
+ $_ControllerCache: new Map([
238
+ ['testMethod', {
239
+ cacheyFn: jest.fn(),
240
+ options: { enable: false }
241
+ }]
242
+ ])
243
+ };
244
+
245
+ const result = await processor.process(
246
+ mockContext,
247
+ mockController,
248
+ 'testMethod',
249
+ { cacheyFn: jest.fn(), options: { enable: false } },
250
+ []
251
+ );
252
+
253
+ expect(result).toBe(true);
254
+ });
255
+ });
256
+
257
+ describe('ResponseCodeProcessor', () => {
258
+ let processor: ResponseCodeProcessor;
259
+
260
+ beforeEach(() => {
261
+ processor = new ResponseCodeProcessor();
262
+ });
263
+
264
+ test('应该正确设置名称和优先级', () => {
265
+ expect(processor.name).toBe('ResponseCode');
266
+ expect(processor.priority).toBe(300);
267
+ });
268
+
269
+ test('没有响应码注解时应该返回true', async () => {
270
+ const mockController = {};
271
+
272
+ const result = await processor.process(
273
+ mockContext,
274
+ mockController,
275
+ 'testMethod',
276
+ null,
277
+ []
278
+ );
279
+
280
+ expect(result).toBe(true);
281
+ });
282
+
283
+ test('应该设置响应码', async () => {
284
+ const mockController = {
285
+ $_ResponseCode: new Map([
286
+ ['testMethod', 201]
287
+ ])
288
+ };
289
+
290
+ const result = await processor.process(
291
+ mockContext,
292
+ mockController,
293
+ 'testMethod',
294
+ null,
295
+ []
296
+ );
297
+
298
+ expect(result).toBe(true);
299
+ expect(mockContext.status).toBe(201);
300
+ });
301
+
302
+ test('没有指定响应码时应该使用默认值200', async () => {
303
+ const mockController = {
304
+ $_ResponseCode: new Map([
305
+ ['testMethod', undefined]
306
+ ])
307
+ };
308
+
309
+ const result = await processor.process(
310
+ mockContext,
311
+ mockController,
312
+ 'testMethod',
313
+ null,
314
+ []
315
+ );
316
+
317
+ expect(result).toBe(true);
318
+ expect(mockContext.status).toBe(200);
319
+ });
320
+ });
321
+
322
+ describe('ResponseHeaderProcessor', () => {
323
+ let processor: ResponseHeaderProcessor;
324
+
325
+ beforeEach(() => {
326
+ processor = new ResponseHeaderProcessor();
327
+ });
328
+
329
+ test('应该正确设置名称和优先级', () => {
330
+ expect(processor.name).toBe('ResponseHeader');
331
+ expect(processor.priority).toBe(400);
332
+ });
333
+
334
+ test('没有响应头注解时应该返回true', async () => {
335
+ const mockController = {};
336
+
337
+ const result = await processor.process(
338
+ mockContext,
339
+ mockController,
340
+ 'testMethod',
341
+ null,
342
+ []
343
+ );
344
+
345
+ expect(result).toBe(true);
346
+ });
347
+
348
+ test('应该设置响应头', async () => {
349
+ const mockController = {
350
+ $_ResponseHeader: new Map([
351
+ ['testMethod', new Map([
352
+ ['Content-Type', 'application/json'],
353
+ ['Cache-Control', 'no-cache']
354
+ ])]
355
+ ])
356
+ };
357
+
358
+ const result = await processor.process(
359
+ mockContext,
360
+ mockController,
361
+ 'testMethod',
362
+ null,
363
+ []
364
+ );
365
+
366
+ expect(result).toBe(true);
367
+ expect(mockContext.set).toHaveBeenCalledWith('Content-Type', 'application/json');
368
+ expect(mockContext.set).toHaveBeenCalledWith('Cache-Control', 'no-cache');
369
+ });
370
+ });
371
+ });