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:
2025-04-09 13:29:38 -04:00
parent d47d5f44b1
commit a8755bd3de
85 changed files with 4218 additions and 764 deletions

View File

@@ -0,0 +1,96 @@
use packet_service::bufferpool::BufferPool;
use std::sync::Arc;
#[tokio::test]
async fn test_buffer_pool_creation() {
let pool_size = 5;
let pool = BufferPool::new(pool_size);
// Verify we can acquire the expected number of buffers
for _ in 0..pool_size {
let buffer = pool.acquire().await;
assert!(buffer.is_some());
}
// The next acquire should return None since all buffers are in use
let buffer = pool.acquire().await;
assert!(buffer.is_none());
}
#[tokio::test]
async fn test_buffer_pool_release() {
let pool_size = 3;
let pool = BufferPool::new(pool_size);
// Acquire all buffers
let mut buffers = Vec::new();
for _ in 0..pool_size {
let buffer = pool.acquire().await.unwrap();
buffers.push(buffer);
}
// Release one buffer
let buffer = buffers.pop().unwrap();
pool.release(buffer).await;
// We should be able to acquire one buffer now
let buffer = pool.acquire().await;
assert!(buffer.is_some());
// But not two
let buffer = pool.acquire().await;
assert!(buffer.is_none());
}
#[tokio::test]
async fn test_buffer_pool_concurrent_access() {
let pool_size = 10;
let pool = Arc::new(BufferPool::new(pool_size));
// Spawn multiple tasks to acquire and release buffers
let mut handles = Vec::new();
for i in 0..pool_size {
let pool_clone = pool.clone();
let handle = tokio::spawn(async move {
// Acquire a buffer
let mut buffer = pool_clone.acquire().await.unwrap();
// Write some data to the buffer
buffer[0] = i as u8;
// Simulate some work
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
// Release the buffer
pool_clone.release(buffer).await;
});
handles.push(handle);
}
// Wait for all tasks to complete
for handle in handles {
handle.await.unwrap();
}
// All buffers should be available again
for _ in 0..pool_size {
let buffer = pool.acquire().await;
assert!(buffer.is_some());
}
}
#[tokio::test]
async fn test_buffer_pool_buffer_size() {
let pool = BufferPool::new(1);
// Acquire a buffer
let buffer = pool.acquire().await.unwrap();
// Buffer should be large enough for maximum packet size
assert!(buffer.len() >= 0xFFF);
// Release the buffer
pool.release(buffer).await;
}

View File

@@ -0,0 +1,108 @@
use packet_service::connection_service::ConnectionService;
use packet_service::connection_state::ConnectionState;
use std::collections::HashSet;
#[test]
fn test_connection_service_add_connection() {
let service = ConnectionService::new();
// Add a connection
let connection_id = service.add_connection();
// Verify the connection exists
let connection = service.get_connection(&connection_id);
assert!(connection.is_some());
}
#[test]
fn test_connection_service_remove_connection() {
let service = ConnectionService::new();
// Add a connection
let connection_id = service.add_connection();
// Verify the connection exists
let connection = service.get_connection(&connection_id);
assert!(connection.is_some());
// Remove the connection
service.remove_connection(&connection_id);
// Verify the connection no longer exists
let connection = service.get_connection(&connection_id);
assert!(connection.is_none());
}
#[test]
fn test_connection_service_get_connection_mut() {
let service = ConnectionService::new();
// Add a connection
let connection_id = service.add_connection();
// Get a mutable reference to the connection
let mut connection = service.get_connection_mut(&connection_id).unwrap();
// Modify the connection
connection.user_id = Some("test_user".to_string());
connection.session_id = Some("test_session".to_string());
connection.character_id = Some(123);
// Drop the mutable reference
drop(connection);
// Verify the changes were saved
let connection = service.get_connection(&connection_id).unwrap();
assert_eq!(connection.user_id, Some("test_user".to_string()));
assert_eq!(connection.session_id, Some("test_session".to_string()));
assert_eq!(connection.character_id, Some(123));
}
#[test]
fn test_connection_service_multiple_connections() {
let service = ConnectionService::new();
// Add multiple connections
let connection_ids: Vec<String> = (0..10).map(|_| service.add_connection()).collect();
// Verify all connections exist
for connection_id in &connection_ids {
let connection = service.get_connection(connection_id);
assert!(connection.is_some());
}
// Verify all connection IDs are unique
let unique_ids: HashSet<String> = connection_ids.iter().cloned().collect();
assert_eq!(unique_ids.len(), connection_ids.len());
}
#[test]
fn test_connection_state_new() {
let state = ConnectionState::new();
// Verify initial state
assert_eq!(state.user_id, None);
assert_eq!(state.session_id, None);
assert_eq!(state.character_id, None);
assert_eq!(state.character_list, None);
assert!(state.additional_data.is_empty());
}
#[test]
fn test_connection_state_additional_data() {
let mut state = ConnectionState::new();
// Add some additional data
state.additional_data.insert("key1".to_string(), "value1".to_string());
state.additional_data.insert("key2".to_string(), "value2".to_string());
// Verify the data was added
assert_eq!(state.additional_data.get("key1"), Some(&"value1".to_string()));
assert_eq!(state.additional_data.get("key2"), Some(&"value2".to_string()));
// Update a value
state.additional_data.insert("key1".to_string(), "updated".to_string());
// Verify the value was updated
assert_eq!(state.additional_data.get("key1"), Some(&"updated".to_string()));
}

