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:
251
tests/character-service/character_service_tests.rs
Normal file
251
tests/character-service/character_service_tests.rs
Normal file
@@ -0,0 +1,251 @@
|
||||
use character_service::character_service::character::character_service_server::CharacterService;
|
||||
use character_service::character_service::character::{
|
||||
CreateCharacterRequest, DeleteCharacterRequest, GetCharacterListRequest, GetCharacterRequest,
|
||||
};
|
||||
use character_service::character_service::MyCharacterService;
|
||||
use mockall::predicate::*;
|
||||
use mockall::predicate::eq;
|
||||
use mockall::mock;
|
||||
|
||||
// Wrapper for the mock to implement the trait
|
||||
struct MockWrapper(MockCharacterDbClientTrait);
|
||||
|
||||
impl character_service::character_db_client::CharacterDbClient for MockWrapper {
|
||||
async fn get_character_list(&mut self, user_id: &str) -> Result<character_service::database::CharacterListResponse, Box<dyn std::error::Error>> {
|
||||
self.0.get_character_list(user_id).await
|
||||
}
|
||||
|
||||
async fn create_character(&mut self, user_id: &str, name: &str, race: i32, face: i32, hair: i32, stone: i32) -> Result<character_service::database::CreateCharacterResponse, Box<dyn std::error::Error>> {
|
||||
self.0.create_character(user_id, name, race, face, hair, stone).await
|
||||
}
|
||||
|
||||
async fn delete_character(&mut self, user_id: &str, char_id: &str, delete_type: i32) -> Result<character_service::database::DeleteCharacterResponse, Box<dyn std::error::Error>> {
|
||||
self.0.delete_character(user_id, char_id, delete_type).await
|
||||
}
|
||||
|
||||
async fn get_character(&mut self, user_id: &str, char_id: &str) -> Result<character_service::database::Character, Box<dyn std::error::Error>> {
|
||||
self.0.get_character(user_id, char_id).await
|
||||
}
|
||||
}
|
||||
use std::sync::Arc;
|
||||
use tonic::{Request, Status};
|
||||
|
||||
// Define a trait for the CharacterDbClient to make it mockable
|
||||
#[mockall::automock]
|
||||
trait CharacterDbClientTrait {
|
||||
async fn get_character_list(&mut self, user_id: &str) -> Result<character_service::database::CharacterListResponse, Box<dyn std::error::Error>>;
|
||||
async fn create_character(&mut self, user_id: &str, name: &str, race: i32, face: i32, hair: i32, stone: i32) -> Result<character_service::database::CreateCharacterResponse, Box<dyn std::error::Error>>;
|
||||
async fn delete_character(&mut self, user_id: &str, char_id: &str, delete_type: i32) -> Result<character_service::database::DeleteCharacterResponse, Box<dyn std::error::Error>>;
|
||||
async fn get_character(&mut self, user_id: &str, char_id: &str) -> Result<character_service::database::Character, Box<dyn std::error::Error>>;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_character_list() {
|
||||
// Create a mock CharacterDbClient
|
||||
let mut mock_client = MockCharacterDbClientTrait::new();
|
||||
|
||||
// Set up expectations
|
||||
mock_client
|
||||
.expect_get_character_list()
|
||||
.with(eq("test_user"))
|
||||
.times(1)
|
||||
.returning(|_| {
|
||||
Ok(character_service::database::CharacterListResponse {
|
||||
characters: vec![
|
||||
character_service::database::Character {
|
||||
id: 1,
|
||||
user_id: "test_user".to_string(),
|
||||
name: "Character1".to_string(),
|
||||
money: 1000,
|
||||
inventory: "{\"items\":[]}".to_string(),
|
||||
stats: "{\"level\":1}".to_string(),
|
||||
skills: "{\"skills\":[]}".to_string(),
|
||||
looks: "{\"race\":0}".to_string(),
|
||||
position: "{\"x\":0,\"y\":0,\"z\":0}".to_string(),
|
||||
deleted_at: "".to_string(),
|
||||
},
|
||||
character_service::database::Character {
|
||||
id: 2,
|
||||
user_id: "test_user".to_string(),
|
||||
name: "Character2".to_string(),
|
||||
money: 2000,
|
||||
inventory: "{\"items\":[]}".to_string(),
|
||||
stats: "{\"level\":5}".to_string(),
|
||||
skills: "{\"skills\":[]}".to_string(),
|
||||
looks: "{\"race\":1}".to_string(),
|
||||
position: "{\"x\":10,\"y\":10,\"z\":0}".to_string(),
|
||||
deleted_at: "".to_string(),
|
||||
},
|
||||
],
|
||||
})
|
||||
});
|
||||
|
||||
// Create a wrapper struct that implements CharacterDbClient
|
||||
struct MockWrapper(MockCharacterDbClientTrait);
|
||||
impl std::ops::Deref for MockWrapper {
|
||||
type Target = MockCharacterDbClientTrait;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
impl std::ops::DerefMut for MockWrapper {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
impl Clone for MockWrapper {
|
||||
fn clone(&self) -> Self {
|
||||
panic!("Mock should not be cloned")
|
||||
}
|
||||
}
|
||||
|
||||
// Create the service with the mock client
|
||||
let service = MyCharacterService {
|
||||
character_db_client: Arc::new(MockWrapper(mock_client)),
|
||||
};
|
||||
|
||||
// Create a request
|
||||
let request = Request::new(GetCharacterListRequest {
|
||||
user_id: "test_user".to_string(),
|
||||
});
|
||||
|
||||
// Call the service method
|
||||
let response = service.get_character_list(request).await.unwrap();
|
||||
let response = response.into_inner();
|
||||
|
||||
// Verify the response
|
||||
assert_eq!(response.characters.len(), 2);
|
||||
assert_eq!(response.characters[0].name, "Character1");
|
||||
assert_eq!(response.characters[1].name, "Character2");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_character() {
|
||||
// Create a mock CharacterDbClient
|
||||
let mut mock_client = MockCharacterDbClientTrait::new();
|
||||
|
||||
// Set up expectations
|
||||
mock_client
|
||||
.expect_create_character()
|
||||
.with(eq("test_user"), eq("NewCharacter"), eq(0), eq(1), eq(2), eq(3))
|
||||
.times(1)
|
||||
.returning(|_, _, _, _, _, _| {
|
||||
Ok(character_service::database::CreateCharacterResponse {
|
||||
result: 0,
|
||||
character_id: 3,
|
||||
})
|
||||
});
|
||||
|
||||
// Create the service with the mock client
|
||||
let service = MyCharacterService {
|
||||
character_db_client: Arc::new(MockWrapper(mock_client)),
|
||||
};
|
||||
|
||||
// Create a request
|
||||
let request = Request::new(CreateCharacterRequest {
|
||||
user_id: "test_user".to_string(),
|
||||
name: "NewCharacter".to_string(),
|
||||
race: 0,
|
||||
face: 1,
|
||||
hair: 2,
|
||||
stone: 3,
|
||||
});
|
||||
|
||||
// Call the service method
|
||||
let response = service.create_character(request).await.unwrap();
|
||||
let response = response.into_inner();
|
||||
|
||||
// Verify the response
|
||||
assert_eq!(response.result, 0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_delete_character() {
|
||||
// Create a mock CharacterDbClient
|
||||
let mut mock_client = MockCharacterDbClientTrait::new();
|
||||
|
||||
// Set up expectations
|
||||
mock_client
|
||||
.expect_delete_character()
|
||||
.with(eq("test_user"), eq("3"), eq(1))
|
||||
.times(1)
|
||||
.returning(|_, _, _| {
|
||||
Ok(character_service::database::DeleteCharacterResponse {
|
||||
remaining_time: 86400, // 24 hours in seconds
|
||||
name: "DeletedCharacter".to_string(),
|
||||
})
|
||||
});
|
||||
|
||||
// Create the service with the mock client
|
||||
let service = MyCharacterService {
|
||||
character_db_client: Arc::new(MockWrapper(mock_client)),
|
||||
};
|
||||
|
||||
// Create a request
|
||||
let request = Request::new(DeleteCharacterRequest {
|
||||
user_id: "test_user".to_string(),
|
||||
char_id: "3".to_string(),
|
||||
delete_type: 1,
|
||||
});
|
||||
|
||||
// Call the service method
|
||||
let response = service.delete_character(request).await.unwrap();
|
||||
let response = response.into_inner();
|
||||
|
||||
// Verify the response
|
||||
assert_eq!(response.remaining_time, 86400);
|
||||
assert_eq!(response.name, "DeletedCharacter");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_get_character() {
|
||||
// Create a mock CharacterDbClient
|
||||
let mut mock_client = MockCharacterDbClientTrait::new();
|
||||
|
||||
// Set up expectations
|
||||
mock_client
|
||||
.expect_get_character()
|
||||
.with(eq("test_user"), eq("1"))
|
||||
.times(1)
|
||||
.returning(|_, _| {
|
||||
Ok(character_service::database::Character {
|
||||
id: 1,
|
||||
user_id: "test_user".to_string(),
|
||||
name: "Character1".to_string(),
|
||||
money: 1000,
|
||||
inventory: "{\"items\":[{\"id\":1,\"count\":10}]}".to_string(),
|
||||
stats: "{\"level\":10,\"hp\":100,\"mp\":50}".to_string(),
|
||||
skills: "{\"skills\":[{\"id\":1,\"level\":5}]}".to_string(),
|
||||
looks: "{\"race\":0,\"face\":1,\"hair\":2}".to_string(),
|
||||
position: "{\"x\":100,\"y\":200,\"z\":0,\"map\":1}".to_string(),
|
||||
deleted_at: "".to_string(),
|
||||
})
|
||||
});
|
||||
|
||||
// Create the service with the mock client
|
||||
let service = MyCharacterService {
|
||||
character_db_client: Arc::new(MockWrapper(mock_client)),
|
||||
};
|
||||
|
||||
// Create a request
|
||||
let request = Request::new(GetCharacterRequest {
|
||||
user_id: "test_user".to_string(),
|
||||
char_id: "1".to_string(),
|
||||
});
|
||||
|
||||
// Call the service method
|
||||
let response = service.get_character(request).await.unwrap();
|
||||
let response = response.into_inner();
|
||||
|
||||
// Verify the response
|
||||
let character = response.character.unwrap();
|
||||
assert_eq!(character.name, "Character1");
|
||||
assert_eq!(character.money, 1000);
|
||||
|
||||
// Verify JSON fields were parsed correctly
|
||||
assert!(character.inventory.contains("items"));
|
||||
assert!(character.stats.contains("level"));
|
||||
assert!(character.skills.contains("skills"));
|
||||
assert!(character.looks.contains("race"));
|
||||
assert!(character.position.contains("map"));
|
||||
}
|
||||
Reference in New Issue
Block a user