- Remove gitlinks (160000 mode) for chainfire, flaredb, iam - Add workspace contents as regular tracked files - Update flake.nix to use simple paths instead of builtins.fetchGit This resolves the nix build failure where submodule directories appeared empty in the nix store. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
159 lines
4.5 KiB
Rust
159 lines
4.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,
|
|
},
|
|
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
|
|
sleep(Duration::from_millis(500)).await;
|
|
|
|
// Connect client
|
|
let mut client = Client::connect(format!("http://{}", api_addr))
|
|
.await
|
|
.unwrap();
|
|
|
|
// Test put
|
|
let rev = client.put("test/key1", "value1").await.unwrap();
|
|
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();
|
|
}
|