@roomkit/worker 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 (158) hide show
  1. package/README.md +122 -0
  2. package/dist/src/admin/admin.controller.d.ts +275 -0
  3. package/dist/src/admin/admin.controller.d.ts.map +1 -0
  4. package/dist/src/admin/admin.controller.js +296 -0
  5. package/dist/src/admin/admin.controller.js.map +1 -0
  6. package/dist/src/admin/admin.module.d.ts +3 -0
  7. package/dist/src/admin/admin.module.d.ts.map +1 -0
  8. package/dist/src/admin/admin.module.js +35 -0
  9. package/dist/src/admin/admin.module.js.map +1 -0
  10. package/dist/src/admin/admin.service.d.ts +282 -0
  11. package/dist/src/admin/admin.service.d.ts.map +1 -0
  12. package/dist/src/admin/admin.service.js +508 -0
  13. package/dist/src/admin/admin.service.js.map +1 -0
  14. package/dist/src/auth/auth.module.d.ts +10 -0
  15. package/dist/src/auth/auth.module.d.ts.map +1 -0
  16. package/dist/src/auth/auth.module.js +37 -0
  17. package/dist/src/auth/auth.module.js.map +1 -0
  18. package/dist/src/auth/auth.service.d.ts +21 -0
  19. package/dist/src/auth/auth.service.d.ts.map +1 -0
  20. package/dist/src/auth/auth.service.js +69 -0
  21. package/dist/src/auth/auth.service.js.map +1 -0
  22. package/dist/src/circuit-breaker/circuit-breaker.module.d.ts +3 -0
  23. package/dist/src/circuit-breaker/circuit-breaker.module.d.ts.map +1 -0
  24. package/dist/src/circuit-breaker/circuit-breaker.module.js +24 -0
  25. package/dist/src/circuit-breaker/circuit-breaker.module.js.map +1 -0
  26. package/dist/src/circuit-breaker/circuit-breaker.service.d.ts +89 -0
  27. package/dist/src/circuit-breaker/circuit-breaker.service.d.ts.map +1 -0
  28. package/dist/src/circuit-breaker/circuit-breaker.service.js +207 -0
  29. package/dist/src/circuit-breaker/circuit-breaker.service.js.map +1 -0
  30. package/dist/src/config/config.module.d.ts +3 -0
  31. package/dist/src/config/config.module.d.ts.map +1 -0
  32. package/dist/src/config/config.module.js +22 -0
  33. package/dist/src/config/config.module.js.map +1 -0
  34. package/dist/src/config/config.service.d.ts +19 -0
  35. package/dist/src/config/config.service.d.ts.map +1 -0
  36. package/dist/src/config/config.service.js +58 -0
  37. package/dist/src/config/config.service.js.map +1 -0
  38. package/dist/src/config/worker.config.d.ts +82 -0
  39. package/dist/src/config/worker.config.d.ts.map +1 -0
  40. package/dist/src/config/worker.config.js +35 -0
  41. package/dist/src/config/worker.config.js.map +1 -0
  42. package/dist/src/index.d.ts +48 -0
  43. package/dist/src/index.d.ts.map +1 -0
  44. package/dist/src/index.js +108 -0
  45. package/dist/src/index.js.map +1 -0
  46. package/dist/src/lifecycle/graceful-shutdown.service.d.ts +71 -0
  47. package/dist/src/lifecycle/graceful-shutdown.service.d.ts.map +1 -0
  48. package/dist/src/lifecycle/graceful-shutdown.service.js +221 -0
  49. package/dist/src/lifecycle/graceful-shutdown.service.js.map +1 -0
  50. package/dist/src/lifecycle/index.d.ts +2 -0
  51. package/dist/src/lifecycle/index.d.ts.map +1 -0
  52. package/dist/src/lifecycle/index.js +18 -0
  53. package/dist/src/lifecycle/index.js.map +1 -0
  54. package/dist/src/main.d.ts +2 -0
  55. package/dist/src/main.d.ts.map +1 -0
  56. package/dist/src/main.js +54 -0
  57. package/dist/src/main.js.map +1 -0
  58. package/dist/src/metrics/metrics.controller.d.ts +15 -0
  59. package/dist/src/metrics/metrics.controller.d.ts.map +1 -0
  60. package/dist/src/metrics/metrics.controller.js +44 -0
  61. package/dist/src/metrics/metrics.controller.js.map +1 -0
  62. package/dist/src/metrics/metrics.module.d.ts +7 -0
  63. package/dist/src/metrics/metrics.module.d.ts.map +1 -0
  64. package/dist/src/metrics/metrics.module.js +28 -0
  65. package/dist/src/metrics/metrics.module.js.map +1 -0
  66. package/dist/src/metrics/metrics.service.d.ts +65 -0
  67. package/dist/src/metrics/metrics.service.d.ts.map +1 -0
  68. package/dist/src/metrics/metrics.service.js +306 -0
  69. package/dist/src/metrics/metrics.service.js.map +1 -0
  70. package/dist/src/migration/migration.module.d.ts +3 -0
  71. package/dist/src/migration/migration.module.d.ts.map +1 -0
  72. package/dist/src/migration/migration.module.js +30 -0
  73. package/dist/src/migration/migration.module.js.map +1 -0
  74. package/dist/src/migration/migration.service.d.ts +68 -0
  75. package/dist/src/migration/migration.service.d.ts.map +1 -0
  76. package/dist/src/migration/migration.service.js +295 -0
  77. package/dist/src/migration/migration.service.js.map +1 -0
  78. package/dist/src/migration/room-migration.service.d.ts +92 -0
  79. package/dist/src/migration/room-migration.service.d.ts.map +1 -0
  80. package/dist/src/migration/room-migration.service.js +297 -0
  81. package/dist/src/migration/room-migration.service.js.map +1 -0
  82. package/dist/src/redis/redis.module.d.ts +3 -0
  83. package/dist/src/redis/redis.module.d.ts.map +1 -0
  84. package/dist/src/redis/redis.module.js +22 -0
  85. package/dist/src/redis/redis.module.js.map +1 -0
  86. package/dist/src/redis/redis.service.d.ts +68 -0
  87. package/dist/src/redis/redis.service.d.ts.map +1 -0
  88. package/dist/src/redis/redis.service.js +260 -0
  89. package/dist/src/redis/redis.service.js.map +1 -0
  90. package/dist/src/room/client-proxy.d.ts +43 -0
  91. package/dist/src/room/client-proxy.d.ts.map +1 -0
  92. package/dist/src/room/client-proxy.js +91 -0
  93. package/dist/src/room/client-proxy.js.map +1 -0
  94. package/dist/src/room/game-room.d.ts +243 -0
  95. package/dist/src/room/game-room.d.ts.map +1 -0
  96. package/dist/src/room/game-room.js +434 -0
  97. package/dist/src/room/game-room.js.map +1 -0
  98. package/dist/src/room/message-handler.service.d.ts +70 -0
  99. package/dist/src/room/message-handler.service.d.ts.map +1 -0
  100. package/dist/src/room/message-handler.service.js +541 -0
  101. package/dist/src/room/message-handler.service.js.map +1 -0
  102. package/dist/src/room/room-manager.service.d.ts +132 -0
  103. package/dist/src/room/room-manager.service.d.ts.map +1 -0
  104. package/dist/src/room/room-manager.service.js +571 -0
  105. package/dist/src/room/room-manager.service.js.map +1 -0
  106. package/dist/src/room/room-persistence.service.d.ts +101 -0
  107. package/dist/src/room/room-persistence.service.d.ts.map +1 -0
  108. package/dist/src/room/room-persistence.service.js +307 -0
  109. package/dist/src/room/room-persistence.service.js.map +1 -0
  110. package/dist/src/room/room-registry.service.d.ts +16 -0
  111. package/dist/src/room/room-registry.service.d.ts.map +1 -0
  112. package/dist/src/room/room-registry.service.js +60 -0
  113. package/dist/src/room/room-registry.service.js.map +1 -0
  114. package/dist/src/room/room.module.d.ts +15 -0
  115. package/dist/src/room/room.module.d.ts.map +1 -0
  116. package/dist/src/room/room.module.js +55 -0
  117. package/dist/src/room/room.module.js.map +1 -0
  118. package/dist/src/room/rooms/echo-room.d.ts +18 -0
  119. package/dist/src/room/rooms/echo-room.d.ts.map +1 -0
  120. package/dist/src/room/rooms/echo-room.js +85 -0
  121. package/dist/src/room/rooms/echo-room.js.map +1 -0
  122. package/dist/src/room/rooms/index.d.ts +2 -0
  123. package/dist/src/room/rooms/index.d.ts.map +1 -0
  124. package/dist/src/room/rooms/index.js +6 -0
  125. package/dist/src/room/rooms/index.js.map +1 -0
  126. package/dist/src/worker.module.d.ts +10 -0
  127. package/dist/src/worker.module.d.ts.map +1 -0
  128. package/dist/src/worker.module.js +46 -0
  129. package/dist/src/worker.module.js.map +1 -0
  130. package/dist/test/circuit-breaker/circuit-breaker.service.spec.d.ts +2 -0
  131. package/dist/test/circuit-breaker/circuit-breaker.service.spec.d.ts.map +1 -0
  132. package/dist/test/circuit-breaker/circuit-breaker.service.spec.js +220 -0
  133. package/dist/test/circuit-breaker/circuit-breaker.service.spec.js.map +1 -0
  134. package/dist/test/integration/admin-api.spec.d.ts +2 -0
  135. package/dist/test/integration/admin-api.spec.d.ts.map +1 -0
  136. package/dist/test/integration/admin-api.spec.js +246 -0
  137. package/dist/test/integration/admin-api.spec.js.map +1 -0
  138. package/dist/test/migration/game-room-migration.spec.d.ts +2 -0
  139. package/dist/test/migration/game-room-migration.spec.d.ts.map +1 -0
  140. package/dist/test/migration/game-room-migration.spec.js +222 -0
  141. package/dist/test/migration/game-room-migration.spec.js.map +1 -0
  142. package/dist/test/room/client-proxy.spec.d.ts +2 -0
  143. package/dist/test/room/client-proxy.spec.d.ts.map +1 -0
  144. package/dist/test/room/client-proxy.spec.js +117 -0
  145. package/dist/test/room/client-proxy.spec.js.map +1 -0
  146. package/dist/test/room/game-room.spec.d.ts +2 -0
  147. package/dist/test/room/game-room.spec.d.ts.map +1 -0
  148. package/dist/test/room/game-room.spec.js +219 -0
  149. package/dist/test/room/game-room.spec.js.map +1 -0
  150. package/dist/test/room/room-manager.service.spec.d.ts +2 -0
  151. package/dist/test/room/room-manager.service.spec.d.ts.map +1 -0
  152. package/dist/test/room/room-manager.service.spec.js +280 -0
  153. package/dist/test/room/room-manager.service.spec.js.map +1 -0
  154. package/dist/test/setup.d.ts +2 -0
  155. package/dist/test/setup.d.ts.map +1 -0
  156. package/dist/test/setup.js +56 -0
  157. package/dist/test/setup.js.map +1 -0
  158. package/package.json +74 -0
