photoncloud-monorepo/chainfire/crates/chainfire-server/tests/integration_test.rs
centra 3eeb303dcb feat: Batch commit for T039.S3 deployment
Includes all pending changes needed for nixos-anywhere:
- fiberlb: L7 policy, rule, certificate types
- deployer: New service for cluster management
- nix-nos: Generic network modules
- Various service updates and fixes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-13 04:34:51 +09:00

174 lines
5 KiB
Rust

//! Integration tests for Chainfire
//!
//! These tests verify that the server, client, and all components work together correctly.
use chainfire_client::Client;
use chainfire_server::{
config::{ClusterConfig, NetworkConfig, NodeConfig, RaftConfig, ServerConfig, StorageConfig},
server::Server,
};
use std::time::Duration;
use tokio::time::sleep;
/// Create a test server configuration
fn test_config(port: u16) -> (ServerConfig, tempfile::TempDir) {
use std::net::SocketAddr;
let api_addr: SocketAddr = format!("127.0.0.1:{}", port).parse().unwrap();
let raft_addr: SocketAddr = format!("127.0.0.1:{}", port + 100).parse().unwrap();
let gossip_addr: SocketAddr = format!("127.0.0.1:{}", port + 200).parse().unwrap();
let temp_dir = tempfile::tempdir().unwrap();
let config = ServerConfig {
node: NodeConfig {
id: 1,
name: format!("test-node-{}", port),
role: "control_plane".to_string(),
},
cluster: ClusterConfig {
id: 1,
bootstrap: true,
initial_members: vec![],
},
network: NetworkConfig {
api_addr,
raft_addr,
gossip_addr,
tls: None,
},
storage: StorageConfig {
data_dir: temp_dir.path().to_path_buf(),
},
raft: RaftConfig::default(),
};
(config, temp_dir)
}
#[tokio::test]
async fn test_single_node_kv_operations() {
// Start server
let (config, _temp_dir) = test_config(23790);
let api_addr = config.network.api_addr;
let server = Server::new(config).await.unwrap();
// Run server in background
let server_handle = tokio::spawn(async move {
let _ = server.run().await;
});
// Wait for server to start and Raft leader election
// Increased from 500ms to 2000ms for CI/constrained environments
sleep(Duration::from_millis(2000)).await;
// Connect client
let mut client = Client::connect(format!("http://{}", api_addr))
.await
.unwrap();
// Test put with retry (leader election may still be in progress)
let mut rev = 0;
for attempt in 0..5 {
match client.put("test/key1", "value1").await {
Ok(r) => {
rev = r;
break;
}
Err(e) if attempt < 4 => {
eprintln!("Put attempt {} failed: {}, retrying...", attempt + 1, e);
sleep(Duration::from_millis(500)).await;
}
Err(e) => panic!("Put failed after 5 attempts: {}", e),
}
}
assert!(rev > 0);
// Test get
let value = client.get("test/key1").await.unwrap();
assert_eq!(value, Some(b"value1".to_vec()));
// Test put with different value
let rev2 = client.put("test/key1", "value2").await.unwrap();
assert!(rev2 > rev);
// Test get updated value
let value = client.get("test/key1").await.unwrap();
assert_eq!(value, Some(b"value2".to_vec()));
// Test get non-existent key
let value = client.get("test/nonexistent").await.unwrap();
assert!(value.is_none());
// Test delete
let deleted = client.delete("test/key1").await.unwrap();
assert!(deleted);
// Verify deletion
let value = client.get("test/key1").await.unwrap();
assert!(value.is_none());
// Test delete non-existent key
let deleted = client.delete("test/nonexistent").await.unwrap();
assert!(!deleted);
// Test prefix operations
client.put("prefix/a", "1").await.unwrap();
client.put("prefix/b", "2").await.unwrap();
client.put("prefix/c", "3").await.unwrap();
client.put("other/key", "other").await.unwrap();
let prefix_values = client.get_prefix("prefix/").await.unwrap();
assert_eq!(prefix_values.len(), 3);
// Cleanup
server_handle.abort();
}
#[tokio::test]
async fn test_cluster_status() {
let (config, _temp_dir) = test_config(23800);
let api_addr = config.network.api_addr;
let server = Server::new(config).await.unwrap();
let server_handle = tokio::spawn(async move {
let _ = server.run().await;
});
sleep(Duration::from_millis(500)).await;
let mut client = Client::connect(format!("http://{}", api_addr))
.await
.unwrap();
let status = client.status().await.unwrap();
assert_eq!(status.leader, 1);
assert!(status.raft_term > 0);
server_handle.abort();
}
#[tokio::test]
async fn test_string_convenience_methods() {
let (config, _temp_dir) = test_config(23810);
let api_addr = config.network.api_addr;
let server = Server::new(config).await.unwrap();
let server_handle = tokio::spawn(async move {
let _ = server.run().await;
});
sleep(Duration::from_millis(500)).await;
let mut client = Client::connect(format!("http://{}", api_addr))
.await
.unwrap();
// Test string methods
client.put_str("/config/name", "chainfire").await.unwrap();
let value = client.get_str("/config/name").await.unwrap();
assert_eq!(value, Some("chainfire".to_string()));
server_handle.abort();
}