View File

@@ -0,0 +1,98 @@
use bincode::{Decode, Encode};
use packet_service::packet::{Packet, PacketPayload};
use packet_service::packet_type::PacketType;
// Define a test payload struct
#[derive(Debug, Encode, Decode, PartialEq)]
struct TestPayload {
id: u32,
name: String,
value: f32,
}
impl PacketPayload for TestPayload {}
#[test]
fn test_packet_creation() {
let payload = TestPayload {
id: 123,
name: "test".to_string(),
value: 3.14,
};
let packet = Packet::new(PacketType::PakcsAlive, &payload).unwrap();
// Check packet fields
assert_eq!(packet.packet_type, PacketType::PakcsAlive);
assert_eq!(packet.packet_crc, 0); // CRC is currently not implemented
assert!(!packet.payload.is_empty());
}
#[test]
fn test_packet_serialization_deserialization() {
let original_payload = TestPayload {
id: 456,
name: "serialization_test".to_string(),
value: 2.71,
};
// Create a packet
let packet = Packet::new(PacketType::PakcsAlive, &original_payload).unwrap();
// Serialize to raw bytes
let raw_data = packet.to_raw();
// Deserialize from raw bytes
let deserialized_packet = Packet::from_raw(&raw_data).unwrap();
// Check packet fields match
assert_eq!(deserialized_packet.packet_type, packet.packet_type);
assert_eq!(deserialized_packet.packet_size, packet.packet_size);
assert_eq!(deserialized_packet.packet_crc, packet.packet_crc);
// Parse the payload
let deserialized_payload: TestPayload = deserialized_packet.parse().unwrap();
// Check payload fields match
assert_eq!(deserialized_payload, original_payload);
}
#[test]
fn test_packet_from_raw_invalid_size() {
// Create a packet with invalid size (too small)
let raw_data = vec![0, 0, 0, 0]; // Only 4 bytes, less than minimum 6 bytes
let result = Packet::from_raw(&raw_data);
assert!(result.is_err());
}
#[test]
fn test_packet_from_raw_size_mismatch() {
// Create a packet with size mismatch
let mut raw_data = vec![0; 10]; // 10 bytes
// Set packet size to 20 (more than actual data)
raw_data[0] = 20;
raw_data[1] = 0;
let result = Packet::from_raw(&raw_data);
assert!(result.is_err());
}
#[test]
fn test_packet_payload_encoding_decoding() {
let original_payload = TestPayload {
id: 789,
name: "encoding_test".to_string(),
value: 1.618,
};
// Encode payload
let encoded = bincode::encode_to_vec(&original_payload, bincode::config::standard()).unwrap();
// Decode payload
let decoded: TestPayload = bincode::decode_from_slice(&encoded, bincode::config::standard()).unwrap().0;
// Check payload fields match
assert_eq!(decoded, original_payload);
}