feat(handler): add app
This commit is contained in:
93
tests/app_lifecycle_smoke.rs
Normal file
93
tests/app_lifecycle_smoke.rs
Normal file
@@ -0,0 +1,93 @@
|
||||
use iam_service::models::{CreateAppRequest, ListAppsQuery, RequestAppStatusChangeRequest, UpdateAppRequest};
|
||||
use iam_service::services::AppService;
|
||||
use sqlx::PgPool;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[tokio::test]
|
||||
async fn app_lifecycle_create_update_disable_approve_delete()
|
||||
-> Result<(), Box<dyn std::error::Error>> {
|
||||
let database_url = match std::env::var("DATABASE_URL") {
|
||||
Ok(v) if !v.trim().is_empty() => v,
|
||||
_ => return Ok(()),
|
||||
};
|
||||
|
||||
let pool = PgPool::connect(&database_url).await?;
|
||||
let service = AppService::new(pool.clone());
|
||||
let actor = Uuid::new_v4();
|
||||
|
||||
let app_id = format!("app{}", Uuid::new_v4().to_string().replace('-', ""));
|
||||
let app_id = &app_id[..std::cmp::min(32, app_id.len())];
|
||||
let app_id = app_id.to_string();
|
||||
|
||||
let created = service
|
||||
.create_app(
|
||||
CreateAppRequest {
|
||||
id: app_id.clone(),
|
||||
name: "Test App".to_string(),
|
||||
description: Some("desc".to_string()),
|
||||
app_type: "product".to_string(),
|
||||
owner: Some("team-a".to_string()),
|
||||
},
|
||||
actor,
|
||||
)
|
||||
.await?;
|
||||
assert_eq!(created.id, app_id);
|
||||
assert_eq!(created.status, "active");
|
||||
|
||||
let updated = service
|
||||
.update_app(
|
||||
&app_id,
|
||||
UpdateAppRequest {
|
||||
name: Some("Test App 2".to_string()),
|
||||
description: None,
|
||||
app_type: None,
|
||||
owner: Some("team-b".to_string()),
|
||||
},
|
||||
actor,
|
||||
)
|
||||
.await?;
|
||||
assert_eq!(updated.name, "Test App 2");
|
||||
assert_eq!(updated.owner.as_deref(), Some("team-b"));
|
||||
|
||||
let req = service
|
||||
.request_status_change(
|
||||
&app_id,
|
||||
RequestAppStatusChangeRequest {
|
||||
to_status: "disabled".to_string(),
|
||||
effective_at: None,
|
||||
reason: Some("test".to_string()),
|
||||
},
|
||||
actor,
|
||||
)
|
||||
.await?;
|
||||
assert_eq!(req.status, "pending");
|
||||
|
||||
let approved = service
|
||||
.approve_status_change(req.id, None, actor)
|
||||
.await?;
|
||||
assert!(approved.status == "approved" || approved.status == "applied");
|
||||
|
||||
let got = service.get_app(&app_id).await?;
|
||||
assert_eq!(got.status, "disabled");
|
||||
|
||||
let list = service
|
||||
.list_apps(ListAppsQuery {
|
||||
page: Some(1),
|
||||
page_size: Some(50),
|
||||
status: Some("disabled".to_string()),
|
||||
app_type: None,
|
||||
sort_by: Some("id".to_string()),
|
||||
sort_order: Some("asc".to_string()),
|
||||
created_from: None,
|
||||
created_to: None,
|
||||
})
|
||||
.await?;
|
||||
assert!(list.iter().any(|a| a.id == app_id));
|
||||
|
||||
service.delete_app(&app_id, actor).await?;
|
||||
let got2 = service.get_app(&app_id).await?;
|
||||
assert_eq!(got2.status, "deleted");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
139
tests/password_reset_smoke.rs
Normal file
139
tests/password_reset_smoke.rs
Normal file
@@ -0,0 +1,139 @@
|
||||
use iam_service::models::{CreateUserRequest, LoginRequest};
|
||||
use iam_service::services::{AuthService, TenantService, UserService};
|
||||
use sqlx::PgPool;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[tokio::test]
|
||||
async fn password_reset_self_and_admin_flow()
|
||||
-> Result<(), Box<dyn std::error::Error>> {
|
||||
let database_url = match std::env::var("DATABASE_URL") {
|
||||
Ok(v) if !v.trim().is_empty() => v,
|
||||
_ => return Ok(()),
|
||||
};
|
||||
|
||||
let pool = PgPool::connect(&database_url).await?;
|
||||
|
||||
let has_users: Option<String> = sqlx::query_scalar("SELECT to_regclass('public.users')::text")
|
||||
.fetch_one(&pool)
|
||||
.await?;
|
||||
let has_refresh_tokens: Option<String> =
|
||||
sqlx::query_scalar("SELECT to_regclass('public.refresh_tokens')::text")
|
||||
.fetch_one(&pool)
|
||||
.await?;
|
||||
if has_users.is_none() || has_refresh_tokens.is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let tenant_service = TenantService::new(pool.clone());
|
||||
let user_service = UserService::new(pool.clone());
|
||||
let auth_service = AuthService::new(pool.clone(), "unused".to_string());
|
||||
|
||||
let tenant = tenant_service
|
||||
.create_tenant(iam_service::models::CreateTenantRequest {
|
||||
name: format!("pwreset-{}", Uuid::new_v4()),
|
||||
config: None,
|
||||
})
|
||||
.await?;
|
||||
|
||||
let admin = auth_service
|
||||
.register(
|
||||
tenant.id,
|
||||
CreateUserRequest {
|
||||
email: format!("admin-{}@example.com", Uuid::new_v4()),
|
||||
password: "AdminOldPassword123".to_string(),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
let user = auth_service
|
||||
.register(
|
||||
tenant.id,
|
||||
CreateUserRequest {
|
||||
email: format!("user-{}@example.com", Uuid::new_v4()),
|
||||
password: "UserOldPassword123".to_string(),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
let login1 = auth_service
|
||||
.login(
|
||||
tenant.id,
|
||||
LoginRequest {
|
||||
email: user.email.clone(),
|
||||
password: "UserOldPassword123".to_string(),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
let active_tokens: i64 =
|
||||
sqlx::query_scalar("SELECT COUNT(1) FROM refresh_tokens WHERE user_id = $1 AND is_revoked = FALSE")
|
||||
.bind(user.id)
|
||||
.fetch_one(&pool)
|
||||
.await?;
|
||||
assert!(active_tokens >= 1);
|
||||
|
||||
user_service
|
||||
.reset_my_password(
|
||||
tenant.id,
|
||||
user.id,
|
||||
"UserOldPassword123".to_string(),
|
||||
"UserNewPassword456".to_string(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let revoked_tokens: i64 =
|
||||
sqlx::query_scalar("SELECT COUNT(1) FROM refresh_tokens WHERE user_id = $1 AND is_revoked = TRUE")
|
||||
.bind(user.id)
|
||||
.fetch_one(&pool)
|
||||
.await?;
|
||||
assert!(revoked_tokens >= 1);
|
||||
|
||||
let old_login = auth_service
|
||||
.login(
|
||||
tenant.id,
|
||||
LoginRequest {
|
||||
email: user.email.clone(),
|
||||
password: "UserOldPassword123".to_string(),
|
||||
},
|
||||
)
|
||||
.await;
|
||||
assert!(old_login.is_err());
|
||||
|
||||
let _new_login = auth_service
|
||||
.login(
|
||||
tenant.id,
|
||||
LoginRequest {
|
||||
email: user.email.clone(),
|
||||
password: "UserNewPassword456".to_string(),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
let temp = user_service
|
||||
.reset_user_password_as_admin(tenant.id, admin.id, user.id, Some(24))
|
||||
.await?;
|
||||
assert!(temp.len() >= 16 && temp.len() <= 64);
|
||||
|
||||
let old2 = auth_service
|
||||
.login(
|
||||
tenant.id,
|
||||
LoginRequest {
|
||||
email: user.email.clone(),
|
||||
password: "UserNewPassword456".to_string(),
|
||||
},
|
||||
)
|
||||
.await;
|
||||
assert!(old2.is_err());
|
||||
|
||||
let _temp_login = auth_service
|
||||
.login(
|
||||
tenant.id,
|
||||
LoginRequest {
|
||||
email: user.email.clone(),
|
||||
password: temp.clone(),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
let _ = login1;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user