Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:28:15 +08:00
commit a0fa7fe95b
15 changed files with 6001 additions and 0 deletions

429
commands/tokio-migrate.md Normal file
View File

@@ -0,0 +1,429 @@
---
name: tokio-migrate
description: Migrate synchronous code to async Tokio or upgrade between Tokio versions
---
# Tokio Migrate Command
This command assists with migrating synchronous code to async Tokio, upgrading between Tokio versions, or converting from other async runtimes.
## Arguments
- `$1` - Migration type: `sync-to-async`, `tokio-upgrade`, `runtime-switch` (required)
- `$2` - Target file or directory (optional, defaults to current directory)
- `$3` - Additional context: Tokio version for upgrades, or source runtime for switches (optional)
## Usage
```
/rust-tokio-expert:tokio-migrate sync-to-async src/handlers/
/rust-tokio-expert:tokio-migrate tokio-upgrade src/ 1.0
/rust-tokio-expert:tokio-migrate runtime-switch src/ async-std
```
## Workflow
### 1. Sync to Async Migration
When migrating synchronous code to async Tokio:
#### Analysis Phase
1. **Scan Target Files**
- Use Glob to find all Rust files in target
- Read files and identify synchronous operations
- Detect blocking I/O operations
- Find CPU-intensive operations
- Identify thread spawning
2. **Identify Conversion Candidates**
- Functions with I/O operations (network, file, database)
- Functions that spawn threads
- Functions with sleep/delays
- Functions with synchronous HTTP clients
- Functions with blocking mutex operations
3. **Analyze Dependencies**
- Check `Cargo.toml` for sync crates
- Identify replacements (e.g., `reqwest` blocking → async)
- Find database drivers needing async versions
#### Migration Phase
4. **Invoke Agent**
- Use Task tool with `subagent_type="rust-tokio-expert:tokio-pro"`
- Provide code context and migration plan
5. **Convert Functions to Async**
The agent should transform:
**Synchronous Function:**
```rust
use std::fs::File;
use std::io::Read;
fn read_config(path: &str) -> Result<String, Error> {
let mut file = File::open(path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
Ok(contents)
}
```
**To Async:**
```rust
use tokio::fs::File;
use tokio::io::AsyncReadExt;
async fn read_config(path: &str) -> Result<String, Error> {
let mut file = File::open(path).await?;
let mut contents = String::new();
file.read_to_string(&mut contents).await?;
Ok(contents)
}
```
6. **Replace Blocking Operations**
Convert common patterns:
**Thread Sleep → Async Sleep:**
```rust
// Before
use std::thread;
use std::time::Duration;
fn wait() {
thread::sleep(Duration::from_secs(1));
}
// After
use tokio::time::{sleep, Duration};
async fn wait() {
sleep(Duration::from_secs(1)).await;
}
```
**Std Mutex → Tokio Mutex:**
```rust
// Before
use std::sync::Mutex;
fn update_state(mutex: &Mutex<State>) {
let mut state = mutex.lock().unwrap();
state.update();
}
// After
use tokio::sync::Mutex;
async fn update_state(mutex: &Mutex<State>) {
let mut state = mutex.lock().await;
state.update();
}
```
**Thread Spawning → Task Spawning:**
```rust
// Before
use std::thread;
fn spawn_worker() {
thread::spawn(|| {
do_work();
});
}
// After
use tokio::task;
async fn spawn_worker() {
task::spawn(async {
do_work().await;
});
}
```
7. **Update Dependencies in Cargo.toml**
Replace sync crates:
```toml
# Before
[dependencies]
reqwest = { version = "0.11", features = ["blocking"] }
# After
[dependencies]
reqwest = "0.11"
tokio = { version = "1", features = ["full"] }
```
8. **Add Runtime Setup**
Add to main.rs:
```rust
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Your async code
Ok(())
}
```
9. **Handle CPU-Intensive Operations**
Wrap in `spawn_blocking`:
```rust
async fn process_data(data: Vec<u8>) -> Result<Vec<u8>, Error> {
// CPU-intensive work
let result = tokio::task::spawn_blocking(move || {
expensive_computation(data)
}).await?;
Ok(result)
}
```
### 2. Tokio Version Upgrade
When upgrading between Tokio versions (e.g., 0.2 → 1.x):
#### Analysis Phase
1. **Detect Current Version**
- Read `Cargo.toml`
- Identify current Tokio version
- Check dependent crates versions
2. **Identify Breaking Changes**
- Scan for deprecated APIs
- Find removed features
- Detect renamed functions
#### Migration Phase
3. **Update Cargo.toml**
```toml
# From Tokio 0.2
[dependencies]
tokio = { version = "0.2", features = ["macros", "rt-threaded"] }
# To Tokio 1.x
[dependencies]
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
```
4. **Update Runtime Setup**
```rust
// Tokio 0.2
#[tokio::main]
async fn main() {
// ...
}
// Tokio 1.x (same, but verify features)
#[tokio::main]
async fn main() {
// ...
}
```
5. **Fix API Changes**
Common migrations:
**Timer API:**
```rust
// Tokio 0.2
use tokio::time::delay_for;
delay_for(Duration::from_secs(1)).await;
// Tokio 1.x
use tokio::time::sleep;
sleep(Duration::from_secs(1)).await;
```
**Timeout API:**
```rust
// Tokio 0.2
use tokio::time::timeout_at;
// Tokio 1.x
use tokio::time::timeout;
```
**Signal Handling:**
```rust
// Tokio 0.2
use tokio::signal::ctrl_c;
// Tokio 1.x (same, but improved)
use tokio::signal::ctrl_c;
```
6. **Update Feature Flags**
Map old features to new:
- `rt-threaded` → `rt-multi-thread`
- `rt-core` → `rt`
- `tcp` → `net`
- `dns` → removed (use async DNS crates)
### 3. Runtime Switch
When switching from other runtimes (async-std, smol) to Tokio:
#### Analysis Phase
1. **Identify Runtime-Specific Code**
- Find runtime initialization
- Detect runtime-specific APIs
- Identify spawning patterns
#### Migration Phase
2. **Replace Runtime Setup**
**From async-std:**
```rust
// Before
#[async_std::main]
async fn main() {
// ...
}
// After
#[tokio::main]
async fn main() {
// ...
}
```
3. **Update Spawning**
```rust
// async-std
use async_std::task;
task::spawn(async { /* ... */ });
// Tokio
use tokio::task;
task::spawn(async { /* ... */ });
```
4. **Replace I/O Types**
```rust
// async-std
use async_std::net::TcpListener;
// Tokio
use tokio::net::TcpListener;
```
5. **Update Dependencies**
Replace runtime-specific crates:
```toml
# Remove
async-std = "1"
# Add
tokio = { version = "1", features = ["full"] }
```
### Common Migration Tasks
For all migration types:
1. **Update Tests**
```rust
// Before
#[async_std::test]
async fn test_something() { }
// After
#[tokio::test]
async fn test_something() { }
```
2. **Update Error Handling**
- Ensure error types work with async
- Add proper error context
- Use `?` operator appropriately
3. **Add Tracing**
- Instrument key functions
- Add structured logging
- Set up tracing subscriber
4. **Verification**
- Run `cargo check`
- Run `cargo test`
- Run `cargo clippy`
- Verify no blocking operations remain
## Migration Checklist
- [ ] All I/O operations are async
- [ ] No `std::thread::sleep` usage
- [ ] No `std::sync::Mutex` in async code
- [ ] CPU-intensive work uses `spawn_blocking`
- [ ] Runtime properly configured
- [ ] Tests updated to use `#[tokio::test]`
- [ ] Dependencies updated in Cargo.toml
- [ ] Error handling verified
- [ ] Documentation updated
- [ ] Performance tested
## Incremental Migration Strategy
For large codebases:
1. **Identify Migration Boundaries**
- Start with leaf functions (no callers)
- Move up the call graph gradually
- Create async versions alongside sync
2. **Bridge Sync and Async**
```rust
// Call async from sync
fn sync_wrapper() -> Result<T, Error> {
let rt = tokio::runtime::Runtime::new()?;
rt.block_on(async_function())
}
// Call sync from async (CPU-intensive)
async fn async_wrapper() -> Result<T, Error> {
tokio::task::spawn_blocking(|| {
sync_function()
}).await?
}
```
3. **Migration Order**
- I/O layer first
- Business logic second
- API/handlers last
- Tests continuously
## Best Practices
1. **Don't Mix Sync and Async I/O**: Choose one model
2. **Use spawn_blocking**: For blocking operations you can't convert
3. **Test Thoroughly**: Async bugs can be subtle
4. **Profile Performance**: Measure before and after
5. **Update Documentation**: Note async requirements
6. **Handle Cancellation**: Implement proper cleanup
7. **Consider Backpressure**: Add flow control
## Notes
- Migration is often incremental - don't try to do everything at once
- Test each migration step thoroughly
- Consider performance implications of async
- Some operations may not benefit from async
- Document breaking changes for API consumers

