Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ jobs:
sh prepare.sh
cd feature
rustup toolchain install nightly
cargo +nightly test -- --format=json -Z unstable-options --report-time > test-report.json

cargo +nightly test -- --nocapture --format=json -Z unstable-options --report-time > test-report.json
- name: json to report md
if: failure()
run: |
Expand Down
114 changes: 112 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,112 @@
# ckb-rust-integration-test
ckb-rust-integration-test
# CKB Rust Integration Test Framework

This repository contains a comprehensive testing framework for the Nervos CKB (Common Knowledge Base) blockchain's Rust SDK.

## Overview

The CKB Rust Integration Test Framework provides automated tests for CKB's RPC interfaces, ensuring that the SDK correctly interacts with CKB nodes. It supports testing both standard CKB RPC and Light Client RPC interfaces.

## Requirements

- Rust (nightly toolchain recommended)
- Cargo
- Git

## Getting Started

### Clone the Repository

```bash
git clone https://github.com/cryptape/ckb-rust-integration-test.git
cd ckb-rust-integration-test
```

### Setup Environment

```bash
sh prepare.sh
```

This script prepares all necessary dependencies and mock data for testing.

### Run Tests

```bash
cd feature
cargo +nightly test -- --nocapture
```

Use the `--nocapture` flag to display output during test execution, which is helpful for debugging.

## Framework Structure

The test framework uses `rstest` to create parameterized tests with mock RPC server responses.

### Directory Structure

- `feature/tests/` - Contains all test code
- `mockrpc/` - Tests for CKB RPC interfaces
- `mock_light_rpc/` - Tests for CKB Light Client RPC interfaces
- `common/` - Shared utilities and helper functions

## Adding New Tests

1. Create a new test file in the appropriate directory
2. Use the `rstest` macro with `mock_rpc_data` to create parameterized tests
3. Add corresponding test data JSON files in the `data` directory

Example:

```rust
use rstest::rstest;
use crate::mockrpc::{mock_rpc_data, MockRpcData};

#[rstest(mock_rpc_data("method_name", "params"))]
fn test_function(mock_rpc_data: MockRpcData) {
let client = mock_rpc_data.client();
// Test implementation
assert_eq!(expected_result, actual_result);
}
```

## Continuous Integration

This project uses GitHub Actions for continuous integration testing. Tests run automatically on pushes to the `main` branch and on pull requests.

### CI Workflow

1. Check out code
2. Set up the test environment
3. Run tests and generate a JSON format test report
4. If tests fail:
- Convert the JSON report to Markdown format
- Upload the report to Qiniu cloud storage
- Provide a download link for the test report

### Test Reports

If tests fail, a detailed report is generated and can be accessed at:
```
https://github-test-logs.ckbapp.dev/ckb-rust-integration-test/test-report.md
```

The test report includes:
- Test summary (total, passed, failed)
- Detailed information about failed tests
- Test name
- Failure reason
- Error stack trace
- Test execution time

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request or create an Issue to improve this testing framework.

Before submitting a PR, please ensure:
1. All tests pass
2. New code has appropriate test coverage
3. Code follows the project's style guidelines

## License

MIT
38 changes: 19 additions & 19 deletions feature/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,39 +17,38 @@ anyhow = "1.0.63"
bech32 = "0.8.1"
derive-getters = "0.2.1"
log = "0.4.6"
reqwest = { version = "0.11", default-features = false, features = [ "json", "blocking" ] }
secp256k1 = { version = "0.29.0", features = ["recovery"] }
reqwest = { version = "0.12", default-features = false, features = ["json", "blocking"] }
secp256k1 = { version = "0.30.0", features = ["recovery"] }
tokio-util = { version = "0.7.7", features = ["codec"] }
tokio = { version = "1" }
bytes = "1"
futures = "0.3"
jsonrpc-core = "18"
parking_lot = "0.12"
lru = "0.7.1"
dashmap = "5.4"
dyn-clone = "1.0"
async-trait = "0.1"

ckb-types = "0.118.0"
ckb-dao-utils = "0.118.0"
ckb-traits = "0.118.0"
ckb-jsonrpc-types = "0.118.0"
ckb-hash = "0.118.0"
ckb-resource = "0.118.0"
ckb-crypto = { version = "=0.118.0", features = ["secp"] }
ckb-script = "0.118.0"
ckb-sdk = "3.4.0"
ckb-types = "0.200.0"
ckb-dao-utils = "0.200.0"
ckb-traits = "0.200.0"
ckb-jsonrpc-types = "0.200.0"
ckb-hash = "0.200.0"
ckb-resource = "0.200.0"
ckb-system-scripts = "0.6.0"
ckb-crypto = { version = "=0.200.0", features = ["secp"] }
ckb-script = "0.200.0"
bitflags = "1.3.2"
sha3 = "0.10.1"
enum-repr-derive = "0.2.0"
hex = "0.4"

# for feature test
rand = { version = "0.7.3", optional = true }
ckb-mock-tx-types = { version = "0.118.0" }
ckb-chain-spec = "0.118.0"
ckb-mock-tx-types = { version = "0.200.0" }
ckb-chain-spec = "0.200.0"

sparse-merkle-tree = "0.6.1"
lazy_static = "1.3.0"
rstest = "0.7.0"

[features]
default = ["default-tls"]
Expand All @@ -59,7 +58,8 @@ rustls-tls = ["reqwest/rustls-tls"]
test = []

