Add comprehensive documentation and unit tests
Documentation: - Add detailed README files for all services (auth, character, database, launcher, packet, utils, world) - Create API documentation for the database service with detailed endpoint specifications - Document database schema and relationships - Add service architecture overviews and configuration instructions Unit Tests: - Implement comprehensive test suite for database repositories (user, character, session) - Add gRPC service tests for database interactions - Create tests for packet service components (bufferpool, connection, packets) - Add utility service tests (health check, logging, load balancer, redis cache, service discovery) - Implement auth service user tests - Add character service tests Code Structure: - Reorganize test files into a more consistent structure - Create a dedicated tests crate for integration testing - Add test helpers and mock implementations for easier testing
This commit is contained in:
151
tests/utils/multi_service_load_balancer_tests.rs
Normal file
151
tests/utils/multi_service_load_balancer_tests.rs
Normal file
@@ -0,0 +1,151 @@
|
||||
use std::collections::HashSet;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
use utils::multi_service_load_balancer::{LoadBalancingStrategy, MultiServiceLoadBalancer, ServiceId};
|
||||
|
||||
// Mock implementation for testing without actual service discovery
|
||||
mod mock {
|
||||
use super::*;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
// Mock version of the load balancer for testing
|
||||
pub struct MockMultiServiceLoadBalancer {
|
||||
strategy: LoadBalancingStrategy,
|
||||
services: Arc<Mutex<HashMap<ServiceId, Vec<SocketAddr>>>>,
|
||||
}
|
||||
|
||||
impl MockMultiServiceLoadBalancer {
|
||||
pub fn new(strategy: LoadBalancingStrategy) -> Self {
|
||||
MockMultiServiceLoadBalancer {
|
||||
strategy,
|
||||
services: Arc::new(Mutex::new(HashMap::new())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_service(&self, service_name: &str, service_protocol: &str, endpoints: Vec<SocketAddr>) {
|
||||
let service_id = ServiceId::new(service_name, service_protocol);
|
||||
let mut services = self.services.lock().unwrap();
|
||||
services.insert(service_id, endpoints);
|
||||
}
|
||||
|
||||
pub fn get_endpoint(&self, service_name: &str, service_protocol: &str) -> Option<SocketAddr> {
|
||||
let service_id = ServiceId::new(service_name, service_protocol);
|
||||
let services = self.services.lock().unwrap();
|
||||
|
||||
if let Some(endpoints) = services.get(&service_id) {
|
||||
if endpoints.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
match self.strategy {
|
||||
LoadBalancingStrategy::Random => {
|
||||
let index = rand::random::<usize>() % endpoints.len();
|
||||
Some(endpoints[index])
|
||||
},
|
||||
LoadBalancingStrategy::RoundRobin => {
|
||||
// For simplicity in tests, just return the first endpoint
|
||||
Some(endpoints[0])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_service_id() {
|
||||
let service_id1 = ServiceId::new("service1", "http");
|
||||
let service_id2 = ServiceId::new("service1", "http");
|
||||
let service_id3 = ServiceId::new("service2", "http");
|
||||
let service_id4 = ServiceId::new("service1", "https");
|
||||
|
||||
// Test equality
|
||||
assert_eq!(service_id1, service_id2);
|
||||
assert_ne!(service_id1, service_id3);
|
||||
assert_ne!(service_id1, service_id4);
|
||||
|
||||
// Test hash implementation
|
||||
let mut set = HashSet::new();
|
||||
set.insert(service_id1);
|
||||
assert!(set.contains(&service_id2));
|
||||
assert!(!set.contains(&service_id3));
|
||||
assert!(!set.contains(&service_id4));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mock_load_balancer_random() {
|
||||
let lb = mock::MockMultiServiceLoadBalancer::new(LoadBalancingStrategy::Random);
|
||||
|
||||
// Add a service with multiple endpoints
|
||||
let endpoints = vec![
|
||||
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 8080),
|
||||
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 2)), 8080),
|
||||
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 3)), 8080),
|
||||
];
|
||||
lb.add_service("test-service", "http", endpoints.clone());
|
||||
|
||||
// Get an endpoint
|
||||
let endpoint = lb.get_endpoint("test-service", "http");
|
||||
assert!(endpoint.is_some());
|
||||
assert!(endpoints.contains(&endpoint.unwrap()));
|
||||
|
||||
// Test non-existent service
|
||||
let endpoint = lb.get_endpoint("non-existent", "http");
|
||||
assert!(endpoint.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mock_load_balancer_round_robin() {
|
||||
let lb = mock::MockMultiServiceLoadBalancer::new(LoadBalancingStrategy::RoundRobin);
|
||||
|
||||
// Add a service with multiple endpoints
|
||||
let endpoints = vec![
|
||||
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)), 8080),
|
||||
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 2)), 8080),
|
||||
SocketAddr::new(IpAddr::V4(Ipv4Addr::new(192, 168, 1, 3)), 8080),
|
||||
];
|
||||
lb.add_service("test-service", "http", endpoints);
|
||||
|
||||
// Get an endpoint
|
||||
let endpoint = lb.get_endpoint("test-service", "http");
|
||||
assert!(endpoint.is_some());
|
||||
|
||||
// Test empty service
|
||||
lb.add_service("empty-service", "http", vec![]);
|
||||
let endpoint = lb.get_endpoint("empty-service", "http");
|
||||
assert!(endpoint.is_none());
|
||||
}
|
||||
|
||||
// Integration test with the actual MultiServiceLoadBalancer
|
||||
// This test is disabled by default as it requires a Consul server
|
||||
#[tokio::test]
|
||||
async fn test_multi_service_load_balancer() {
|
||||
use std::env;
|
||||
|
||||
// Skip test if CONSUL_TEST_ENABLED is not set to true
|
||||
if env::var("CONSUL_TEST_ENABLED").unwrap_or_else(|_| "false".to_string()) != "true" {
|
||||
println!("Skipping MultiServiceLoadBalancer test. Set CONSUL_TEST_ENABLED=true to run.");
|
||||
return;
|
||||
}
|
||||
|
||||
let consul_url = env::var("TEST_CONSUL_URL").unwrap_or_else(|_| "http://localhost:8500".to_string());
|
||||
let service_name = env::var("TEST_CONSUL_SERVICE_NAME").unwrap_or_else(|_| "database-service".to_string());
|
||||
let protocol = "tcp";
|
||||
|
||||
let lb = MultiServiceLoadBalancer::new(&consul_url, LoadBalancingStrategy::Random);
|
||||
|
||||
// Refresh service endpoints
|
||||
let result = lb.refresh_service_endpoints(&service_name, protocol).await;
|
||||
assert!(result.is_ok(), "Failed to refresh service endpoints: {:?}", result.err());
|
||||
|
||||
// Get an endpoint
|
||||
let result = lb.get_endpoint(&service_name, protocol).await;
|
||||
assert!(result.is_ok(), "Failed to get endpoint: {:?}", result.err());
|
||||
|
||||
let endpoint = result.unwrap();
|
||||
assert!(endpoint.is_some(), "No endpoint found for service {}", service_name);
|
||||
|
||||
println!("Found endpoint for service {}: {:?}", service_name, endpoint);
|
||||
}
|
||||
Reference in New Issue
Block a user