Skip to content

Commit af354d0

Browse files
authored
refactor: 优化 js 端状态管理, 重构项目为 ts,优化单测, build.sh 新增快速构建 (#1)
* refactor: 项目重构为 ts, 优化 js 侧状态管理,新增队列对实例状态更新进行处理, 优化 build 脚本 * fix: build.sh 支持 macos * fix: 单测优化 * cd: Bump version from 1.0.5 to 1.1.0 * feat: 单测重构为ts, 使用 vitest, 解决队列中的竞态问题 * fix: filename typo
1 parent 8a45bbf commit af354d0

34 files changed

Lines changed: 2093 additions & 1358 deletions

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,3 +216,8 @@ coverage.*.html
216216
*.gcda
217217
*.gcno
218218
*.gcov
219+
220+
### TypeScript ###
221+
dist/
222+
*.tsbuildinfo
223+
*.test.js.map

CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ else()
3636
set(ROCKETMQ_LIB ${CMAKE_CURRENT_SOURCE_DIR}/deps/rocketmq/bin/librocketmq.a)
3737
endif()
3838

39-
file(GLOB SOURCE_FILES "src/*.cpp")
39+
file(GLOB SOURCE_FILES "lib/*.cpp")
4040
add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES})
4141
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "" SUFFIX ".node")
4242
set_target_properties(${PROJECT_NAME}
@@ -46,8 +46,8 @@ set_target_properties(${PROJECT_NAME}
4646
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/build")
4747
target_link_libraries(${PROJECT_NAME} ${ROCKETMQ_LIB})
4848

49-
set(CMAKE_DEPENDS_USE_COMPILER FALSE)
50-
set(CMAKE_SKIP_DEPENDENCY_TRACKING TRUE)
49+
# Keep CMake dependency tracking enabled to avoid missing compiler_depend.ts with newer CMake
50+
# versions when using Makefile generators.
5151

5252
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
5353
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++11")

TESTING.md

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
# 测试指南
2+
3+
本项目现在使用 **Vitest** 作为测试框架,并完全支持 **TypeScript**
4+
5+
## 🎯 测试设置
6+
7+
### 测试框架
8+
- **Vitest**: 现代、快速的测试框架
9+
- **TypeScript**: 所有测试文件使用 `.ts` 扩展名
10+
- **原生绑定支持**: 完全兼容 C++ 原生模块
11+
12+
### 文件结构
13+
```
14+
test/
15+
├── consumer.test.ts # Consumer 功能测试
16+
├── consumer_ack.test.ts # Consumer ACK 测试
17+
├── producer.test.ts # Producer 功能测试
18+
├── rocketmq_init.test.ts # 初始化测试
19+
└── helpers/
20+
└── binding.ts # 测试辅助工具
21+
```
22+
23+
## 🚀 运行测试
24+
25+
### 基本命令
26+
27+
```bash
28+
# 完整测试(推荐)- 编译原生模块 + TypeScript + 运行测试
29+
npm test
30+
31+
# 快速测试 - 只编译 TypeScript + 运行测试(需要原生模块已编译)
32+
npm run test:dryrun
33+
34+
# 开发模式测试 - 带内存优化
35+
npm run test:dev
36+
37+
# 覆盖率测试
38+
npm run test:coverage
39+
40+
# 监视模式 - 文件变化时自动重新运行
41+
npm run test:watch
42+
```
43+
44+
### 单独运行 Vitest
45+
46+
```bash
47+
# 直接运行 Vitest
48+
npm run vitest
49+
50+
# 带覆盖率
51+
npm run vitest:coverage
52+
```
53+
54+
## 📝 编写测试
55+
56+
### TypeScript 测试示例
57+
58+
```typescript
59+
import { describe, test, expect } from 'vitest';
60+
import { RocketMQProducer } from '../dist/producer';
61+
62+
describe('Producer tests', () => {
63+
test('should create producer instance', () => {
64+
const producer = new RocketMQProducer('test-group');
65+
expect(producer).toBeTruthy();
66+
expect(producer.status).toBe(0);
67+
});
68+
69+
test('should handle async operations', async () => {
70+
const producer = new RocketMQProducer('test-group');
71+
await producer.start();
72+
expect(producer.status).toBe(1);
73+
await producer.shutdown();
74+
});
75+
});
76+
```
77+
78+
### 重要注意事项
79+
80+
1. **导入路径**: 测试文件从 `../dist/` 导入编译后的代码,以确保原生绑定兼容性
81+
2. **类型安全**: 所有测试代码都有完整的 TypeScript 类型检查
82+
3. **异步测试**: 使用 `async/await` 处理异步操作
83+
4. **环境变量**: 测试会自动设置必要的环境变量
84+
85+
## 🔧 配置
86+
87+
### Vitest 配置 (`vitest.config.mjs`)
88+
89+
- **环境**: Node.js 环境,适合原生绑定
90+
- **TypeScript**: 通过 esbuild 自动编译
91+
- **超时**: 原生操作设置 30 秒超时
92+
- **并发**: 限制为单进程以避免原生绑定冲突
93+
- **覆盖率**: 使用 v8 提供商,包含源码覆盖率
94+
95+
### 覆盖率阈值
96+
97+
- 行覆盖率: 80%
98+
- 函数覆盖率: 80%
99+
- 分支覆盖率: 70%
100+
- 语句覆盖率: 80%
101+
102+
## 🐛 调试
103+
104+
### 常见问题
105+
106+
1. **原生绑定加载失败**
107+
```bash
108+
# 确保原生模块已编译
109+
npm run build:native:test
110+
```
111+
112+
2. **TypeScript 编译错误**
113+
```bash
114+
# 清理并重新编译
115+
npm run clean:ts
116+
npm run build:ts
117+
```
118+
119+
3. **测试超时**
120+
- 原生操作测试超时设置为 30 秒
121+
- 如需调整,修改 `vitest.config.mjs` 中的 `testTimeout`
122+
123+
### 调试模式
124+
125+
```bash
126+
# 使用 Node.js 调试器
127+
node --inspect-brk node_modules/.bin/vitest run
128+
129+
# 详细输出
130+
npm run vitest -- --reporter=verbose
131+
```
132+
133+
## 📊 测试覆盖率
134+
135+
生成详细的覆盖率报告:
136+
137+
```bash
138+
npm run test:coverage
139+
```
140+
141+
报告将生成在 `coverage/` 目录中,包括:
142+
- HTML 报告: `coverage/index.html`
143+
- JSON 数据: `coverage/coverage-final.json`
144+
- 文本摘要: 控制台输出

build.sh

Lines changed: 84 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,70 @@ build_all_linux() {
163163
build_linux_emulated
164164
}
165165

166+
# 本地直接构建当前架构(不依赖 act/docker),用于快速调试
167+
build_local_host() {
168+
info "=== 本地快速构建当前架构(无容器) ==="
169+
local log_file="$LOG_DIR/local-${HOST_OS}-${HOST_ARCH}.log"
170+
local artifact_name=""
171+
172+
if [[ "$HOST_OS" == "linux" ]]; then
173+
if [[ "$HOST_ARCH" == "amd64" ]]; then
174+
artifact_name="linux-x86_64-gnu-rocketmq.node"
175+
elif [[ "$HOST_ARCH" == "arm64" ]]; then
176+
artifact_name="linux-aarch64-gnu-rocketmq.node"
177+
else
178+
error "当前 Linux 架构不支持快速构建: $HOST_ARCH"
179+
return 1
180+
fi
181+
182+
(
183+
rm -rf build/
184+
npm install --no-audit --prefer-offline
185+
./deps/rocketmq/build.sh
186+
npx cmake-js compile --CDCMAKE_BUILD_TYPE=Release
187+
strip -s build/rocketmq.node 2>/dev/null || true
188+
cp build/rocketmq.node "$RELEASE_DIR/$artifact_name"
189+
) 2>&1 | tee "$log_file"
190+
191+
elif [[ "$HOST_OS" == "macos" ]]; then
192+
local osx_arch=""
193+
if [[ "$HOST_ARCH" == "amd64" ]]; then
194+
osx_arch="x86_64"
195+
artifact_name="darwin-x86_64-rocketmq.node"
196+
elif [[ "$HOST_ARCH" == "arm64" ]]; then
197+
osx_arch="arm64"
198+
artifact_name="darwin-arm64-rocketmq.node"
199+
else
200+
error "当前 macOS 架构不支持快速构建: $HOST_ARCH"
201+
return 1
202+
fi
203+
204+
(
205+
rm -rf build/
206+
npm install --no-audit --prefer-offline
207+
./deps/rocketmq/build.sh
208+
npx cmake-js compile --CDCMAKE_BUILD_TYPE=Release \
209+
--CDCMAKE_OSX_ARCHITECTURES="$osx_arch" \
210+
--CDCMAKE_OSX_DEPLOYMENT_TARGET=11 \
211+
--CDCMAKE_SKIP_DEPENDENCY_TRACKING=ON
212+
strip -S -x build/rocketmq.node 2>/dev/null || true
213+
cp build/rocketmq.node "$RELEASE_DIR/$artifact_name"
214+
) 2>&1 | tee "$log_file"
215+
216+
else
217+
error "快速构建仅支持 macOS 或 Linux 主机"
218+
return 1
219+
fi
220+
221+
if [[ -f "$RELEASE_DIR/$artifact_name" ]]; then
222+
success "本地快速构建完成: $artifact_name"
223+
return 0
224+
fi
225+
226+
error "本地快速构建失败,查看日志: $log_file"
227+
return 1
228+
}
229+
166230
# =============================================================================
167231
# 主逻辑
168232
# =============================================================================
@@ -172,24 +236,26 @@ show_help() {
172236
用法: $0 [选项]
173237
174238
选项:
175-
all 构建所有平台 (默认)
176-
linux 构建所有 Linux 目标
177-
linux-native 仅构建当前架构的 Linux 目标 (快)
178-
linux-cross 仅构建交叉架构的 Linux 目标 (慢)
179-
macos 构建 macOS Universal
239+
all 构建所有平台 (默认)
240+
linux 构建所有 Linux 目标
241+
linux-native 仅构建当前架构的 Linux 目标 (快)
242+
linux-cross 仅构建交叉架构的 Linux 目标 (慢)
243+
macos 构建 macOS Universal
244+
local 本地快速构建当前主机架构(macOS/Linux,无 act/docker)
180245
181-
linux-gnu-x64 单独构建 linux-gnu-x64
182-
linux-gnu-arm64 单独构建 linux-gnu-arm64
183-
linux-musl-x64 单独构建 linux-musl-x64
184-
linux-musl-arm64 单独构建 linux-musl-arm64
246+
linux-gnu-x64 单独构建 linux-gnu-x64
247+
linux-gnu-arm64 单独构建 linux-gnu-arm64
248+
linux-musl-x64 单独构建 linux-musl-x64
249+
linux-musl-arm64 单独构建 linux-musl-arm64
185250
186-
-h, --help 显示帮助信息
251+
-h, --help 显示帮助信息
187252
188253
示例:
189-
$0 # 构建所有
190-
$0 linux-native # 仅构建当前架构
191-
$0 linux-gnu-x64 # 仅构建指定目标
192-
$0 macos # 仅构建 macOS
254+
$0 # 构建所有
255+
$0 linux-native # 仅构建当前架构
256+
$0 linux-gnu-x64 # 仅构建指定目标
257+
$0 macos # 仅构建 macOS
258+
$0 local # 本地快速构建当前架构
193259
EOF
194260
}
195261

@@ -220,6 +286,10 @@ main() {
220286
info "=== 构建交叉架构 Linux 目标 ==="
221287
build_linux_emulated
222288
;;
289+
local)
290+
info "=== 本地快速构建(当前主机架构) ==="
291+
build_local_host
292+
;;
223293
macos)
224294
if [[ "$HOST_OS" != "macos" ]]; then
225295
error "macOS 构建只能在 macOS 上运行"

example/status_behavior.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
const { RocketMQProducer } = require('../src/producer');
2+
const { Status } = require('../src/constants');
3+
4+
async function demonstrateStatusBehavior() {
5+
const producer = new RocketMQProducer('demo-group');
6+
7+
console.log('=== 新的状态行为演示 ===');
8+
console.log('初始状态:', getStatusName(producer.status)); // STOPPED
9+
10+
console.log('\n1. 调用 start() 后状态不会立即改变');
11+
const startPromise = producer.start();
12+
console.log('调用 start() 后立即检查状态:', getStatusName(producer.status)); // 可能还是 STOPPED
13+
14+
await startPromise;
15+
console.log('start() 完成后状态:', getStatusName(producer.status)); // STARTED
16+
17+
console.log('\n2. 并发调用会被正确处理');
18+
const promise1 = producer.start(); // 应该失败
19+
const promise2 = producer.start(); // 应该失败
20+
21+
try {
22+
await promise1;
23+
console.log('第一个 start() 调用成功');
24+
} catch (err) {
25+
console.log('第一个 start() 调用失败:', err.message);
26+
}
27+
28+
try {
29+
await promise2;
30+
console.log('第二个 start() 调用成功');
31+
} catch (err) {
32+
console.log('第二个 start() 调用失败:', err.message);
33+
}
34+
35+
console.log('\n3. 清理');
36+
await producer.shutdown();
37+
console.log('最终状态:', getStatusName(producer.status)); // STOPPED
38+
}
39+
40+
function getStatusName(status) {
41+
switch (status) {
42+
case Status.STOPPED: return 'STOPPED';
43+
case Status.STARTED: return 'STARTED';
44+
case Status.STARTING: return 'STARTING';
45+
case Status.STOPPING: return 'STOPPING';
46+
default: return 'UNKNOWN';
47+
}
48+
}
49+
50+
demonstrateStatusBehavior().catch(console.error);
File renamed without changes.

0 commit comments

Comments
 (0)