2025-04-08 06:14:55 +08:00
|
|
|
use anyhow::Result;
|
|
|
|
use database::enums::{AssetPermissionRole, AssetType, UserOrganizationRole, Verification};
|
2025-04-08 06:43:00 +08:00
|
|
|
use database::models::MetricFile;
|
|
|
|
use database::pool::init_pools;
|
2025-04-08 06:14:55 +08:00
|
|
|
use database::schema::metric_files;
|
|
|
|
use diesel::prelude::*;
|
|
|
|
use diesel_async::RunQueryDsl;
|
|
|
|
use handlers::metrics::update_metric_handler::{update_metric_handler, UpdateMetricRequest};
|
2025-04-08 06:43:00 +08:00
|
|
|
use middleware::AuthenticatedUser;
|
2025-04-08 06:28:17 +08:00
|
|
|
use std::sync::Once;
|
2025-04-08 06:14:55 +08:00
|
|
|
use uuid::Uuid;
|
|
|
|
|
2025-04-08 06:43:00 +08:00
|
|
|
static INIT: Once = Once::new();
|
|
|
|
|
|
|
|
async fn init_db_pool() -> Result<()> {
|
|
|
|
INIT.call_once(|| {
|
|
|
|
// We'll just initialize the INIT variable
|
|
|
|
// The connection pool should already be initialized in the test environment
|
|
|
|
println!("Database initialized for test");
|
2025-04-08 06:32:54 +08:00
|
|
|
});
|
2025-04-08 06:43:00 +08:00
|
|
|
|
|
|
|
Ok(())
|
2025-04-08 06:28:17 +08:00
|
|
|
}
|
|
|
|
|
2025-04-08 06:43:00 +08:00
|
|
|
// Mock test setup for handlers tests
|
2025-04-08 06:18:58 +08:00
|
|
|
struct TestSetup {
|
|
|
|
pub user: AuthenticatedUser,
|
2025-04-08 06:43:00 +08:00
|
|
|
pub organization: database::models::Organization,
|
|
|
|
pub db: TestDb,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TestSetup {
|
|
|
|
pub async fn new(role: Option<UserOrganizationRole>) -> Result<Self> {
|
|
|
|
let db = TestDb::new().await?;
|
|
|
|
|
|
|
|
// Create organization
|
|
|
|
let organization = database::models::Organization {
|
|
|
|
id: db.organization_id,
|
|
|
|
name: format!("Test Org {}", Uuid::new_v4()),
|
|
|
|
domain: Some("test.example.com".to_string()),
|
|
|
|
created_at: chrono::Utc::now(),
|
|
|
|
updated_at: chrono::Utc::now(),
|
|
|
|
deleted_at: None,
|
2025-04-30 00:37:37 +08:00
|
|
|
payment_required: false,
|
2025-04-08 06:43:00 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
// Create user with specified role
|
|
|
|
let user_role = role.unwrap_or(UserOrganizationRole::WorkspaceAdmin);
|
|
|
|
let now = chrono::Utc::now();
|
|
|
|
|
|
|
|
let user = AuthenticatedUser {
|
|
|
|
id: db.user_id,
|
|
|
|
email: format!("test-user-{}@example.com", Uuid::new_v4()),
|
|
|
|
name: Some(format!("Test User {}", Uuid::new_v4())),
|
|
|
|
config: serde_json::json!({}),
|
|
|
|
created_at: now,
|
|
|
|
updated_at: now,
|
|
|
|
attributes: serde_json::json!({}),
|
|
|
|
avatar_url: None,
|
|
|
|
organizations: vec![
|
|
|
|
middleware::types::OrganizationMembership {
|
|
|
|
id: db.organization_id,
|
|
|
|
role: user_role,
|
|
|
|
}
|
|
|
|
],
|
|
|
|
teams: vec![],
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(Self {
|
|
|
|
user,
|
|
|
|
organization,
|
|
|
|
db,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Simple test database setup
|
|
|
|
struct TestDb {
|
2025-04-08 06:18:58 +08:00
|
|
|
pub test_id: String,
|
2025-04-08 06:43:00 +08:00
|
|
|
pub organization_id: Uuid,
|
|
|
|
pub user_id: Uuid,
|
2025-04-08 06:18:11 +08:00
|
|
|
}
|
|
|
|
|
2025-04-08 06:43:00 +08:00
|
|
|
impl TestDb {
|
|
|
|
pub async fn new() -> Result<Self> {
|
|
|
|
let test_id = format!("test-{}", Uuid::new_v4());
|
|
|
|
let organization_id = Uuid::new_v4();
|
|
|
|
let user_id = Uuid::new_v4();
|
2025-04-08 06:27:51 +08:00
|
|
|
|
2025-04-08 06:43:00 +08:00
|
|
|
Ok(Self {
|
|
|
|
test_id,
|
|
|
|
organization_id,
|
|
|
|
user_id,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn diesel_conn(&self) -> Result<diesel_async::pooled_connection::bb8::PooledConnection<'_, diesel_async::AsyncPgConnection>> {
|
|
|
|
database::pool::get_pg_pool()
|
|
|
|
.get()
|
|
|
|
.await
|
|
|
|
.map_err(|e| anyhow::anyhow!("Failed to get database connection: {}", e))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn cleanup(&self) -> Result<()> {
|
|
|
|
// In a real environment, this would clean up test data
|
|
|
|
// For our tests, we'll handle cleanup manually in each test
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unit test to verify the verification field is properly handled
|
|
|
|
#[test]
|
|
|
|
fn test_verification_in_update_request() {
|
|
|
|
// Create a simple update request with verification field set
|
|
|
|
let request = UpdateMetricRequest {
|
|
|
|
verification: Some(Verification::Verified),
|
|
|
|
..Default::default()
|
2025-04-08 06:27:51 +08:00
|
|
|
};
|
|
|
|
|
2025-04-08 06:43:00 +08:00
|
|
|
// Verify the verification field is correctly set
|
|
|
|
assert_eq!(request.verification.unwrap(), Verification::Verified);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Integration test for metric status update
|
|
|
|
#[tokio::test]
|
|
|
|
async fn test_update_metric_status() -> Result<()> {
|
|
|
|
// Initialize DB connection pool
|
|
|
|
init_db_pool().await?;
|
2025-04-08 06:27:51 +08:00
|
|
|
|
2025-04-08 06:43:00 +08:00
|
|
|
// Set up test environment with admin user
|
|
|
|
let setup = TestSetup::new(Some(UserOrganizationRole::WorkspaceAdmin)).await?;
|
2025-04-08 06:27:51 +08:00
|
|
|
|
2025-04-08 06:43:00 +08:00
|
|
|
// Create test metric using helpers
|
|
|
|
let test_id = format!("test-{}", Uuid::new_v4());
|
2025-04-08 06:14:55 +08:00
|
|
|
let metric_id = Uuid::new_v4();
|
2025-04-08 06:43:00 +08:00
|
|
|
let mut conn = setup.db.diesel_conn().await?;
|
2025-04-08 06:14:55 +08:00
|
|
|
|
|
|
|
// Create a simple metric with test content
|
|
|
|
let content = database::types::MetricYml {
|
2025-04-08 06:43:00 +08:00
|
|
|
name: format!("Test Metric {}", test_id),
|
|
|
|
description: Some(format!("Test metric description for {}", test_id)),
|
2025-04-08 06:14:55 +08:00
|
|
|
sql: "SELECT * FROM test".to_string(),
|
|
|
|
time_frame: "last 30 days".to_string(),
|
|
|
|
chart_config: create_default_chart_config(),
|
|
|
|
dataset_ids: vec![],
|
|
|
|
};
|
|
|
|
|
|
|
|
// Initial verification status
|
|
|
|
let initial_verification = Verification::NotRequested;
|
|
|
|
|
|
|
|
// Create the test metric file
|
|
|
|
let metric_file = MetricFile {
|
|
|
|
id: metric_id,
|
2025-04-08 06:43:00 +08:00
|
|
|
name: format!("{}-Test Metric", test_id),
|
|
|
|
file_name: format!("{}-test_metric.yml", test_id),
|
2025-04-08 06:14:55 +08:00
|
|
|
content: content.clone(),
|
|
|
|
verification: initial_verification,
|
|
|
|
evaluation_obj: None,
|
|
|
|
evaluation_summary: None,
|
|
|
|
evaluation_score: None,
|
2025-04-08 06:18:11 +08:00
|
|
|
organization_id: setup.organization.id,
|
|
|
|
created_by: setup.user.id,
|
2025-04-08 06:43:00 +08:00
|
|
|
created_at: setup.user.created_at,
|
|
|
|
updated_at: setup.user.updated_at,
|
2025-04-08 06:14:55 +08:00
|
|
|
deleted_at: None,
|
|
|
|
publicly_accessible: false,
|
|
|
|
publicly_enabled_by: None,
|
|
|
|
public_expiry_date: None,
|
|
|
|
version_history: database::types::VersionHistory(std::collections::HashMap::new()),
|
|
|
|
data_metadata: None,
|
|
|
|
public_password: None,
|
|
|
|
};
|
|
|
|
|
|
|
|
// Insert the test metric into the database
|
|
|
|
diesel::insert_into(metric_files::table)
|
|
|
|
.values(&metric_file)
|
|
|
|
.execute(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
2025-04-08 06:43:00 +08:00
|
|
|
// Create test user in the database (required for foreign key constraints)
|
|
|
|
diesel::insert_into(database::schema::organizations::table)
|
|
|
|
.values((
|
|
|
|
database::schema::organizations::id.eq(setup.organization.id),
|
|
|
|
database::schema::organizations::name.eq(&setup.organization.name),
|
|
|
|
database::schema::organizations::domain.eq(setup.organization.domain.as_ref()),
|
|
|
|
database::schema::organizations::created_at.eq(setup.organization.created_at),
|
|
|
|
database::schema::organizations::updated_at.eq(setup.organization.updated_at),
|
|
|
|
database::schema::organizations::deleted_at.eq::<Option<chrono::DateTime<chrono::Utc>>>(None),
|
|
|
|
))
|
|
|
|
.on_conflict_do_nothing()
|
|
|
|
.execute(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
// Create test user
|
|
|
|
diesel::insert_into(database::schema::users::table)
|
|
|
|
.values((
|
|
|
|
database::schema::users::id.eq(setup.user.id),
|
|
|
|
database::schema::users::email.eq(&setup.user.email),
|
|
|
|
database::schema::users::name.eq(setup.user.name.as_ref()),
|
|
|
|
database::schema::users::config.eq(serde_json::json!({})),
|
|
|
|
database::schema::users::created_at.eq(setup.user.created_at),
|
|
|
|
database::schema::users::updated_at.eq(setup.user.updated_at),
|
|
|
|
database::schema::users::attributes.eq(serde_json::json!({})),
|
|
|
|
database::schema::users::avatar_url.eq::<Option<String>>(None),
|
|
|
|
))
|
|
|
|
.on_conflict_do_nothing()
|
|
|
|
.execute(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
// Create user-organization relationship
|
|
|
|
diesel::insert_into(database::schema::users_to_organizations::table)
|
|
|
|
.values((
|
|
|
|
database::schema::users_to_organizations::user_id.eq(setup.user.id),
|
|
|
|
database::schema::users_to_organizations::organization_id.eq(setup.organization.id),
|
|
|
|
database::schema::users_to_organizations::role.eq(setup.user.organizations[0].role),
|
|
|
|
database::schema::users_to_organizations::sharing_setting.eq(database::enums::SharingSetting::None),
|
|
|
|
database::schema::users_to_organizations::edit_sql.eq(true),
|
|
|
|
database::schema::users_to_organizations::upload_csv.eq(true),
|
|
|
|
database::schema::users_to_organizations::export_assets.eq(true),
|
|
|
|
database::schema::users_to_organizations::email_slack_enabled.eq(true),
|
|
|
|
database::schema::users_to_organizations::created_at.eq(setup.user.created_at),
|
|
|
|
database::schema::users_to_organizations::updated_at.eq(setup.user.updated_at),
|
|
|
|
database::schema::users_to_organizations::deleted_at.eq::<Option<chrono::DateTime<chrono::Utc>>>(None),
|
|
|
|
database::schema::users_to_organizations::created_by.eq(setup.user.id),
|
|
|
|
database::schema::users_to_organizations::updated_by.eq(setup.user.id),
|
|
|
|
database::schema::users_to_organizations::deleted_by.eq::<Option<Uuid>>(None),
|
|
|
|
database::schema::users_to_organizations::status.eq(database::enums::UserOrganizationStatus::Active),
|
|
|
|
))
|
|
|
|
.on_conflict_do_nothing()
|
|
|
|
.execute(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
// Now create permission for the user
|
2025-04-08 06:14:55 +08:00
|
|
|
diesel::insert_into(database::schema::asset_permissions::table)
|
|
|
|
.values((
|
2025-04-08 06:18:11 +08:00
|
|
|
database::schema::asset_permissions::identity_id.eq(setup.user.id),
|
2025-04-08 06:14:55 +08:00
|
|
|
database::schema::asset_permissions::identity_type.eq(database::enums::IdentityType::User),
|
|
|
|
database::schema::asset_permissions::asset_id.eq(metric_id),
|
|
|
|
database::schema::asset_permissions::asset_type.eq(AssetType::MetricFile),
|
|
|
|
database::schema::asset_permissions::role.eq(AssetPermissionRole::Owner),
|
2025-04-08 06:43:00 +08:00
|
|
|
database::schema::asset_permissions::created_at.eq(setup.user.created_at),
|
|
|
|
database::schema::asset_permissions::updated_at.eq(setup.user.created_at),
|
2025-04-08 06:14:55 +08:00
|
|
|
database::schema::asset_permissions::deleted_at.eq::<Option<chrono::DateTime<chrono::Utc>>>(None),
|
2025-04-08 06:18:11 +08:00
|
|
|
database::schema::asset_permissions::created_by.eq(setup.user.id),
|
|
|
|
database::schema::asset_permissions::updated_by.eq(setup.user.id),
|
2025-04-08 06:14:55 +08:00
|
|
|
))
|
|
|
|
.execute(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
// Create update request with new verification status
|
|
|
|
let request = UpdateMetricRequest {
|
|
|
|
verification: Some(Verification::Verified),
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
|
|
|
|
// Call the update_metric_handler
|
|
|
|
let updated_metric = update_metric_handler(
|
|
|
|
&metric_id,
|
2025-04-08 06:18:11 +08:00
|
|
|
&setup.user,
|
2025-04-08 06:14:55 +08:00
|
|
|
request
|
|
|
|
).await?;
|
|
|
|
|
|
|
|
// Verify response has the updated status
|
|
|
|
assert_eq!(updated_metric.status, Verification::Verified);
|
|
|
|
|
|
|
|
// Verify database was updated
|
|
|
|
let db_metric = metric_files::table
|
|
|
|
.find(metric_id)
|
|
|
|
.first::<MetricFile>(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
assert_eq!(db_metric.verification, Verification::Verified);
|
|
|
|
|
|
|
|
// Clean up test data
|
|
|
|
diesel::delete(metric_files::table)
|
|
|
|
.filter(metric_files::id.eq(metric_id))
|
|
|
|
.execute(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
diesel::delete(database::schema::asset_permissions::table)
|
|
|
|
.filter(database::schema::asset_permissions::asset_id.eq(metric_id))
|
|
|
|
.execute(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
2025-04-08 06:43:00 +08:00
|
|
|
// TestDb cleanup will handle the rest of the cleanup
|
|
|
|
setup.db.cleanup().await?;
|
2025-04-08 06:18:11 +08:00
|
|
|
|
2025-04-08 06:14:55 +08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
// Helper function to create default chart config for testing
|
|
|
|
fn create_default_chart_config() -> database::types::metric_yml::ChartConfig {
|
|
|
|
use database::types::metric_yml::{BarAndLineAxis, BarLineChartConfig, BaseChartConfig, ChartConfig};
|
|
|
|
use indexmap::IndexMap;
|
|
|
|
|
|
|
|
ChartConfig::Bar(BarLineChartConfig {
|
|
|
|
base: BaseChartConfig {
|
|
|
|
column_label_formats: IndexMap::new(),
|
|
|
|
column_settings: None,
|
|
|
|
colors: None,
|
|
|
|
show_legend: None,
|
|
|
|
grid_lines: None,
|
|
|
|
show_legend_headline: None,
|
|
|
|
goal_lines: None,
|
|
|
|
trendlines: None,
|
|
|
|
disable_tooltip: None,
|
|
|
|
y_axis_config: None,
|
|
|
|
x_axis_config: None,
|
|
|
|
category_axis_style_config: None,
|
|
|
|
y2_axis_config: None,
|
|
|
|
},
|
|
|
|
bar_and_line_axis: BarAndLineAxis {
|
|
|
|
x: vec!["x".to_string()],
|
|
|
|
y: vec!["y".to_string()],
|
|
|
|
category: None,
|
|
|
|
tooltip: None,
|
|
|
|
},
|
|
|
|
bar_layout: None,
|
|
|
|
bar_sort_by: None,
|
|
|
|
bar_group_type: None,
|
|
|
|
bar_show_total_at_top: None,
|
|
|
|
line_group_type: None,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test unauthorized access
|
|
|
|
#[tokio::test]
|
|
|
|
async fn test_update_metric_status_unauthorized() -> Result<()> {
|
2025-04-08 06:43:00 +08:00
|
|
|
// Initialize DB connection pool
|
|
|
|
init_db_pool().await?;
|
2025-04-08 06:14:55 +08:00
|
|
|
|
2025-04-08 06:43:00 +08:00
|
|
|
// Set up test environment with viewer user (limited permissions)
|
|
|
|
let setup = TestSetup::new(Some(UserOrganizationRole::Viewer)).await?;
|
2025-04-08 06:27:51 +08:00
|
|
|
|
2025-04-08 06:43:00 +08:00
|
|
|
// Create test metric
|
|
|
|
let test_id = format!("test-{}", Uuid::new_v4());
|
2025-04-08 06:14:55 +08:00
|
|
|
let metric_id = Uuid::new_v4();
|
2025-04-08 06:43:00 +08:00
|
|
|
let mut conn = setup.db.diesel_conn().await?;
|
2025-04-08 06:14:55 +08:00
|
|
|
|
|
|
|
// Create a simple metric with test content
|
|
|
|
let content = database::types::MetricYml {
|
2025-04-08 06:43:00 +08:00
|
|
|
name: format!("Test Metric {}", test_id),
|
|
|
|
description: Some(format!("Test metric description for {}", test_id)),
|
2025-04-08 06:14:55 +08:00
|
|
|
sql: "SELECT * FROM test".to_string(),
|
|
|
|
time_frame: "last 30 days".to_string(),
|
|
|
|
chart_config: create_default_chart_config(),
|
|
|
|
dataset_ids: vec![],
|
|
|
|
};
|
|
|
|
|
|
|
|
// Initial verification status
|
|
|
|
let initial_verification = Verification::NotRequested;
|
|
|
|
|
|
|
|
// Create the test metric file
|
|
|
|
let metric_file = MetricFile {
|
|
|
|
id: metric_id,
|
2025-04-08 06:43:00 +08:00
|
|
|
name: format!("{}-Test Metric", test_id),
|
|
|
|
file_name: format!("{}-test_metric.yml", test_id),
|
2025-04-08 06:14:55 +08:00
|
|
|
content: content.clone(),
|
|
|
|
verification: initial_verification,
|
|
|
|
evaluation_obj: None,
|
|
|
|
evaluation_summary: None,
|
|
|
|
evaluation_score: None,
|
2025-04-08 06:18:11 +08:00
|
|
|
organization_id: setup.organization.id,
|
|
|
|
created_by: setup.user.id,
|
2025-04-08 06:43:00 +08:00
|
|
|
created_at: setup.user.created_at,
|
|
|
|
updated_at: setup.user.updated_at,
|
2025-04-08 06:14:55 +08:00
|
|
|
deleted_at: None,
|
|
|
|
publicly_accessible: false,
|
|
|
|
publicly_enabled_by: None,
|
|
|
|
public_expiry_date: None,
|
|
|
|
version_history: database::types::VersionHistory(std::collections::HashMap::new()),
|
|
|
|
data_metadata: None,
|
|
|
|
public_password: None,
|
|
|
|
};
|
|
|
|
|
|
|
|
// Insert the test metric into the database
|
|
|
|
diesel::insert_into(metric_files::table)
|
|
|
|
.values(&metric_file)
|
|
|
|
.execute(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
2025-04-08 06:43:00 +08:00
|
|
|
// Create test user in the database (required for foreign key constraints)
|
|
|
|
diesel::insert_into(database::schema::organizations::table)
|
|
|
|
.values((
|
|
|
|
database::schema::organizations::id.eq(setup.organization.id),
|
|
|
|
database::schema::organizations::name.eq(&setup.organization.name),
|
|
|
|
database::schema::organizations::domain.eq(setup.organization.domain.as_ref()),
|
|
|
|
database::schema::organizations::created_at.eq(setup.organization.created_at),
|
|
|
|
database::schema::organizations::updated_at.eq(setup.organization.updated_at),
|
|
|
|
database::schema::organizations::deleted_at.eq::<Option<chrono::DateTime<chrono::Utc>>>(None),
|
|
|
|
))
|
|
|
|
.on_conflict_do_nothing()
|
|
|
|
.execute(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
// Create test user
|
|
|
|
diesel::insert_into(database::schema::users::table)
|
|
|
|
.values((
|
|
|
|
database::schema::users::id.eq(setup.user.id),
|
|
|
|
database::schema::users::email.eq(&setup.user.email),
|
|
|
|
database::schema::users::name.eq(setup.user.name.as_ref()),
|
|
|
|
database::schema::users::config.eq(serde_json::json!({})),
|
|
|
|
database::schema::users::created_at.eq(setup.user.created_at),
|
|
|
|
database::schema::users::updated_at.eq(setup.user.created_at),
|
|
|
|
database::schema::users::attributes.eq(serde_json::json!({})),
|
|
|
|
database::schema::users::avatar_url.eq::<Option<String>>(None),
|
|
|
|
))
|
|
|
|
.on_conflict_do_nothing()
|
|
|
|
.execute(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
// Create user-organization relationship
|
|
|
|
diesel::insert_into(database::schema::users_to_organizations::table)
|
|
|
|
.values((
|
|
|
|
database::schema::users_to_organizations::user_id.eq(setup.user.id),
|
|
|
|
database::schema::users_to_organizations::organization_id.eq(setup.organization.id),
|
|
|
|
database::schema::users_to_organizations::role.eq(setup.user.organizations[0].role),
|
|
|
|
database::schema::users_to_organizations::sharing_setting.eq(database::enums::SharingSetting::None),
|
|
|
|
database::schema::users_to_organizations::edit_sql.eq(true),
|
|
|
|
database::schema::users_to_organizations::upload_csv.eq(true),
|
|
|
|
database::schema::users_to_organizations::export_assets.eq(true),
|
|
|
|
database::schema::users_to_organizations::email_slack_enabled.eq(true),
|
|
|
|
database::schema::users_to_organizations::created_at.eq(setup.user.created_at),
|
|
|
|
database::schema::users_to_organizations::updated_at.eq(setup.user.created_at),
|
|
|
|
database::schema::users_to_organizations::deleted_at.eq::<Option<chrono::DateTime<chrono::Utc>>>(None),
|
|
|
|
database::schema::users_to_organizations::created_by.eq(setup.user.id),
|
|
|
|
database::schema::users_to_organizations::updated_by.eq(setup.user.id),
|
|
|
|
database::schema::users_to_organizations::deleted_by.eq::<Option<Uuid>>(None),
|
|
|
|
database::schema::users_to_organizations::status.eq(database::enums::UserOrganizationStatus::Active),
|
|
|
|
))
|
|
|
|
.on_conflict_do_nothing()
|
|
|
|
.execute(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
2025-04-08 06:14:55 +08:00
|
|
|
// Create view-only permission
|
|
|
|
diesel::insert_into(database::schema::asset_permissions::table)
|
|
|
|
.values((
|
2025-04-08 06:18:11 +08:00
|
|
|
database::schema::asset_permissions::identity_id.eq(setup.user.id),
|
2025-04-08 06:14:55 +08:00
|
|
|
database::schema::asset_permissions::identity_type.eq(database::enums::IdentityType::User),
|
|
|
|
database::schema::asset_permissions::asset_id.eq(metric_id),
|
|
|
|
database::schema::asset_permissions::asset_type.eq(AssetType::MetricFile),
|
|
|
|
database::schema::asset_permissions::role.eq(AssetPermissionRole::CanView),
|
2025-04-08 06:43:00 +08:00
|
|
|
database::schema::asset_permissions::created_at.eq(setup.user.created_at),
|
|
|
|
database::schema::asset_permissions::updated_at.eq(setup.user.created_at),
|
2025-04-08 06:14:55 +08:00
|
|
|
database::schema::asset_permissions::deleted_at.eq::<Option<chrono::DateTime<chrono::Utc>>>(None),
|
2025-04-08 06:18:11 +08:00
|
|
|
database::schema::asset_permissions::created_by.eq(setup.user.id),
|
|
|
|
database::schema::asset_permissions::updated_by.eq(setup.user.id),
|
2025-04-08 06:14:55 +08:00
|
|
|
))
|
|
|
|
.execute(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
// Create update request with new verification status
|
|
|
|
let request = UpdateMetricRequest {
|
|
|
|
verification: Some(Verification::Verified),
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
|
|
|
|
// Call the update_metric_handler - should fail
|
|
|
|
let result = update_metric_handler(
|
|
|
|
&metric_id,
|
2025-04-08 06:18:11 +08:00
|
|
|
&setup.user,
|
2025-04-08 06:14:55 +08:00
|
|
|
request
|
|
|
|
).await;
|
|
|
|
|
|
|
|
// Verify the operation failed
|
|
|
|
assert!(result.is_err());
|
|
|
|
|
|
|
|
// Verify database was not updated
|
|
|
|
let db_metric = metric_files::table
|
|
|
|
.find(metric_id)
|
|
|
|
.first::<MetricFile>(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
assert_eq!(db_metric.verification, initial_verification);
|
|
|
|
|
|
|
|
// Clean up test data
|
|
|
|
diesel::delete(metric_files::table)
|
|
|
|
.filter(metric_files::id.eq(metric_id))
|
|
|
|
.execute(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
diesel::delete(database::schema::asset_permissions::table)
|
|
|
|
.filter(database::schema::asset_permissions::asset_id.eq(metric_id))
|
|
|
|
.execute(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
2025-04-08 06:43:00 +08:00
|
|
|
// TestDb cleanup will handle the rest of the cleanup
|
|
|
|
setup.db.cleanup().await?;
|
2025-04-08 06:18:11 +08:00
|
|
|
|
2025-04-08 06:14:55 +08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test edge cases for status updates
|
|
|
|
#[tokio::test]
|
|
|
|
async fn test_update_metric_status_null_value() -> Result<()> {
|
2025-04-08 06:43:00 +08:00
|
|
|
// Initialize DB connection pool
|
|
|
|
init_db_pool().await?;
|
2025-04-08 06:27:51 +08:00
|
|
|
|
2025-04-08 06:43:00 +08:00
|
|
|
// Set up test environment with admin user
|
|
|
|
let setup = TestSetup::new(Some(UserOrganizationRole::WorkspaceAdmin)).await?;
|
2025-04-08 06:27:51 +08:00
|
|
|
|
2025-04-08 06:43:00 +08:00
|
|
|
// Create test metric
|
|
|
|
let test_id = format!("test-{}", Uuid::new_v4());
|
2025-04-08 06:14:55 +08:00
|
|
|
let metric_id = Uuid::new_v4();
|
2025-04-08 06:43:00 +08:00
|
|
|
let mut conn = setup.db.diesel_conn().await?;
|
2025-04-08 06:14:55 +08:00
|
|
|
|
|
|
|
// Create a simple metric with test content
|
|
|
|
let content = database::types::MetricYml {
|
2025-04-08 06:43:00 +08:00
|
|
|
name: format!("Test Metric {}", test_id),
|
|
|
|
description: Some(format!("Test metric description for {}", test_id)),
|
2025-04-08 06:14:55 +08:00
|
|
|
sql: "SELECT * FROM test".to_string(),
|
|
|
|
time_frame: "last 30 days".to_string(),
|
|
|
|
chart_config: create_default_chart_config(),
|
|
|
|
dataset_ids: vec![],
|
|
|
|
};
|
|
|
|
|
2025-04-08 06:43:00 +08:00
|
|
|
// Initial verification status - set to Verified for this test
|
2025-04-08 06:14:55 +08:00
|
|
|
let initial_verification = Verification::Verified;
|
|
|
|
|
|
|
|
// Create the test metric file
|
|
|
|
let metric_file = MetricFile {
|
|
|
|
id: metric_id,
|
2025-04-08 06:43:00 +08:00
|
|
|
name: format!("{}-Test Metric", test_id),
|
|
|
|
file_name: format!("{}-test_metric.yml", test_id),
|
2025-04-08 06:14:55 +08:00
|
|
|
content: content.clone(),
|
|
|
|
verification: initial_verification,
|
|
|
|
evaluation_obj: None,
|
|
|
|
evaluation_summary: None,
|
|
|
|
evaluation_score: None,
|
2025-04-08 06:18:11 +08:00
|
|
|
organization_id: setup.organization.id,
|
|
|
|
created_by: setup.user.id,
|
2025-04-08 06:43:00 +08:00
|
|
|
created_at: setup.user.created_at,
|
|
|
|
updated_at: setup.user.updated_at,
|
2025-04-08 06:14:55 +08:00
|
|
|
deleted_at: None,
|
|
|
|
publicly_accessible: false,
|
|
|
|
publicly_enabled_by: None,
|
|
|
|
public_expiry_date: None,
|
|
|
|
version_history: database::types::VersionHistory(std::collections::HashMap::new()),
|
|
|
|
data_metadata: None,
|
|
|
|
public_password: None,
|
|
|
|
};
|
|
|
|
|
|
|
|
// Insert the test metric into the database
|
|
|
|
diesel::insert_into(metric_files::table)
|
|
|
|
.values(&metric_file)
|
|
|
|
.execute(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
2025-04-08 06:43:00 +08:00
|
|
|
// Create test user in the database (required for foreign key constraints)
|
|
|
|
diesel::insert_into(database::schema::organizations::table)
|
|
|
|
.values((
|
|
|
|
database::schema::organizations::id.eq(setup.organization.id),
|
|
|
|
database::schema::organizations::name.eq(&setup.organization.name),
|
|
|
|
database::schema::organizations::domain.eq(setup.organization.domain.as_ref()),
|
|
|
|
database::schema::organizations::created_at.eq(setup.organization.created_at),
|
|
|
|
database::schema::organizations::updated_at.eq(setup.organization.updated_at),
|
|
|
|
database::schema::organizations::deleted_at.eq::<Option<chrono::DateTime<chrono::Utc>>>(None),
|
|
|
|
))
|
|
|
|
.on_conflict_do_nothing()
|
|
|
|
.execute(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
// Create test user
|
|
|
|
diesel::insert_into(database::schema::users::table)
|
|
|
|
.values((
|
|
|
|
database::schema::users::id.eq(setup.user.id),
|
|
|
|
database::schema::users::email.eq(&setup.user.email),
|
|
|
|
database::schema::users::name.eq(setup.user.name.as_ref()),
|
|
|
|
database::schema::users::config.eq(serde_json::json!({})),
|
|
|
|
database::schema::users::created_at.eq(setup.user.created_at),
|
|
|
|
database::schema::users::updated_at.eq(setup.user.created_at),
|
|
|
|
database::schema::users::attributes.eq(serde_json::json!({})),
|
|
|
|
database::schema::users::avatar_url.eq::<Option<String>>(None),
|
|
|
|
))
|
|
|
|
.on_conflict_do_nothing()
|
|
|
|
.execute(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
// Create user-organization relationship
|
|
|
|
diesel::insert_into(database::schema::users_to_organizations::table)
|
|
|
|
.values((
|
|
|
|
database::schema::users_to_organizations::user_id.eq(setup.user.id),
|
|
|
|
database::schema::users_to_organizations::organization_id.eq(setup.organization.id),
|
|
|
|
database::schema::users_to_organizations::role.eq(setup.user.organizations[0].role),
|
|
|
|
database::schema::users_to_organizations::sharing_setting.eq(database::enums::SharingSetting::None),
|
|
|
|
database::schema::users_to_organizations::edit_sql.eq(true),
|
|
|
|
database::schema::users_to_organizations::upload_csv.eq(true),
|
|
|
|
database::schema::users_to_organizations::export_assets.eq(true),
|
|
|
|
database::schema::users_to_organizations::email_slack_enabled.eq(true),
|
|
|
|
database::schema::users_to_organizations::created_at.eq(setup.user.created_at),
|
|
|
|
database::schema::users_to_organizations::updated_at.eq(setup.user.created_at),
|
|
|
|
database::schema::users_to_organizations::deleted_at.eq::<Option<chrono::DateTime<chrono::Utc>>>(None),
|
|
|
|
database::schema::users_to_organizations::created_by.eq(setup.user.id),
|
|
|
|
database::schema::users_to_organizations::updated_by.eq(setup.user.id),
|
|
|
|
database::schema::users_to_organizations::deleted_by.eq::<Option<Uuid>>(None),
|
|
|
|
database::schema::users_to_organizations::status.eq(database::enums::UserOrganizationStatus::Active),
|
|
|
|
))
|
|
|
|
.on_conflict_do_nothing()
|
|
|
|
.execute(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
// Create permission for the user - Owner level
|
2025-04-08 06:14:55 +08:00
|
|
|
diesel::insert_into(database::schema::asset_permissions::table)
|
|
|
|
.values((
|
2025-04-08 06:18:11 +08:00
|
|
|
database::schema::asset_permissions::identity_id.eq(setup.user.id),
|
2025-04-08 06:14:55 +08:00
|
|
|
database::schema::asset_permissions::identity_type.eq(database::enums::IdentityType::User),
|
|
|
|
database::schema::asset_permissions::asset_id.eq(metric_id),
|
|
|
|
database::schema::asset_permissions::asset_type.eq(AssetType::MetricFile),
|
|
|
|
database::schema::asset_permissions::role.eq(AssetPermissionRole::Owner),
|
2025-04-08 06:43:00 +08:00
|
|
|
database::schema::asset_permissions::created_at.eq(setup.user.created_at),
|
|
|
|
database::schema::asset_permissions::updated_at.eq(setup.user.created_at),
|
2025-04-08 06:14:55 +08:00
|
|
|
database::schema::asset_permissions::deleted_at.eq::<Option<chrono::DateTime<chrono::Utc>>>(None),
|
2025-04-08 06:18:11 +08:00
|
|
|
database::schema::asset_permissions::created_by.eq(setup.user.id),
|
|
|
|
database::schema::asset_permissions::updated_by.eq(setup.user.id),
|
2025-04-08 06:14:55 +08:00
|
|
|
))
|
|
|
|
.execute(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
// Create update request with null verification value
|
|
|
|
let request = UpdateMetricRequest {
|
|
|
|
verification: None,
|
|
|
|
..Default::default()
|
|
|
|
};
|
|
|
|
|
|
|
|
// Call the update_metric_handler
|
|
|
|
let updated_metric = update_metric_handler(
|
|
|
|
&metric_id,
|
2025-04-08 06:18:11 +08:00
|
|
|
&setup.user,
|
2025-04-08 06:14:55 +08:00
|
|
|
request
|
|
|
|
).await?;
|
|
|
|
|
|
|
|
// Verify original status is preserved
|
|
|
|
assert_eq!(updated_metric.status, initial_verification);
|
|
|
|
|
|
|
|
// Verify database status was not changed
|
|
|
|
let db_metric = metric_files::table
|
|
|
|
.find(metric_id)
|
|
|
|
.first::<MetricFile>(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
assert_eq!(db_metric.verification, initial_verification);
|
|
|
|
|
|
|
|
// Clean up test data
|
|
|
|
diesel::delete(metric_files::table)
|
|
|
|
.filter(metric_files::id.eq(metric_id))
|
|
|
|
.execute(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
diesel::delete(database::schema::asset_permissions::table)
|
|
|
|
.filter(database::schema::asset_permissions::asset_id.eq(metric_id))
|
|
|
|
.execute(&mut conn)
|
|
|
|
.await?;
|
|
|
|
|
2025-04-08 06:43:00 +08:00
|
|
|
// TestDb cleanup will handle the rest of the cleanup
|
|
|
|
setup.db.cleanup().await?;
|
2025-04-08 06:18:11 +08:00
|
|
|
|
2025-04-08 06:14:55 +08:00
|
|
|
Ok(())
|
2025-04-08 06:43:00 +08:00
|
|
|
}
|
|
|
|
|