248
commands/tokio-review.md Normal file
View File

@@ -0,0 +1,248 @@
---
name: tokio-review
description: Review Tokio code for async anti-patterns, performance issues, and best practices
---
# Tokio Review Command
This command performs comprehensive code review of Tokio-based applications, identifying async/await anti-patterns, performance issues, blocking operations, and suggesting improvements.
## Arguments
- `$1` - File path or directory to review (optional, defaults to current directory)
## Usage
```
/rust-tokio-expert:tokio-review
/rust-tokio-expert:tokio-review src/handlers/
/rust-tokio-expert:tokio-review src/main.rs
```
## Workflow
1. **Analyze Target**
- If no argument provided, scan current directory for Rust files
- If directory provided, scan all `.rs` files recursively
- If file provided, review that specific file
2. **Read Relevant Files**
- Use Glob tool to find Rust source files
- Read all identified files using Read tool
- Prioritize files in: src/main.rs, src/lib.rs, src/**/*.rs
3. **Invoke Agent**
- Use Task tool with `subagent_type="rust-tokio-expert:tokio-performance"`
- Provide all source code context to the agent
- Request comprehensive analysis
4. **Review Checklist**
The agent should analyze for:
### Async/Await Anti-Patterns
- [ ] **Blocking Operations in Async Context**
- Detect `std::thread::sleep` instead of `tokio::time::sleep`
- Identify blocking I/O operations
- Find CPU-intensive operations not wrapped in `spawn_blocking`
- [ ] **Holding Locks Across Await Points**
- Detect `std::sync::Mutex` or `tokio::sync::Mutex` held across `.await`
- Suggest lock scope reduction
- Recommend alternatives like channels
- [ ] **Unnecessary Cloning**
- Identify expensive clones in async contexts
- Suggest `Arc` for shared data
- Recommend reference passing where possible
- [ ] **Futures Not Being Awaited**
- Find async functions called without `.await`
- Detect unused futures
- Identify missing error handling
### Performance Issues
- [ ] **Excessive Task Spawning**
- Detect unbounded task creation in loops
- Suggest `buffer_unordered` or bounded concurrency
- Recommend semaphore-based limiting
- [ ] **Large Future Sizes**
- Identify large types stored in future state
- Suggest boxing large data
- Recommend heap allocation for big arrays
- [ ] **Inefficient Channel Usage**
- Detect unbounded channels
- Identify inappropriate channel types
- Suggest buffer size optimization
- [ ] **Memory Allocation in Hot Paths**
- Find repeated allocations in loops
- Suggest buffer reuse
- Recommend object pooling
### Concurrency Issues
- [ ] **Potential Deadlocks**
- Detect complex lock ordering
- Identify circular dependencies
- Suggest lock-free alternatives
- [ ] **Missing Timeout Handling**
- Find network operations without timeouts
- Suggest `tokio::time::timeout` usage
- Recommend timeout configuration
- [ ] **Improper Shutdown Handling**
- Check for graceful shutdown implementation
- Verify cleanup in Drop implementations
- Ensure resource release
### Error Handling
- [ ] **Error Propagation**
- Verify proper error context
- Check error type appropriateness
- Suggest improvements for error handling
- [ ] **Panic in Async Context**
- Detect unwrap/expect in async code
- Suggest proper error handling
- Recommend Result usage
### Channel Patterns
- [ ] **Channel Selection**
- Verify appropriate channel type (mpsc, oneshot, broadcast, watch)
- Check buffer sizes
- Suggest alternatives if needed
- [ ] **Select! Usage**
- Review select! macro usage
- Check for biased selection when needed
- Verify all branches handle errors
### Runtime Configuration
- [ ] **Runtime Setup**
- Check worker thread configuration
- Verify blocking thread pool size
- Suggest optimizations based on workload
5. **Generate Report**
Create a structured review report with:
### Critical Issues (Must Fix)
- Blocking operations in async context
- Potential deadlocks
- Memory safety issues
- Resource leaks
### High Priority (Should Fix)
- Performance bottlenecks
- Inefficient patterns
- Missing error handling
- Improper shutdown handling
### Medium Priority (Consider Fixing)
- Suboptimal channel usage
- Missing timeouts
- Code organization
- Documentation gaps
### Low Priority (Nice to Have)
- Style improvements
- Additional tracing
- Better variable names
For each issue, provide:
- **Location**: File, line number, function
- **Issue**: Clear description of the problem
- **Impact**: Why it matters (performance, correctness, maintainability)
- **Suggestion**: Specific fix with code example
- **Priority**: Critical, High, Medium, Low
6. **Code Examples**
For each suggestion, provide:
- Current problematic code
- Suggested improved code
- Explanation of the improvement
7. **Summary Statistics**
Provide overview:
- Total files reviewed
- Total issues found (by priority)
- Estimated effort to fix
- Overall code health score (if applicable)
## Example Report Format
```markdown
# Tokio Code Review Report
## Summary
- Files reviewed: 15
- Critical issues: 2
- High priority: 5
- Medium priority: 8
- Low priority: 3
## Critical Issues
### 1. Blocking Operation in Async Context
**Location**: `src/handlers/user.rs:45`
**Function**: `process_user`
**Issue**:
Using `std::thread::sleep` in async function blocks the runtime thread.
**Current Code**:
\`\`\`rust
async fn process_user(id: u64) {
std::thread::sleep(Duration::from_secs(1)); // Blocks thread!
// ...
}
\`\`\`
**Suggested Fix**:
\`\`\`rust
async fn process_user(id: u64) {
tokio::time::sleep(Duration::from_secs(1)).await; // Yields control
// ...
}
\`\`\`
**Impact**: This blocks an entire runtime worker thread, preventing other tasks from making progress. Can cause significant performance degradation under load.
## High Priority Issues
### 1. Lock Held Across Await Point
**Location**: `src/state.rs:78`
...
```
## Best Practices Validation
The review should also verify:
1. **Tracing**: Proper use of `#[instrument]` and structured logging
2. **Error Types**: Appropriate error types with context
3. **Testing**: Async tests with `#[tokio::test]`
4. **Documentation**: Doc comments on public async functions
5. **Metrics**: Performance-critical paths instrumented
6. **Configuration**: Runtime properly configured
7. **Dependencies**: Using appropriate crate versions
## Notes
- Focus on actionable feedback with concrete examples
- Prioritize issues that impact correctness over style
- Provide educational explanations for async concepts
- Suggest resources for learning more about identified issues
- Be constructive and supportive in feedback tone

