feat: fixing role and auth test
This commit is contained in:
@@ -143,8 +143,8 @@ async fn test_register_should_succeed() {
|
|||||||
"fullname": "Valid User",
|
"fullname": "Valid User",
|
||||||
"student_type": "regular",
|
"student_type": "regular",
|
||||||
"phone_number": "0812345678",
|
"phone_number": "0812345678",
|
||||||
"reffered_by": "Facebook",
|
"reffered_by": "Facebook",
|
||||||
"refferal_code": "KFNB"
|
"refferal_code": "KFNB"
|
||||||
});
|
});
|
||||||
let res = server.post("/v1/auth/register").json(&payload).await;
|
let res = server.post("/v1/auth/register").json(&payload).await;
|
||||||
assert_eq!(res.status_code(), StatusCode::CREATED);
|
assert_eq!(res.status_code(), StatusCode::CREATED);
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ pub fn create_test_app(state: AppState) -> TestServer {
|
|||||||
TestServer::new(app).unwrap()
|
TestServer::new(app).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn delete_dummy_role(state: AppState, id: String) {
|
||||||
|
let repo = RolesRepository::new(&state);
|
||||||
|
let _ = repo.query_delete_role(id).await;
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_get_role_list_should_return_200() {
|
async fn test_get_role_list_should_return_200() {
|
||||||
let state = create_mock_app_state().await;
|
let state = create_mock_app_state().await;
|
||||||
@@ -35,11 +40,18 @@ async fn test_post_create_role_should_return_201() {
|
|||||||
.layer(axum::Extension(state.clone()));
|
.layer(axum::Extension(state.clone()));
|
||||||
let server = TestServer::new(app).unwrap();
|
let server = TestServer::new(app).unwrap();
|
||||||
let payload = RolesRequestCreateDto {
|
let payload = RolesRequestCreateDto {
|
||||||
name: "Test Role".into(),
|
name: "Test Role #1".into(),
|
||||||
permissions: vec![],
|
permissions: vec![],
|
||||||
};
|
};
|
||||||
let res = server.post("/v1/roles/create").json(&payload).await;
|
let res = server.post("/v1/roles/create").json(&payload).await;
|
||||||
|
let repo = RolesRepository::new(&state);
|
||||||
assert_eq!(res.status_code(), StatusCode::CREATED);
|
assert_eq!(res.status_code(), StatusCode::CREATED);
|
||||||
|
let id = repo
|
||||||
|
.query_role_by_name(payload.name.clone())
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.id;
|
||||||
|
delete_dummy_role(state, id).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -58,7 +70,7 @@ async fn test_put_update_role_should_return_200() {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let id = existing.id.clone();
|
let id = existing.id.clone();
|
||||||
let server = create_test_app(state);
|
let server = create_test_app(state.clone());
|
||||||
let payload = RolesRequestUpdateDto {
|
let payload = RolesRequestUpdateDto {
|
||||||
name: Some("Updated Role".into()),
|
name: Some("Updated Role".into()),
|
||||||
permissions: Some(vec![]),
|
permissions: Some(vec![]),
|
||||||
@@ -69,6 +81,12 @@ async fn test_put_update_role_should_return_200() {
|
|||||||
.await;
|
.await;
|
||||||
dbg!(res.text());
|
dbg!(res.text());
|
||||||
assert_eq!(res.status_code(), StatusCode::OK);
|
assert_eq!(res.status_code(), StatusCode::OK);
|
||||||
|
let id = repo
|
||||||
|
.query_role_by_name(payload.name.clone().unwrap())
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.id;
|
||||||
|
delete_dummy_role(state.clone(), id).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -92,3 +110,71 @@ async fn test_delete_role_should_return_200() {
|
|||||||
dbg!(res.text());
|
dbg!(res.text());
|
||||||
assert_eq!(res.status_code(), StatusCode::OK);
|
assert_eq!(res.status_code(), StatusCode::OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_post_create_role_with_empty_name_should_return_400() {
|
||||||
|
let state = create_mock_app_state().await;
|
||||||
|
let server = create_test_app(state);
|
||||||
|
let payload = RolesRequestCreateDto {
|
||||||
|
name: "".into(),
|
||||||
|
permissions: vec![],
|
||||||
|
};
|
||||||
|
let res = server.post("/v1/roles/create").json(&payload).await;
|
||||||
|
dbg!(res.text());
|
||||||
|
assert_eq!(res.status_code(), StatusCode::BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_put_update_nonexistent_role_should_return_404() {
|
||||||
|
let state = create_mock_app_state().await;
|
||||||
|
let server = create_test_app(state);
|
||||||
|
let payload = RolesRequestUpdateDto {
|
||||||
|
name: Some("Does Not Exist".into()),
|
||||||
|
permissions: Some(vec![]),
|
||||||
|
};
|
||||||
|
let res = server
|
||||||
|
.put("/v1/roles/update/nonexistent-id")
|
||||||
|
.json(&payload)
|
||||||
|
.await;
|
||||||
|
dbg!(res.text());
|
||||||
|
assert_eq!(res.status_code(), StatusCode::NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_delete_nonexistent_role_should_return_404() {
|
||||||
|
let state = create_mock_app_state().await;
|
||||||
|
let server = create_test_app(state);
|
||||||
|
let res = server.delete("/v1/roles/delete/nonexistent-id").await;
|
||||||
|
dbg!(res.text());
|
||||||
|
assert_eq!(res.status_code(), StatusCode::NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_get_role_list_with_invalid_page_params_should_return_400() {
|
||||||
|
let state = create_mock_app_state().await;
|
||||||
|
let server = create_test_app(state);
|
||||||
|
let res = server.get("/v1/roles?page=abc&per_page=xyz").await;
|
||||||
|
dbg!(res.text());
|
||||||
|
assert_eq!(res.status_code(), StatusCode::BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_create_duplicate_role_should_return_409() {
|
||||||
|
let state = create_mock_app_state().await;
|
||||||
|
let repo = RolesRepository::new(&state);
|
||||||
|
let _ = repo
|
||||||
|
.query_create_role(RolesRequestCreateDto {
|
||||||
|
name: "Admin".into(),
|
||||||
|
permissions: vec![],
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
let server = create_test_app(state);
|
||||||
|
let payload = RolesRequestCreateDto {
|
||||||
|
name: "Admin".into(),
|
||||||
|
permissions: vec![],
|
||||||
|
};
|
||||||
|
let res = server.post("/v1/roles/create").json(&payload).await;
|
||||||
|
dbg!(res.text());
|
||||||
|
assert_eq!(res.status_code(), StatusCode::CONFLICT);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
use crate::PermissionsItemDto;
|
use crate::PermissionsItemDto;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
|
use validator::Validate;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
|
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)]
|
||||||
pub struct RolesRequestUpdateDto {
|
pub struct RolesRequestUpdateDto {
|
||||||
|
#[validate(length(min = 1, message = "Role name must not be empty"))]
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub permissions: Option<Vec<String>>,
|
pub permissions: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema)]
|
#[derive(Clone, Debug, Serialize, Deserialize, ToSchema, Validate)]
|
||||||
pub struct RolesRequestCreateDto {
|
pub struct RolesRequestCreateDto {
|
||||||
|
#[validate(length(min = 1, message = "Role name must not be empty"))]
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub permissions: Vec<String>,
|
pub permissions: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,14 @@
|
|||||||
use crate::{
|
|
||||||
common_response, success_list_response, success_response, AppState,
|
|
||||||
MetaRequestDto, ResponseListSuccessDto, ResponseSuccessDto,
|
|
||||||
};
|
|
||||||
use axum::http::StatusCode;
|
|
||||||
|
|
||||||
use super::{RolesRepository, RolesRequestCreateDto, RolesRequestUpdateDto};
|
use super::{RolesRepository, RolesRequestCreateDto, RolesRequestUpdateDto};
|
||||||
|
use crate::{
|
||||||
|
common_response, success_list_response, success_response, validate_request,
|
||||||
|
AppState, MetaRequestDto, ResponseListSuccessDto, ResponseSuccessDto,
|
||||||
|
};
|
||||||
|
use axum::{http::StatusCode, response::Response};
|
||||||
|
|
||||||
pub struct RolesService;
|
pub struct RolesService;
|
||||||
|
|
||||||
impl RolesService {
|
impl RolesService {
|
||||||
pub async fn get_role_list(
|
pub async fn get_role_list(state: &AppState, meta: MetaRequestDto) -> Response {
|
||||||
state: &AppState,
|
|
||||||
meta: MetaRequestDto,
|
|
||||||
) -> axum::response::Response {
|
|
||||||
let repo = RolesRepository::new(state);
|
let repo = RolesRepository::new(state);
|
||||||
match repo.query_role_list(meta).await {
|
match repo.query_role_list(meta).await {
|
||||||
Ok(data) => {
|
Ok(data) => {
|
||||||
@@ -26,10 +22,7 @@ impl RolesService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_role_by_id(
|
pub async fn get_role_by_id(state: &AppState, id: String) -> Response {
|
||||||
state: &AppState,
|
|
||||||
id: String,
|
|
||||||
) -> axum::response::Response {
|
|
||||||
let repo = RolesRepository::new(state);
|
let repo = RolesRepository::new(state);
|
||||||
match repo.query_role_by_id(id).await {
|
match repo.query_role_by_id(id).await {
|
||||||
Ok(role) => success_response(ResponseSuccessDto { data: role }),
|
Ok(role) => success_response(ResponseSuccessDto { data: role }),
|
||||||
@@ -40,8 +33,20 @@ impl RolesService {
|
|||||||
pub async fn create_role(
|
pub async fn create_role(
|
||||||
state: &AppState,
|
state: &AppState,
|
||||||
payload: RolesRequestCreateDto,
|
payload: RolesRequestCreateDto,
|
||||||
) -> axum::response::Response {
|
) -> Response {
|
||||||
|
if let Err((status, message)) = validate_request(&payload) {
|
||||||
|
return common_response(status, &message);
|
||||||
|
}
|
||||||
let repo = RolesRepository::new(state);
|
let repo = RolesRepository::new(state);
|
||||||
|
match repo.query_role_by_name(payload.name.clone()).await {
|
||||||
|
Ok(_role) => {
|
||||||
|
return common_response(StatusCode::CONFLICT, "Role name already exists");
|
||||||
|
}
|
||||||
|
Err(err) if err.to_string().contains("not found") => {}
|
||||||
|
Err(e) => {
|
||||||
|
return common_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
match repo.query_create_role(payload).await {
|
match repo.query_create_role(payload).await {
|
||||||
Ok(msg) => common_response(StatusCode::CREATED, &msg),
|
Ok(msg) => common_response(StatusCode::CREATED, &msg),
|
||||||
Err(e) => common_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
|
Err(e) => common_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string()),
|
||||||
@@ -52,19 +57,53 @@ impl RolesService {
|
|||||||
state: &AppState,
|
state: &AppState,
|
||||||
id: String,
|
id: String,
|
||||||
payload: RolesRequestUpdateDto,
|
payload: RolesRequestUpdateDto,
|
||||||
) -> axum::response::Response {
|
) -> Response {
|
||||||
|
if let Err((status, message)) = validate_request(&payload) {
|
||||||
|
return common_response(status, &message);
|
||||||
|
}
|
||||||
let repo = RolesRepository::new(state);
|
let repo = RolesRepository::new(state);
|
||||||
|
let existing_role = match repo.query_role_by_id(id.clone()).await {
|
||||||
|
Ok(role) => role,
|
||||||
|
Err(err) if err.to_string().contains("not found") => {
|
||||||
|
return common_response(StatusCode::NOT_FOUND, "Role not found");
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return common_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(new_name) = payload.name.clone() {
|
||||||
|
match repo.query_role_by_name(new_name.clone()).await {
|
||||||
|
Ok(role_with_same_name) => {
|
||||||
|
if role_with_same_name.id != existing_role.id {
|
||||||
|
return common_response(
|
||||||
|
StatusCode::CONFLICT,
|
||||||
|
"Role name already exists",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) if err.to_string().contains("not found") => {}
|
||||||
|
Err(e) => {
|
||||||
|
return common_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
match repo.query_update_role(id, payload).await {
|
match repo.query_update_role(id, payload).await {
|
||||||
Ok(msg) => common_response(StatusCode::OK, &msg),
|
Ok(msg) => common_response(StatusCode::OK, &msg),
|
||||||
Err(e) => common_response(StatusCode::BAD_REQUEST, &e.to_string()),
|
Err(e) => common_response(StatusCode::BAD_REQUEST, &e.to_string()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_role(
|
pub async fn delete_role(state: &AppState, id: String) -> Response {
|
||||||
state: &AppState,
|
|
||||||
id: String,
|
|
||||||
) -> axum::response::Response {
|
|
||||||
let repo = RolesRepository::new(state);
|
let repo = RolesRepository::new(state);
|
||||||
|
match repo.query_role_by_id(id.clone()).await {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(err) if err.to_string().contains("not found") => {
|
||||||
|
return common_response(StatusCode::NOT_FOUND, "Role not found");
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return common_response(StatusCode::INTERNAL_SERVER_ERROR, &e.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
match repo.query_delete_role(id).await {
|
match repo.query_delete_role(id).await {
|
||||||
Ok(msg) => common_response(StatusCode::OK, &msg),
|
Ok(msg) => common_response(StatusCode::OK, &msg),
|
||||||
Err(e) => common_response(StatusCode::BAD_REQUEST, &e.to_string()),
|
Err(e) => common_response(StatusCode::BAD_REQUEST, &e.to_string()),
|
||||||
|
|||||||
Reference in New Issue
Block a user