[dev-dependencies]
clap = { version = "=4.4.18", features = [ "derive" ] } # TODO clap v4.5 requires rustc v1.74.0+
clap = { version = "4.5", features = ["derive"] }
httpmock = "0.6"
async-global-executor = "2.3.1"
hex = "0.4"
tempfile = "3.19.1"
ckb-sdk = { git = "https://github.com/eval-exec/ckb-sdk-rust", rev = "fa01ccd79871b7a1fddecba8c0ba71064abcbeba" }
rstest = "0.18.2"
136 changes: 136 additions & 0 deletions feature/doc/newMultiSign.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@

# 多签功能测试用例

## 1. 多签基本功能测试用例

### 1.1 多签配置生成

**用例**: 验证 `MultisigConfig::new_with` 生成多签配置的正确性。

**输入**:
- 使用 `MultisigScript::V2`
- 多种 threshold 值(例如 1、2、n)
- `require_first_n` 参数的边界值(如 0 和最大值)
- 不同的参与者公钥哈希列表

**预期结果**:
- 正确生成对应的多签配置
- 验证配置中的 hash160 和生成的地址是否符合预期

### 1.2 多签地址生成

**用例**: 测试 `multisig_config.to_address` 方法。

**场景**:
- 使用不同的网络类型(主网、测试网)
- 验证生成的地址格式是否正确

**预期结果**:
- 地址符合多签规则,且与配置中的参与者和 threshold 一致

### 1.3 多签依赖加载

**用例**: 验证 `MultisigScript::V2.dep_group` 方法。

**场景**:
- 环境变量中设置了 `MULTISIG_V2_DEP_GROUP`
- 未设置环境变量时,加载默认依赖
- 在不同网络(主网、测试网、开发网络)中测试

**预期结果**:
- 能正确加载依赖,返回有效的 (code_hash, index)

### 1.4 多签脚本 ID 测试

**用例**: 测试 `MultisigScript::V2.script_id` 方法。

**场景**:
- 验证 code_hash 和 hash_type 是否符合预期
- 测试 `MultisigScript::Legacy` 的兼容性

**预期结果**:
- 返回正确的脚本 ID

## 2. 转账功能测试用例

### 2.1 简单转账

**用例**: 验证从多签地址向单一接收地址转账。

**场景**:
- 输入单一的多签地址
- 输出容量设置为合法值

**预期结果**:
- 交易生成成功,witness 包含正确的签名

### 2.2 多输出转账

**用例**: 测试从多签地址向多个地址转账。

**场景**:
- 多个输出地址,分别设置不同的容量
- 验证交易是否正确平衡

**预期结果**:
- 输出总容量与输入总容量一致(扣除手续费)
- 每个 output 的锁脚本正确

### 2.3 阈值签名测试

**用例**: 测试不同的 threshold 值对签名的影响。

**场景**:
- 设置 2-of-3 和 3-of-5 的多签配置
- 提供符合和不符合阈值的签名

**预期结果**:
- 符合阈值时解锁成功
- 不符合阈值时解锁失败

### 2.4 无效多签配置

**用例**: 测试无效的多签配置。

**场景**:
- 设置非法的 threshold 和 require_first_n 参数
- 提供与配置不匹配的签名

**预期结果**:
- 多签配置生成失败或解锁失败

## 3. 边界测试

### 3.1 参数边界

**测试 threshold 和 require_first_n 参数的极端值**:
- 最小值:0
- 最大值:参与者总数
- 验证生成的配置和交易是否正常

### 3.2 签名边界

- 验证当签名数量正好等于 threshold 时是否能解锁
- 验证额外提供无效签名时是否会影响解锁

## 4. 性能和兼容性

### 4.1 性能测试

**用例**: 测试在高输入/输出数量情况下的性能。

**场景**:
- 构造包含 100 个输入和 100 个输出的交易

**预期结果**:
- 交易构造时间和解锁时间在合理范围内

### 4.2 兼容性测试

**用例**: 验证 `MultisigScript::V2` 和 Legacy 的兼容性。

**场景**:
- 在同一交易中混合使用 `MultisigScript::V2` 和 Legacy

**预期结果**:
- 能正确解锁并完成交易
3 changes: 3 additions & 0 deletions feature/tests/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod common;
pub mod mockrpc;
pub mod mock_light_rpc;
19 changes: 2 additions & 17 deletions feature/tests/mock_light_rpc/mod.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,3 @@
mod fetch_header;
mod fetch_transaction;
mod get_cells;
mod get_cells_capacity;
mod get_genesis_block;
mod get_header;
mod get_peers;
mod get_scripts;
mod get_tip_header;
mod get_transaction;
mod get_transactions;
mod local_node_info;
mod send_transaction;
mod set_scripts;

use ckb_sdk::rpc::LightClientRpcClient;
// use ckb_sdk::LightClientRpcClient;
use reqwest::blocking::Client;
Expand Down Expand Up @@ -86,8 +71,8 @@ impl MockRpcData {

#[fixture]
pub fn mock_rpc_data(
#[default = "Alice"] name: impl AsRef<str>,
#[default = "params"] params: impl AsRef<str>,
#[default("Alice")] name: impl AsRef<str>,
#[default("params")] params: impl AsRef<str>,
) -> MockRpcData {
return MockRpcData::new(name.as_ref().to_owned(), params.as_ref().to_owned());
}
4 changes: 2 additions & 2 deletions feature/tests/mockrpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ impl MockRpcData {

#[fixture]
pub fn mock_rpc_data(
#[default = "Alice"] name: impl AsRef<str>,
#[default = "params"] params: impl AsRef<str>,
#[default("Alice")] name: impl AsRef<str>,
#[default("params")] params: impl AsRef<str>,
) -> MockRpcData {
return MockRpcData::new(name.as_ref().to_owned(), params.as_ref().to_owned());
}
Loading