- update: database client to implement a database trait so we can mock it out
- update unit tests - add: database client mock
This commit is contained in:
@@ -1,18 +1,28 @@
|
||||
use std::error::Error;
|
||||
use tonic::transport::Channel;
|
||||
use crate::database::{database_service_client::DatabaseServiceClient, GetUserByUsernameRequest, GetUserRequest, GetUserResponse};
|
||||
use crate::database::{database_service_client::DatabaseServiceClient, CreateUserRequest, CreateUserResponse, GetUserByUsernameRequest, GetUserRequest, GetUserResponse};
|
||||
use async_trait::async_trait;
|
||||
|
||||
#[async_trait]
|
||||
pub trait DatabaseClientTrait: Sized {
|
||||
async fn connect(endpoint: &str) -> Result<Self, Box<dyn std::error::Error>>;
|
||||
async fn get_user_by_userid(&mut self, user_id: i32) -> Result<GetUserResponse, Box<dyn std::error::Error>>;
|
||||
async fn get_user_by_username(&mut self, user_id: &str) -> Result<GetUserResponse, Box<dyn std::error::Error>>;
|
||||
async fn create_user(&mut self, username: &str, email: &str, password: &str) -> Result<CreateUserResponse, Box<dyn std::error::Error>>;
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub struct DatabaseClient {
|
||||
client: DatabaseServiceClient<Channel>,
|
||||
}
|
||||
|
||||
impl DatabaseClient {
|
||||
pub async fn connect(endpoint: &str) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
#[async_trait]
|
||||
impl DatabaseClientTrait for DatabaseClient {
|
||||
async fn connect(endpoint: &str) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let client = DatabaseServiceClient::connect(endpoint.to_string()).await?;
|
||||
Ok(Self { client })
|
||||
}
|
||||
|
||||
pub async fn get_user_by_userid(
|
||||
async fn get_user_by_userid(
|
||||
&mut self,
|
||||
user_id: i32,
|
||||
) -> Result<GetUserResponse, Box<dyn std::error::Error>> {
|
||||
@@ -23,7 +33,7 @@ impl DatabaseClient {
|
||||
Ok(response.into_inner())
|
||||
}
|
||||
|
||||
pub async fn get_user_by_username(
|
||||
async fn get_user_by_username(
|
||||
&mut self,
|
||||
username: &str,
|
||||
) -> Result<GetUserResponse, Box<dyn std::error::Error>> {
|
||||
@@ -33,4 +43,14 @@ impl DatabaseClient {
|
||||
let response = self.client.get_user_by_username(request).await?;
|
||||
Ok(response.into_inner())
|
||||
}
|
||||
|
||||
async fn create_user(&mut self, username: &str, email: &str, password: &str) -> Result<CreateUserResponse, Box<dyn Error>> {
|
||||
let request = tonic::Request::new(CreateUserRequest {
|
||||
username: username.to_string(),
|
||||
email: email.to_string(),
|
||||
hashed_password: password.to_string(),
|
||||
});
|
||||
let response = self.client.create_user(request).await?;
|
||||
Ok(response.into_inner())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
use tonic::{Request, Response, Status};
|
||||
use crate::jwt::{generate_token, validate_token};
|
||||
use crate::users::verify_user;
|
||||
use crate::database_client::DatabaseClient;
|
||||
use crate::database_client::{DatabaseClient, DatabaseClientTrait};
|
||||
use crate::auth::auth_service_server::{AuthService};
|
||||
use crate::auth::{LoginRequest, LoginResponse, ValidateTokenRequest, ValidateTokenResponse};
|
||||
use tracing::{info, warn};
|
||||
|
||||
pub struct MyAuthService {
|
||||
pub db_client: DatabaseClient,
|
||||
pub struct MyAuthService<T: DatabaseClientTrait + Clone> {
|
||||
pub db_client: T,
|
||||
}
|
||||
|
||||
#[tonic::async_trait]
|
||||
impl AuthService for MyAuthService {
|
||||
impl<T: DatabaseClientTrait + Send + Sync + Clone + 'static> AuthService for MyAuthService<T> {
|
||||
async fn login(
|
||||
&self,
|
||||
request: Request<LoginRequest>,
|
||||
|
||||
@@ -8,4 +8,7 @@ pub mod auth {
|
||||
}
|
||||
pub mod database {
|
||||
tonic::include_proto!("database"); // Matches package name in database.proto
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod mocks;
|
||||
@@ -3,6 +3,7 @@ use std::env;
|
||||
use tonic::transport::Server;
|
||||
use auth_service::grpc::MyAuthService;
|
||||
use auth_service::database_client::DatabaseClient;
|
||||
use auth_service::database_client::DatabaseClientTrait;
|
||||
use auth_service::auth::auth_service_server::AuthServiceServer;
|
||||
|
||||
pub mod auth {
|
||||
|
||||
23
auth-service/src/mocks/database_client_mock.rs
Normal file
23
auth-service/src/mocks/database_client_mock.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
use mockall::{mock, predicate::*};
|
||||
use async_trait::async_trait;
|
||||
use crate::database::{CreateUserResponse, GetUserResponse};
|
||||
use crate::database_client::{DatabaseClientTrait};
|
||||
|
||||
#[cfg(test)]
|
||||
mock! {
|
||||
pub DatabaseClient {}
|
||||
|
||||
#[async_trait]
|
||||
impl DatabaseClientTrait for DatabaseClient {
|
||||
async fn connect(endpoint: &str) -> Result<Self, Box<dyn std::error::Error>>;
|
||||
async fn get_user_by_userid(&mut self, user_id: i32) -> Result<GetUserResponse, Box<dyn std::error::Error>>;
|
||||
async fn get_user_by_username(&mut self, user_id: &str) -> Result<GetUserResponse, Box<dyn std::error::Error>>;
|
||||
async fn create_user(&mut self, username: &str, email: &str, password: &str) -> Result<CreateUserResponse, Box<dyn std::error::Error>>;
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for MockDatabaseClient {
|
||||
fn clone(&self) -> Self {
|
||||
MockDatabaseClient::new() // Create a new mock instance
|
||||
}
|
||||
}
|
||||
2
auth-service/src/mocks/mod.rs
Normal file
2
auth-service/src/mocks/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
#[cfg(test)]
|
||||
pub mod database_client_mock;
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::database_client::DatabaseClient;
|
||||
use crate::database_client::{DatabaseClient, DatabaseClientTrait};
|
||||
|
||||
use argon2::{
|
||||
password_hash::{
|
||||
@@ -19,7 +19,7 @@ pub fn verify_password(password: &str, hash: &str) -> bool {
|
||||
Argon2::default().verify_password(password.as_bytes(), &parsed_hash).is_ok()
|
||||
}
|
||||
|
||||
pub async fn verify_user(mut db_client: DatabaseClient,
|
||||
pub async fn verify_user<T: DatabaseClientTrait>(mut db_client: T,
|
||||
username: &str, password: &str) -> Option<String> {
|
||||
// Placeholder: Replace with a gRPC call to the Database Service
|
||||
let user = db_client.get_user_by_username(username).await.ok()?;
|
||||
|
||||
Reference in New Issue
Block a user