247
commands/tokio-scaffold.md Normal file
View File

@@ -0,0 +1,247 @@
---
name: tokio-scaffold
description: Scaffold new Tokio projects with proper structure and best practices
---
# Tokio Scaffold Command
This command scaffolds new Tokio-based Rust projects with modern structure, proper dependencies, error handling patterns, tracing infrastructure, and testing setup.
## Arguments
- `$1` - Project name (required)
- `$2` - Project type: `http-server`, `grpc-server`, `tcp-server`, `cli`, or `library` (optional, defaults to `library`)
## Usage
```
/rust-tokio-expert:tokio-scaffold my-service http-server
/rust-tokio-expert:tokio-scaffold my-cli cli
/rust-tokio-expert:tokio-scaffold my-lib library
```
## Workflow
1. **Validate Arguments**
- Check that project name is provided
- Validate project type if provided
- Ensure target directory doesn't already exist
2. **Invoke Agent**
- Use Task tool with `subagent_type="rust-tokio-expert:tokio-pro"`
- Pass project name and type to the agent
3. **Agent Instructions**
The agent should create a complete project structure based on the type:
### For HTTP Server Projects
Create:
- `Cargo.toml` with dependencies:
- tokio with full features
- axum for HTTP framework
- tower and tower-http for middleware
- serde and serde_json for serialization
- tracing and tracing-subscriber for logging
- anyhow and thiserror for error handling
- sqlx (optional) for database
- config for configuration management
- `src/main.rs` with:
- Runtime setup with tracing
- Router configuration
- Graceful shutdown handling
- Health check endpoints
- `src/handlers/mod.rs` with example HTTP handlers
- `src/error.rs` with custom error types
- `src/config.rs` with configuration loading
- `src/telemetry.rs` with tracing setup
- `tests/integration_test.rs` with API integration tests
- `.env.example` with configuration template
- `README.md` with usage instructions
### For gRPC Server Projects
Create:
- `Cargo.toml` with:
- tokio with full features
- tonic and tonic-build
- prost for protobuf
- tower for middleware
- tracing infrastructure
- error handling crates
- `proto/service.proto` with example service definition
- `build.rs` for proto compilation
- `src/main.rs` with gRPC server setup
- `src/service.rs` with service implementation
- `src/error.rs` with error types
- `tests/integration_test.rs`
### For TCP Server Projects
Create:
- `Cargo.toml` with:
- tokio with io-util, net features
- tokio-util with codec
- bytes for buffer management
- tracing infrastructure
- `src/main.rs` with TCP server setup
- `src/protocol.rs` with protocol definition
- `src/handler.rs` with connection handler
- `tests/integration_test.rs`
### For CLI Projects
Create:
- `Cargo.toml` with:
- tokio with full features
- clap for argument parsing
- anyhow for error handling
- tracing-subscriber for logging
- `src/main.rs` with CLI setup
- `src/commands/mod.rs` with command structure
- `src/config.rs` with configuration
- `tests/cli_test.rs`
### For Library Projects
Create:
- `Cargo.toml` with:
- tokio as optional dependency
- async-trait
- thiserror for errors
- `src/lib.rs` with library structure
- `tests/lib_test.rs` with comprehensive tests
- `examples/basic.rs` with usage example
- `README.md` with API documentation
4. **Common Files for All Types**
- `.gitignore` with Rust-specific ignores
- `Cargo.toml` with proper metadata
- `rustfmt.toml` with formatting rules
- `clippy.toml` with linting configuration (if needed)
5. **Initialize Testing**
For all project types:
- Add `#[tokio::test]` examples
- Include timeout tests
- Add mock/test utilities
- Set up test helpers
6. **Documentation**
Generate `README.md` with:
- Project description
- Requirements
- Installation instructions
- Usage examples
- Development setup
- Testing instructions
- Contributing guidelines
7. **Verification**
After scaffolding:
- Run `cargo check` to verify compilation
- Run `cargo test` to verify tests
- Report any issues found
## Example Cargo.toml Template (HTTP Server)
```toml
[package]
name = "{{project_name}}"
version = "0.1.0"
edition = "2021"
[dependencies]
tokio = { version = "1", features = ["full"] }
axum = "0.7"
tower = "0.4"
tower-http = { version = "0.5", features = ["trace", "compression-gzip"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] }
anyhow = "1"
thiserror = "1"
config = "0.14"
[dev-dependencies]
tokio-test = "0.4"
```
## Example Main Template (HTTP Server)
```rust
use axum::{Router, routing::get};
use std::net::SocketAddr;
use tower_http::trace::TraceLayer;
mod handlers;
mod error;
mod config;
mod telemetry;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Initialize telemetry
telemetry::init()?;
// Load configuration
let config = config::load()?;
// Create router
let app = Router::new()
.route("/health", get(handlers::health_check))
.route("/api/v1/users", get(handlers::list_users))
.layer(TraceLayer::new_for_http());
// Start server
let addr = SocketAddr::from(([0, 0, 0, 0], config.port));
tracing::info!("Starting server on {}", addr);
let listener = tokio::net::TcpListener::bind(addr).await?;
axum::serve(listener, app)
.with_graceful_shutdown(shutdown_signal())
.await?;
Ok(())
}
async fn shutdown_signal() {
tokio::signal::ctrl_c()
.await
.expect("failed to install CTRL+C signal handler");
}
```
## Best Practices
The scaffolded project should follow these best practices:
1. **Error Handling**: Use `thiserror` for domain errors, `anyhow` for application errors
2. **Configuration**: Use environment variables with sensible defaults
3. **Logging**: Use `tracing` with structured logging
4. **Testing**: Include both unit and integration tests
5. **Documentation**: Generate comprehensive README with examples
6. **Security**: Include basic security headers and validation
7. **Performance**: Configure runtime appropriately for workload type
8. **Observability**: Include metrics and health check endpoints
## Notes
- Always use the latest stable versions of dependencies
- Include comments explaining key architectural decisions
- Provide both simple and advanced usage examples
- Generate projects that compile and pass tests out of the box
- Follow Rust API guidelines and naming conventions