@@ -0,0 +1,246 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ /// <reference types="jest" />
7
+ const testing_1 = require("@nestjs/testing");
8
+ const supertest_1 = __importDefault(require("supertest"));
9
+ const admin_controller_1 = require("../../src/admin/admin.controller");
10
+ const admin_service_1 = require("../../src/admin/admin.service");
11
+ const config_service_1 = require("../../src/config/config.service");
12
+ const redis_service_1 = require("../../src/redis/redis.service");
13
+ const room_manager_service_1 = require("../../src/room/room-manager.service");
14
+ const circuit_breaker_service_1 = require("../../src/circuit-breaker/circuit-breaker.service");
15
+ /**
16
+ * Worker Admin API 集成测试
17
+ * 只测试 Admin API 模块,使用 mock 依赖
18
+ */
19
+ describe('Worker Admin API (Integration)', () => {
20
+ let app;
21
+ let adminService;
22
+ const mockConfigService = {
23
+ workerId: 'worker-test-integration',
24
+ redisHost: process.env.REDIS_HOST || 'localhost',
25
+ redisPort: parseInt(process.env.REDIS_PORT || '6379', 10),
26
+ redisPassword: process.env.REDIS_PASSWORD,
27
+ adminPort: 18082,
28
+ heartbeatInterval: 30000,
29
+ maxRooms: 500,
30
+ circuitFailureThreshold: 10,
31
+ circuitSuccessThreshold: 5,
32
+ circuitOpenTimeout: 30000,
33
+ maxPendingRequests: 1000,
34
+ };
35
+ const mockRedisService = {
36
+ client: {
37
+ status: 'ready',
38
+ },
39
+ publish: jest.fn().mockResolvedValue(1),
40
+ get: jest.fn().mockResolvedValue(null),
41
+ set: jest.fn().mockResolvedValue('OK'),
42
+ del: jest.fn().mockResolvedValue(1),
43
+ };
44
+ const mockRoomManagerService = {
45
+ getAllRooms: jest.fn().mockReturnValue(new Map()),
46
+ getRoom: jest.fn().mockReturnValue(null),
47
+ getRoomCount: jest.fn().mockReturnValue(0),
48
+ getTotalPlayerCount: jest.fn().mockReturnValue(0),
49
+ closeRoom: jest.fn().mockResolvedValue(true),
50
+ closeAllRooms: jest.fn().mockResolvedValue({ closed: 0, failed: 0 }),
51
+ canAcceptNewRoom: jest.fn().mockReturnValue(true),
52
+ getRegisteredRoomTypes: jest.fn().mockReturnValue(['test', 'echo']),
53
+ getRegisteredGameTypes: jest.fn().mockReturnValue(['test', 'echo']),
54
+ };
55
+ let circuitBreakerState = 'closed';
56
+ const mockCircuitBreakerService = {
57
+ getState: jest.fn().mockImplementation(() => circuitBreakerState),
58
+ getStats: jest.fn().mockImplementation(() => ({
59
+ state: circuitBreakerState,
60
+ failures: 0,
61
+ successes: 0,
62
+ lastFailure: null,
63
+ lastSuccess: null,
64
+ pendingRequests: 0,
65
+ })),
66
+ isOpen: jest.fn().mockImplementation(() => circuitBreakerState === 'open'),
67
+ isHealthy: jest.fn().mockImplementation(() => circuitBreakerState === 'closed'),
68
+ reset: jest.fn().mockImplementation(() => {
69
+ circuitBreakerState = 'closed';
70
+ }),
71
+ trip: jest.fn().mockImplementation(() => {
72
+ circuitBreakerState = 'open';
73
+ }),
74
+ forceOpen: jest.fn().mockImplementation(() => {
75
+ circuitBreakerState = 'open';
76
+ }),
77
+ forceClose: jest.fn().mockImplementation(() => {
78
+ circuitBreakerState = 'closed';
79
+ }),
80
+ getConfig: jest.fn().mockReturnValue({
81
+ failureThreshold: 10,
82
+ successThreshold: 5,
83
+ openTimeout: 30000,
84
+ maxPendingRequests: 1000,
85
+ }),
86
+ getPendingRequestsCount: jest.fn().mockReturnValue(0),
87
+ };
88
+ beforeAll(async () => {
89
+ const moduleFixture = await testing_1.Test.createTestingModule({
90
+ controllers: [admin_controller_1.AdminController],
91
+ providers: [
92
+ admin_service_1.AdminService,
93
+ { provide: config_service_1.ConfigService, useValue: mockConfigService },
94
+ { provide: redis_service_1.RedisService, useValue: mockRedisService },
95
+ { provide: room_manager_service_1.RoomManagerService, useValue: mockRoomManagerService },
96
+ { provide: circuit_breaker_service_1.CircuitBreakerService, useValue: mockCircuitBreakerService },
97
+ ],
98
+ }).compile();
99
+ app = moduleFixture.createNestApplication();
100
+ adminService = moduleFixture.get(admin_service_1.AdminService);
101
+ await app.init();
102
+ });
103
+ beforeEach(() => {
104
+ // 每个测试前重置熔断器状态
105
+ circuitBreakerState = 'closed';
106
+ jest.clearAllMocks();
107
+ });
108
+ afterAll(async () => {
109
+ await app.close();
110
+ });
111
+ describe('GET /admin/health', () => {
112
+ it('should return health status', async () => {
113
+ const response = await (0, supertest_1.default)(app.getHttpServer())
114
+ .get('/admin/health')
115
+ .expect(200);
116
+ expect(response.body).toHaveProperty('status', 'ok');
117
+ expect(response.body).toHaveProperty('workerId');
118
+ expect(response.body).toHaveProperty('timestamp');
119
+ expect(response.body).toHaveProperty('circuitBreaker');
120
+ });
121
+ });
122
+ describe('GET /admin/status', () => {
123
+ it('should return system status', async () => {
124
+ const response = await (0, supertest_1.default)(app.getHttpServer())
125
+ .get('/admin/status')
126
+ .expect(200);
127
+ expect(response.body).toHaveProperty('workerId');
128
+ expect(response.body).toHaveProperty('uptime');
129
+ expect(response.body).toHaveProperty('draining', false);
130
+ expect(response.body).toHaveProperty('rooms');
131
+ expect(response.body.rooms).toHaveProperty('count');
132
+ expect(response.body).toHaveProperty('circuitBreaker');
133
+ expect(response.body).toHaveProperty('memory');
134
+ });
135
+ });
136
+ describe('GET /admin/rooms', () => {
137
+ it('should return empty rooms list initially', async () => {
138
+ const response = await (0, supertest_1.default)(app.getHttpServer())
139
+ .get('/admin/rooms')
140
+ .expect(200);
141
+ expect(response.body).toHaveProperty('count', 0);
142
+ expect(response.body).toHaveProperty('rooms');
143
+ expect(response.body.rooms).toEqual([]);
144
+ });
145
+ });
146
+ describe('GET /admin/rooms/:id', () => {
147
+ it('should return 404 for non-existent room', async () => {
148
+ await (0, supertest_1.default)(app.getHttpServer())
149
+ .get('/admin/rooms/non-existent-room')
150
+ .expect(404);
151
+ });
152
+ });
153
+ describe('GET /admin/circuit-breaker', () => {
154
+ it('should return circuit breaker status', async () => {
155
+ const response = await (0, supertest_1.default)(app.getHttpServer())
156
+ .get('/admin/circuit-breaker')
157
+ .expect(200);
158
+ expect(response.body).toHaveProperty('state', 'closed');
159
+ expect(response.body).toHaveProperty('failures');
160
+ expect(response.body).toHaveProperty('successes');
161
+ expect(response.body).toHaveProperty('pendingRequests');
162
+ expect(response.body).toHaveProperty('isHealthy', true);
163
+ expect(response.body).toHaveProperty('config');
164
+ });
165
+ });
166
+ describe('POST /admin/circuit-breaker/trip', () => {
167
+ it('should manually trip circuit breaker', async () => {
168
+ const response = await (0, supertest_1.default)(app.getHttpServer())
169
+ .post('/admin/circuit-breaker/trip')
170
+ .send({ reason: 'test trip' })
171
+ .expect(200);
172
+ expect(response.body).toHaveProperty('success', true);
173
+ expect(response.body).toHaveProperty('state', 'open');
174
+ });
175
+ });
176
+ describe('POST /admin/circuit-breaker/reset', () => {
177
+ it('should reset circuit breaker', async () => {
178
+ // First trip it
179
+ await (0, supertest_1.default)(app.getHttpServer())
180
+ .post('/admin/circuit-breaker/trip')
181
+ .send({ reason: 'test' });
182
+ // Then reset
183
+ const response = await (0, supertest_1.default)(app.getHttpServer())
184
+ .post('/admin/circuit-breaker/reset')
185
+ .expect(200);
186
+ expect(response.body).toHaveProperty('success', true);
187
+ expect(response.body).toHaveProperty('state', 'closed');
188
+ });
189
+ });
190
+ describe('GET /admin/redis/status', () => {
191
+ it('should return Redis status', async () => {
192
+ const response = await (0, supertest_1.default)(app.getHttpServer())
193
+ .get('/admin/redis/status')
194
+ .expect(200);
195
+ expect(response.body).toHaveProperty('status');
196
+ expect(response.body).toHaveProperty('host');
197
+ expect(response.body).toHaveProperty('port');
198
+ });
199
+ });
200
+ describe('GET /admin/game-types', () => {
201
+ it('should return registered game types', async () => {
202
+ const response = await (0, supertest_1.default)(app.getHttpServer())
203
+ .get('/admin/game-types')
204
+ .expect(200);
205
+ expect(response.body).toHaveProperty('count');
206
+ expect(response.body).toHaveProperty('gameTypes');
207
+ expect(response.body.gameTypes).toContain('test');
208
+ expect(response.body.gameTypes).toContain('echo');
209
+ });
210
+ });
211
+ describe('GET /admin/metrics', () => {
212
+ it('should return metrics data', async () => {
213
+ const response = await (0, supertest_1.default)(app.getHttpServer())
214
+ .get('/admin/metrics')
215
+ .expect(200);
216
+ expect(response.body).toHaveProperty('timestamp');
217
+ expect(response.body).toHaveProperty('worker');
218
+ expect(response.body).toHaveProperty('rooms');
219
+ expect(response.body).toHaveProperty('circuitBreaker');
220
+ expect(response.body).toHaveProperty('memory');
221
+ });
222
+ });
223
+ describe('POST /admin/drain', () => {
224
+ it('should set worker to draining mode', async () => {
225
+ const response = await (0, supertest_1.default)(app.getHttpServer())
226
+ .post('/admin/drain')
227
+ .expect(200);
228
+ expect(response.body).toHaveProperty('success', true);
229
+ expect(response.body).toHaveProperty('status', 'draining');
230
+ });
231
+ });
232
+ describe('POST /admin/resume', () => {
233
+ it('should resume worker from draining mode', async () => {
234
+ // First drain
235
+ await (0, supertest_1.default)(app.getHttpServer())
236
+ .post('/admin/drain');
237
+ // Then resume
238
+ const response = await (0, supertest_1.default)(app.getHttpServer())
239
+ .post('/admin/resume')
240
+ .expect(200);
241
+ expect(response.body).toHaveProperty('success', true);
242
+ expect(response.body).toHaveProperty('status', 'ok');
243
+ });
244
+ });
245
+ });
246
+ //# sourceMappingURL=admin-api.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-api.spec.js","sourceRoot":"","sources":["../../../test/integration/admin-api.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=game-room-migration.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"game-room-migration.spec.d.ts","sourceRoot":"","sources":["../../../test/migration/game-room-migration.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,222 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /// <reference types="jest" />
4
+ const game_room_1 = require("../../src/room/game-room");
5
+ const client_proxy_1 = require("../../src/room/client-proxy");
6
+ /**
7
+ * 测试用房间实现 - 带有可序列化的游戏状态
8
+ */
9
+ class TestRoom extends game_room_1.GameRoom {
10
+ gameState = {
11
+ round: 0,
12
+ scores: {},
13
+ customData: '',
14
+ };
15
+ async onCreate(options) {
16
+ if (options.initialRound) {
17
+ this.gameState.round = options.initialRound;
18
+ }
19
+ if (options.customData) {
20
+ this.gameState.customData = options.customData;
21
+ }
22
+ }
23
+ async onJoin(client, options) {
24
+ this.gameState.scores[client.userId] = 0;
25
+ }
26
+ async onLeave(client, reason) {
27
+ delete this.gameState.scores[client.userId];
28
+ }
29
+ async onMessage(client, msgType, payload) {
30
+ // 简单的消息处理
31
+ if (msgType === 'add:score') {
32
+ // 增加分数
33
+ this.gameState.scores[client.userId] = (this.gameState.scores[client.userId] || 0) + 1;
34
+ }
35
+ }
36
+ async onDispose() {
37
+ this.gameState = { round: 0, scores: {}, customData: '' };
38
+ }
39
+ // 覆盖获取游戏状态
40
+ getGameState() {
41
+ return { ...this.gameState };
42
+ }
43
+ // 覆盖恢复游戏状态
44
+ restoreGameState(state) {
45
+ const gameState = state;
46
+ if (gameState) {
47
+ this.gameState = { ...gameState };
48
+ }
49
+ }
50
+ // 测试辅助方法
51
+ getTestGameState() {
52
+ return this.gameState;
53
+ }
54
+ setRound(round) {
55
+ this.gameState.round = round;
56
+ }
57
+ setScore(userId, score) {
58
+ this.gameState.scores[userId] = score;
59
+ }
60
+ }
61
+ describe('GameRoom Migration', () => {
62
+ let room;
63
+ const workerId = 'worker-test-1';
64
+ beforeEach(() => {
65
+ room = new TestRoom('room-1', 'test-game', 4, { customSetting: true });
66
+ room.status = 'active';
67
+ });
68
+ describe('createSnapshot', () => {
69
+ it('should create a snapshot with basic room info', () => {
70
+ const snapshot = room.createSnapshot(workerId);
71
+ expect(snapshot.roomId).toBe('room-1');
72
+ expect(snapshot.gameType).toBe('test-game');
73
+ expect(snapshot.maxPlayers).toBe(4);
74
+ expect(snapshot.config).toEqual({ customSetting: true });
75
+ expect(snapshot.status).toBe('active');
76
+ expect(snapshot.sourceWorkerId).toBe(workerId);
77
+ expect(snapshot.snapshotVersion).toBe(1);
78
+ expect(snapshot.snapshotTime).toBeDefined();
79
+ });
80
+ it('should include game state in snapshot', () => {
81
+ room.setRound(5);
82
+ room.setScore('user-1', 100);
83
+ room.setScore('user-2', 75);
84
+ const snapshot = room.createSnapshot(workerId);
85
+ const gameState = snapshot.gameState;
86
+ expect(gameState.round).toBe(5);
87
+ expect(gameState.scores['user-1']).toBe(100);
88
+ expect(gameState.scores['user-2']).toBe(75);
89
+ });
90
+ it('should include player information', () => {
91
+ // 创建 mock ClientProxy
92
+ const mockRedisService = {
93
+ publish: jest.fn(),
94
+ };
95
+ // 构造函数参数顺序: userId, connectionId, gatewayId, redisService, workerId
96
+ const mockClient1 = new client_proxy_1.ClientProxy('user-1', 'conn-1', 'gateway-1', mockRedisService, workerId);
97
+ const mockClient2 = new client_proxy_1.ClientProxy('user-2', 'conn-2', 'gateway-1', mockRedisService, workerId);
98
+ const playerInfo1 = { userId: 'user-1', nickname: 'Player 1', joinedAt: Date.now() };
99
+ const playerInfo2 = { userId: 'user-2', nickname: 'Player 2', joinedAt: Date.now() };
100
+ room.addPlayer(mockClient1, playerInfo1);
101
+ room.addPlayer(mockClient2, playerInfo2);
102
+ const snapshot = room.createSnapshot(workerId);
103
+ expect(snapshot.players).toHaveLength(2);
104
+ expect(snapshot.players[0].userId).toBe('user-1');
105
+ expect(snapshot.players[0].gatewayId).toBe('gateway-1');
106
+ expect(snapshot.players[0].connectionId).toBe('conn-1');
107
+ expect(snapshot.players[0].playerInfo.nickname).toBe('Player 1');
108
+ });
109
+ });
110
+ describe('restoreFromSnapshot', () => {
111
+ it('should restore basic room state from snapshot', () => {
112
+ const snapshot = {
113
+ roomId: 'room-1',
114
+ gameType: 'test-game',
115
+ maxPlayers: 4,
116
+ config: {},
117
+ status: 'active',
118
+ createdAt: Date.now() - 60000,
119
+ players: [],
120
+ gameState: { round: 10, scores: {}, customData: 'test-data' },
121
+ snapshotVersion: 1,
122
+ snapshotTime: Date.now(),
123
+ sourceWorkerId: 'old-worker',
124
+ };
125
+ room.restoreFromSnapshot(snapshot);
126
+ expect(room.status).toBe('active');
127
+ expect(room.sourceWorkerId).toBe('old-worker');
128
+ });
129
+ it('should restore game state from snapshot', () => {
130
+ const gameState = {
131
+ round: 15,
132
+ scores: { 'user-1': 200, 'user-2': 150 },
133
+ customData: 'restored-data',
134
+ };
135
+ const snapshot = {
136
+ roomId: 'room-1',
137
+ gameType: 'test-game',
138
+ maxPlayers: 4,
139
+ config: {},
140
+ status: 'active',
141
+ createdAt: Date.now(),
142
+ players: [],
143
+ gameState,
144
+ snapshotVersion: 1,
145
+ snapshotTime: Date.now(),
146
+ sourceWorkerId: 'old-worker',
147
+ };
148
+ room.restoreFromSnapshot(snapshot);
149
+ const restoredState = room.getTestGameState();
150
+ expect(restoredState.round).toBe(15);
151
+ expect(restoredState.scores['user-1']).toBe(200);
152
+ expect(restoredState.scores['user-2']).toBe(150);
153
+ expect(restoredState.customData).toBe('restored-data');
154
+ });
155
+ it('should restore player infos from snapshot', () => {
156
+ const snapshot = {
157
+ roomId: 'room-1',
158
+ gameType: 'test-game',
159
+ maxPlayers: 4,
160
+ config: {},
161
+ status: 'active',
162
+ createdAt: Date.now(),
163
+ players: [
164
+ {
165
+ userId: 'user-1',
166
+ gatewayId: 'gateway-1',
167
+ connectionId: 'conn-1',
168
+ playerInfo: { userId: 'user-1', nickname: 'Test Player', joinedAt: Date.now() },
169
+ },
170
+ ],
171
+ gameState: null,
172
+ snapshotVersion: 1,
173
+ snapshotTime: Date.now(),
174
+ sourceWorkerId: 'old-worker',
175
+ };
176
+ room.restoreFromSnapshot(snapshot);
177
+ // playerInfos 应该被恢复
178
+ const playerInfo = room.playerInfos.get('user-1');
179
+ expect(playerInfo).toBeDefined();
180
+ expect(playerInfo?.nickname).toBe('Test Player');
181
+ });
182
+ });
183
+ describe('migration lifecycle', () => {
184
+ it('should set isMigrating flag on migration start', async () => {
185
+ expect(room.isMigrating).toBe(false);
186
+ await room.onMigrationStart();
187
+ expect(room.isMigrating).toBe(true);
188
+ });
189
+ it('should clear isMigrating flag on migration complete', async () => {
190
+ room.isMigrating = true;
191
+ await room.onMigrationComplete();
192
+ expect(room.isMigrating).toBe(false);
193
+ });
194
+ it('should clear isMigrating flag on migration failed', async () => {
195
+ room.isMigrating = true;
196
+ await room.onMigrationFailed('test error');
197
+ expect(room.isMigrating).toBe(false);
198
+ });
199
+ });
200
+ describe('snapshot round-trip', () => {
201
+ it('should preserve all state through snapshot and restore', () => {
202
+ // 设置初始状态
203
+ room.status = 'active';
204
+ room.setRound(25);
205
+ room.setScore('player-a', 500);
206
+ room.setScore('player-b', 350);
207
+ // 创建快照
208
+ const snapshot = room.createSnapshot(workerId);
209
+ // 创建新房间并恢复
210
+ const newRoom = new TestRoom('room-1', 'test-game', 4, {});
211
+ newRoom.restoreFromSnapshot(snapshot);
212
+ // 验证状态
213
+ expect(newRoom.status).toBe('active');
214
+ expect(newRoom.sourceWorkerId).toBe(workerId);
215
+ const restoredState = newRoom.getTestGameState();
216
+ expect(restoredState.round).toBe(25);
217
+ expect(restoredState.scores['player-a']).toBe(500);
218
+ expect(restoredState.scores['player-b']).toBe(350);
219
+ });
220
+ });
221
+ });
222
+ //# sourceMappingURL=game-room-migration.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"game-room-migration.spec.js","sourceRoot":"","sources":["../../../test/migration/game-room-migration.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=client-proxy.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-proxy.spec.d.ts","sourceRoot":"","sources":["../../../test/room/client-proxy.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /// <reference types="jest" />
4
+ const client_proxy_1 = require("../../src/room/client-proxy");
5
+ const core_1 = require("@roomkit/core");
6
+ describe('ClientProxy', () => {
7
+ let clientProxy;
8
+ let mockRedisService;
9
+ const userId = 'user-123';
10
+ const connectionId = 'conn-456';
11
+ const gatewayId = 'gateway-001';
12
+ const workerId = 'worker-001';
13
+ const roomId = 'room-789';
14
+ beforeEach(() => {
15
+ mockRedisService = {
16
+ publish: jest.fn().mockResolvedValue(undefined),
17
+ };
18
+ clientProxy = new client_proxy_1.ClientProxy(userId, connectionId, gatewayId, mockRedisService, workerId, roomId);
19
+ });
20
+ afterEach(() => {
21
+ jest.clearAllMocks();
22
+ });
23
+ describe('constructor', () => {
24
+ it('should initialize with correct properties', () => {
25
+ expect(clientProxy.userId).toBe(userId);
26
+ expect(clientProxy.connectionId).toBe(connectionId);
27
+ expect(clientProxy.gatewayId).toBe(gatewayId);
28
+ expect(clientProxy.workerId).toBe(workerId);
29
+ expect(clientProxy.roomId).toBe(roomId);
30
+ });
31
+ it('should allow undefined roomId', () => {
32
+ const proxy = new client_proxy_1.ClientProxy(userId, connectionId, gatewayId, mockRedisService, workerId);
33
+ expect(proxy.roomId).toBeUndefined();
34
+ });
35
+ });
36
+ describe('send', () => {
37
+ it('should publish message to gateway channel', async () => {
38
+ const msgId = 1001;
39
+ const payload = { data: 'test' };
40
+ await clientProxy.send(msgId, payload);
41
+ expect(mockRedisService.publish).toHaveBeenCalledWith(core_1.RedisChannels.rpcGateway(gatewayId), expect.objectContaining({
42
+ type: 'client-response',
43
+ workerId,
44
+ connectionId,
45
+ msgId,
46
+ payload,
47
+ timestamp: expect.any(Number),
48
+ }));
49
+ });
50
+ it('should include correct timestamp', async () => {
51
+ const before = Date.now();
52
+ await clientProxy.send(1001, {});
53
+ const after = Date.now();
54
+ const publishedMessage = mockRedisService.publish.mock.calls[0][1];
55
+ expect(publishedMessage.timestamp).toBeGreaterThanOrEqual(before);
56
+ expect(publishedMessage.timestamp).toBeLessThanOrEqual(after);
57
+ });
58
+ });
59
+ describe('sendSuccess', () => {
60
+ it('should send success response with data', async () => {
61
+ await clientProxy.sendSuccess(1002, { roomId: 'room-1' });
62
+ expect(mockRedisService.publish).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({
63
+ payload: { success: true, roomId: 'room-1' },
64
+ }));
65
+ });
66
+ it('should send success response without additional data', async () => {
67
+ await clientProxy.sendSuccess(1002);
68
+ expect(mockRedisService.publish).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({
69
+ payload: { success: true },
70
+ }));
71
+ });
72
+ });
73
+ describe('sendError', () => {
74
+ it('should send error response', async () => {
75
+ await clientProxy.sendError(1002, 'ROOM_NOT_FOUND');
76
+ expect(mockRedisService.publish).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({
77
+ payload: { success: false, error: 'ROOM_NOT_FOUND' },
78
+ }));
79
+ });
80
+ });
81
+ describe('broadcast', () => {
82
+ it('should publish to broadcast channel with excludeSelf=true', async () => {
83
+ await clientProxy.broadcast('game:action', { message: 'hello' });
84
+ expect(mockRedisService.publish).toHaveBeenCalledWith(core_1.RedisChannels.broadcast(), expect.objectContaining({
85
+ type: 'room-broadcast',
86
+ workerId,
87
+ roomId,
88
+ excludeUserId: userId,
89
+ msgType: 'game:action',
90
+ payload: { message: 'hello' },
91
+ }));
92
+ });
93
+ it('should publish without excludeUserId when excludeSelf=false', async () => {
94
+ await clientProxy.broadcast('game:action', { message: 'hello' }, false);
95
+ expect(mockRedisService.publish).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({
96
+ excludeUserId: undefined,
97
+ }));
98
+ });
99
+ it('should not broadcast when roomId is undefined', async () => {
100
+ const warnSpy = jest.spyOn(console, 'warn').mockImplementation();
101
+ const proxyWithoutRoom = new client_proxy_1.ClientProxy(userId, connectionId, gatewayId, mockRedisService, workerId);
102
+ await proxyWithoutRoom.broadcast('game:action', { message: 'hello' });
103
+ expect(mockRedisService.publish).not.toHaveBeenCalled();
104
+ expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('Cannot broadcast'));
105
+ warnSpy.mockRestore();
106
+ });
107
+ });
108
+ describe('broadcastAll', () => {
109
+ it('should broadcast to all players including self', async () => {
110
+ await clientProxy.broadcastAll('game:action', { message: 'hello' });
111
+ expect(mockRedisService.publish).toHaveBeenCalledWith(expect.any(String), expect.objectContaining({
112
+ excludeUserId: undefined,
113
+ }));
114
+ });
115
+ });
116
+ });
117
+ //# sourceMappingURL=client-proxy.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client-proxy.spec.js","sourceRoot":"","sources":["../../../test/room/client-proxy.spec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=game-room.spec.d.ts.map