425
commands/tokio-test.md Normal file
View File

@@ -0,0 +1,425 @@
---
name: tokio-test
description: Generate comprehensive async tests for Tokio applications
---
# Tokio Test Command
This command generates comprehensive async tests for Tokio applications, including unit tests, integration tests, benchmarks, and property-based tests.
## Arguments
- `$1` - Target to generate tests for: file path, module name, or function name (required)
- `$2` - Test type: `unit`, `integration`, `benchmark`, or `all` (optional, defaults to `unit`)
## Usage
```
/rust-tokio-expert:tokio-test src/handlers/user.rs
/rust-tokio-expert:tokio-test src/service.rs integration
/rust-tokio-expert:tokio-test process_request benchmark
/rust-tokio-expert:tokio-test src/api/ all
```
## Workflow
1. **Parse Arguments**
- Validate target is provided
- Determine test type (unit, integration, benchmark, all)
- Identify target scope (file, module, or function)
2. **Analyze Target Code**
- Read the target file(s) using Read tool
- Identify async functions to test
- Analyze function signatures and dependencies
- Detect error types and return values
3. **Invoke Agent**
- Use Task tool with `subagent_type="rust-tokio-expert:tokio-pro"`
- Provide code context and test requirements
- Request test generation based on type
4. **Generate Unit Tests**
For each async function, create tests covering:
### Happy Path Tests
```rust
#[tokio::test]
async fn test_process_user_success() {
// Arrange
let user_id = 1;
let expected_name = "John Doe";
// Act
let result = process_user(user_id).await;
// Assert
assert!(result.is_ok());
let user = result.unwrap();
assert_eq!(user.name, expected_name);
}
```
### Error Handling Tests
```rust
#[tokio::test]
async fn test_process_user_not_found() {
let result = process_user(999).await;
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), Error::NotFound));
}
```
### Timeout Tests
```rust
#[tokio::test]
async fn test_operation_completes_within_timeout() {
use tokio::time::{timeout, Duration};
let result = timeout(
Duration::from_secs(5),
slow_operation()
).await;
assert!(result.is_ok(), "Operation timed out");
}
```
### Concurrent Execution Tests
```rust
#[tokio::test]
async fn test_concurrent_processing() {
let handles: Vec<_> = (0..10)
.map(|i| tokio::spawn(process_item(i)))
.collect();
let results: Vec<_> = futures::future::join_all(handles)
.await
.into_iter()
.map(|r| r.unwrap())
.collect();
assert_eq!(results.len(), 10);
assert!(results.iter().all(|r| r.is_ok()));
}
```
### Mock Tests
```rust
#[cfg(test)]
mod tests {
use super::*;
use mockall::predicate::*;
use mockall::mock;
mock! {
UserRepository {}
#[async_trait::async_trait]
impl UserRepository for UserRepository {
async fn find_by_id(&self, id: u64) -> Result<User, Error>;
}
}
#[tokio::test]
async fn test_with_mock_repository() {
let mut mock_repo = MockUserRepository::new();
mock_repo
.expect_find_by_id()
.with(eq(1))
.times(1)
.returning(|_| Ok(User { id: 1, name: "Test".into() }));
let service = UserService::new(Box::new(mock_repo));
let user = service.get_user(1).await.unwrap();
assert_eq!(user.name, "Test");
}
}
```
5. **Generate Integration Tests**
Create `tests/integration_test.rs` with:
### API Integration Tests
```rust
use tokio::net::TcpListener;
#[tokio::test]
async fn test_http_endpoint() {
// Start test server
let listener = TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr = listener.local_addr().unwrap();
tokio::spawn(async move {
run_server(listener).await.unwrap();
});
// Make request
let client = reqwest::Client::new();
let response = client
.get(format!("http://{}/health", addr))
.send()
.await
.unwrap();
assert_eq!(response.status(), 200);
}
```
### Database Integration Tests
```rust
#[tokio::test]
async fn test_database_operations() {
let pool = create_test_pool().await;
// Insert test data
let user = User { id: 1, name: "Test".into() };
save_user(&pool, &user).await.unwrap();
// Verify
let fetched = find_user(&pool, 1).await.unwrap();
assert_eq!(fetched.unwrap().name, "Test");
// Cleanup
cleanup_test_data(&pool).await;
}
```
### End-to-End Tests
```rust
#[tokio::test]
async fn test_complete_workflow() {
// Setup
let app = create_test_app().await;
// Create user
let create_response = app.create_user("John").await.unwrap();
let user_id = create_response.id;
// Fetch user
let user = app.get_user(user_id).await.unwrap();
assert_eq!(user.name, "John");
// Update user
app.update_user(user_id, "Jane").await.unwrap();
// Verify update
let updated = app.get_user(user_id).await.unwrap();
assert_eq!(updated.name, "Jane");
// Delete user
app.delete_user(user_id).await.unwrap();
// Verify deletion
let deleted = app.get_user(user_id).await;
assert!(deleted.is_err());
}
```
6. **Generate Benchmarks**
Create `benches/async_bench.rs` with:
```rust
use criterion::{criterion_group, criterion_main, Criterion, BenchmarkId};
use tokio::runtime::Runtime;
fn benchmark_async_operations(c: &mut Criterion) {
let rt = Runtime::new().unwrap();
let mut group = c.benchmark_group("async-operations");
// Throughput benchmark
for size in [10, 100, 1000].iter() {
group.throughput(criterion::Throughput::Elements(*size as u64));
group.bench_with_input(
BenchmarkId::from_parameter(size),
size,
|b, &size| {
b.to_async(&rt).iter(|| async move {
process_batch(size).await
});
},
);
}
// Latency benchmark
group.bench_function("single_request", |b| {
b.to_async(&rt).iter(|| async {
process_request().await
});
});
// Concurrent operations
group.bench_function("concurrent_10", |b| {
b.to_async(&rt).iter(|| async {
let handles: Vec<_> = (0..10)
.map(|_| tokio::spawn(process_request()))
.collect();
for handle in handles {
handle.await.unwrap();
}
});
});
group.finish();
}
criterion_group!(benches, benchmark_async_operations);
criterion_main!(benches);
```
7. **Generate Test Utilities**
Create `tests/common/mod.rs` with helpers:
```rust
use tokio::runtime::Runtime;
pub fn create_test_runtime() -> Runtime {
Runtime::new().unwrap()
}
pub async fn setup_test_database() -> TestDb {
// Create test database
// Run migrations
// Return handle
}
pub async fn cleanup_test_database(db: TestDb) {
// Drop test database
}
pub struct TestApp {
// Application state for testing
}
impl TestApp {
pub async fn new() -> Self {
// Initialize test application
}
pub async fn cleanup(self) {
// Cleanup resources
}
}
```
8. **Add Test Configuration**
Update `Cargo.toml` with test dependencies:
```toml
[dev-dependencies]
tokio-test = "0.4"
mockall = "0.12"
criterion = { version = "0.5", features = ["async_tokio"] }
proptest = "1"
futures = "0.3"
```
9. **Generate Property-Based Tests**
For appropriate functions:
```rust
use proptest::prelude::*;
proptest! {
#[test]
fn test_parse_always_succeeds(input in "\\PC*") {
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async {
let result = parse_input(&input).await;
assert!(result.is_ok() || result.is_err());
});
}
}
```
10. **Run and Verify Tests**
After generation:
- Run `cargo test` to verify tests compile and pass
- Run `cargo bench` to verify benchmarks work
- Report coverage gaps if any
- Suggest additional test cases if needed
## Test Categories
Generate tests for:
1. **Functional Correctness**
- Happy path scenarios
- Edge cases
- Error conditions
- Boundary values
2. **Concurrency**
- Race conditions
- Deadlocks
- Task spawning
- Shared state access
3. **Performance**
- Throughput
- Latency
- Resource usage
- Scalability
4. **Reliability**
- Error recovery
- Timeout handling
- Retry logic
- Graceful degradation
5. **Integration**
- API endpoints
- Database operations
- External services
- End-to-end workflows
## Best Practices
Generated tests should:
1. Use descriptive test names that explain what is being tested
2. Follow Arrange-Act-Assert pattern
3. Be independent and idempotent
4. Clean up resources properly
5. Use appropriate timeouts
6. Include helpful assertion messages
7. Mock external dependencies
8. Test both success and failure paths
9. Use `#[tokio::test]` for async tests
10. Configure runtime appropriately for test type
## Example Test Organization
```
tests/
├── common/
│ ├── mod.rs # Shared test utilities
│ └── fixtures.rs # Test data fixtures
├── integration_test.rs # API integration tests
├── database_test.rs # Database integration tests
└── e2e_test.rs # End-to-end tests
benches/
├── throughput.rs # Throughput benchmarks
└── latency.rs # Latency benchmarks
```
## Notes
- Generate tests that are maintainable and easy to understand
- Include comments explaining complex test scenarios
- Provide setup and teardown helpers
- Use realistic test data
- Consider using test fixtures for consistency
- Document any test-specific configuration needed