added in some tests and such for dashboard_ymls and metric_handlers

This commit is contained in:
dal 2025-03-19 00:09:43 -06:00
parent 42f8226b2e
commit 2a33977a4e
No known key found for this signature in database
GPG Key ID: 16F4B0E1E9F61122
3 changed files with 370 additions and 1 deletions

View File

@ -168,3 +168,267 @@ impl ToSql<Jsonb, Pg> for DashboardYml {
Ok(IsNull::No)
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_dashboard_yml_camel_case_serialization() {
// Test case: Verify that DashboardYml serializes to camelCase
// Expected: JSON fields should be in camelCase format
// Create a dashboard with one row
let dashboard = DashboardYml {
name: "Test Dashboard".to_string(),
description: Some("This is a test dashboard".to_string()),
rows: vec![
Row {
items: vec![
RowItem {
id: Uuid::parse_str("00000000-0000-0000-0000-000000000001").unwrap(),
}
],
row_height: Some(400),
column_sizes: Some(vec![12]),
id: Some(1),
}
],
};
// Serialize to JSON
let json = serde_json::to_value(&dashboard).unwrap();
// Verify camelCase field names in the output
assert!(json.get("name").is_some());
assert!(json.get("description").is_some());
assert!(json.get("rows").is_some());
// Check row fields are in camelCase
let row = &json["rows"][0];
assert!(row.get("items").is_some());
assert!(row.get("rowHeight").is_some());
assert!(row.get("columnSizes").is_some());
assert!(row.get("id").is_some());
// Verify snake_case field names are NOT present
assert!(row.get("row_height").is_none());
assert!(row.get("column_sizes").is_none());
}
#[test]
fn test_dashboard_yml_snake_case_deserialization() {
// Test case: Verify that DashboardYml deserializes from snake_case
// Expected: Both snake_case and camelCase fields should be accepted
// Create JSON with snake_case fields
let json = json!({
"name": "Test Dashboard",
"description": "This is a test dashboard",
"rows": [
{
"items": [
{
"id": "00000000-0000-0000-0000-000000000001"
}
],
"row_height": 400,
"column_sizes": [12]
}
]
});
// Convert to YAML and use the new method to assign IDs
let yaml = serde_yaml::to_string(&json).unwrap();
let dashboard = DashboardYml::new(yaml).unwrap();
// Verify fields were properly deserialized
assert_eq!(dashboard.name, "Test Dashboard");
assert_eq!(dashboard.description, Some("This is a test dashboard".to_string()));
assert_eq!(dashboard.rows.len(), 1);
assert_eq!(dashboard.rows[0].row_height, Some(400));
assert_eq!(dashboard.rows[0].column_sizes, Some(vec![12]));
// Check that a row ID was assigned
assert_eq!(dashboard.rows[0].id, Some(1));
}
#[test]
fn test_dashboard_yml_camel_case_deserialization() {
// Test case: Verify that DashboardYml deserializes from camelCase
// Expected: camelCase fields should be properly deserialized
// Create JSON with camelCase fields
let json = json!({
"name": "Test Dashboard",
"description": "This is a test dashboard",
"rows": [
{
"items": [
{
"id": "00000000-0000-0000-0000-000000000001"
}
],
"rowHeight": 400,
"columnSizes": [12]
}
]
});
// Convert to YAML and use the new method to assign IDs
let yaml = serde_yaml::to_string(&json).unwrap();
let dashboard = DashboardYml::new(yaml).unwrap();
// Verify fields were properly deserialized
assert_eq!(dashboard.name, "Test Dashboard");
assert_eq!(dashboard.description, Some("This is a test dashboard".to_string()));
assert_eq!(dashboard.rows.len(), 1);
assert_eq!(dashboard.rows[0].row_height, Some(400));
assert_eq!(dashboard.rows[0].column_sizes, Some(vec![12]));
// Check that a row ID was assigned
assert_eq!(dashboard.rows[0].id, Some(1));
}
#[test]
fn test_row_id_generation() {
// Test case: Verify that row IDs are properly generated
// Expected: Row IDs should increment by 1 for each row
// Create a dashboard from YAML without row IDs
let yaml = r#"
name: Test Dashboard
description: This is a test dashboard
rows:
- items:
- id: 00000000-0000-0000-0000-000000000001
rowHeight: 400
columnSizes: [12]
- items:
- id: 00000000-0000-0000-0000-000000000002
rowHeight: 320
columnSizes: [12]
- items:
- id: 00000000-0000-0000-0000-000000000003
rowHeight: 550
columnSizes: [12]
"#;
// Create dashboard using the new method (which should assign row IDs)
let dashboard = DashboardYml::new(yaml.to_string()).unwrap();
// Verify that row IDs were assigned in sequence
assert_eq!(dashboard.rows[0].id, Some(1));
assert_eq!(dashboard.rows[1].id, Some(2));
assert_eq!(dashboard.rows[2].id, Some(3));
}
#[test]
fn test_add_row_method() {
// Test case: Verify that the add_row method assigns the next available ID
// Expected: New rows get the next sequential ID
// Create a dashboard with one row
let mut dashboard = DashboardYml {
name: "Test Dashboard".to_string(),
description: None,
rows: vec![
Row {
items: vec![RowItem { id: Uuid::new_v4() }],
row_height: None,
column_sizes: None,
id: Some(1),
}
],
};
// Add a second row using the add_row method
dashboard.add_row(
vec![RowItem { id: Uuid::new_v4() }],
Some(400),
Some(vec![12]),
);
// Add a third row
dashboard.add_row(
vec![RowItem { id: Uuid::new_v4() }],
Some(320),
None,
);
// Verify that row IDs were assigned in sequence
assert_eq!(dashboard.rows[0].id, Some(1));
assert_eq!(dashboard.rows[1].id, Some(2));
assert_eq!(dashboard.rows[2].id, Some(3));
// Verify that get_next_row_id returns the expected value
assert_eq!(dashboard.get_next_row_id(), 4);
}
#[test]
fn test_non_sequential_row_ids() {
// Test case: Verify that get_next_row_id works with non-sequential IDs
// Expected: Next ID should be max(id) + 1
// Create a dashboard with rows that have non-sequential IDs
let dashboard = DashboardYml {
name: "Test Dashboard".to_string(),
description: None,
rows: vec![
Row {
items: vec![RowItem { id: Uuid::new_v4() }],
row_height: None,
column_sizes: None,
id: Some(1),
},
Row {
items: vec![RowItem { id: Uuid::new_v4() }],
row_height: None,
column_sizes: None,
id: Some(5), // Intentionally out of sequence
},
Row {
items: vec![RowItem { id: Uuid::new_v4() }],
row_height: None,
column_sizes: None,
id: Some(3),
}
],
};
// Verify that get_next_row_id returns max(id) + 1
assert_eq!(dashboard.get_next_row_id(), 6);
}
#[test]
fn test_explicitly_provided_id() {
// Test case: Verify that explicitly provided IDs are preserved during deserialization
// Expected: Row ID should match the provided value
// Create JSON with an explicit ID field
let json = json!({
"name": "Test Dashboard",
"description": "This is a test dashboard",
"rows": [
{
"items": [
{
"id": "00000000-0000-0000-0000-000000000001"
}
],
"rowHeight": 400,
"columnSizes": [12],
"id": 42 // Explicitly set ID
}
]
});
// Convert to YAML and use the new method
let yaml = serde_yaml::to_string(&json).unwrap();
let dashboard = DashboardYml::new(yaml).unwrap();
// Verify the explicit ID was preserved
assert_eq!(dashboard.rows[0].id, Some(42));
}
}

View File

@ -25,6 +25,26 @@ pub struct UpdateMetricRequest {
}
/// Handler to update a metric by ID
///
/// This handler updates a metric file in the database and increments its version number.
/// Each time a metric is updated, the previous version is saved in the version history.
///
/// # Arguments
/// * `metric_id` - The UUID of the metric to update
/// * `user_id` - The UUID of the user making the update
/// * `request` - The update request containing the fields to modify
///
/// # Returns
/// * `Result<BusterMetric>` - The updated metric on success, or an error
///
/// # Versioning
/// The function automatically handles versioning:
/// 1. Retrieves the current metric and extracts its content
/// 2. Updates the content based on the request parameters
/// 3. Increments the version number (based on the number of existing versions)
/// 4. Adds the updated content to the version history with the new version number
/// 5. Saves both the updated content and version history to the database
///
pub async fn update_metric_handler(
metric_id: &Uuid,
user_id: &Uuid,

View File

@ -85,6 +85,18 @@ async fn test_update_metric_integration() -> Result<()> {
assert!(db_metric.version_history.0.contains_key(&"1".to_string()));
assert!(db_metric.version_history.0.contains_key(&"2".to_string()));
// Get the latest version from the version history
let latest_version = db_metric.version_history.get_latest_version().unwrap();
assert_eq!(latest_version.version_number, 2);
// Verify the latest version's content matches the current content
if let database::types::VersionContent::MetricYml(latest_content) = &latest_version.content {
assert_eq!(latest_content.time_frame, "weekly");
assert_eq!(latest_content.description, Some("Updated test description".to_string()));
} else {
panic!("Expected MetricYml content in version history");
}
println!("Update metric test passed with ID: {}", metric_id);
},
Err(e) => {
@ -133,7 +145,7 @@ async fn test_update_nonexistent_metric() -> Result<()> {
Ok(())
}
/// Test updating specific metric fields one at a time
/// Test updating specific metric fields one at a time and verify version increments properly
#[tokio::test]
async fn test_update_specific_metric_fields() -> Result<()> {
// Setup test environment
@ -174,6 +186,25 @@ async fn test_update_specific_metric_fields() -> Result<()> {
// Verify other fields were not changed
assert_eq!(metric.time_frame, "daily");
assert_eq!(metric.status, Verification::NotRequested);
// Verify version number was incremented
assert_eq!(metric.version_number, 2);
// Verify in the database
let mut conn = get_pg_pool().get().await?;
let db_metric = metric_files::table
.filter(metric_files::id.eq(metric_id))
.first::<database::models::MetricFile>(&mut conn)
.await?;
// Check version history has exactly 2 versions
assert_eq!(db_metric.version_history.0.len(), 2);
assert!(db_metric.version_history.0.contains_key(&"1".to_string()));
assert!(db_metric.version_history.0.contains_key(&"2".to_string()));
// Get the latest version
let latest_version = db_metric.version_history.get_latest_version().unwrap();
assert_eq!(latest_version.version_number, 2);
},
Err(e) => {
cleanup_test_data(Some(metric_id), None).await?;
@ -198,6 +229,26 @@ async fn test_update_specific_metric_fields() -> Result<()> {
// Verify title remains from previous update
assert_eq!(metric.title, "Title Only Update");
// Verify version number increased again
assert_eq!(metric.version_number, 3);
// Verify in the database
let mut conn = get_pg_pool().get().await?;
let db_metric = metric_files::table
.filter(metric_files::id.eq(metric_id))
.first::<database::models::MetricFile>(&mut conn)
.await?;
// Check version history has exactly 3 versions
assert_eq!(db_metric.version_history.0.len(), 3);
assert!(db_metric.version_history.0.contains_key(&"1".to_string()));
assert!(db_metric.version_history.0.contains_key(&"2".to_string()));
assert!(db_metric.version_history.0.contains_key(&"3".to_string()));
// Get the latest version
let latest_version = db_metric.version_history.get_latest_version().unwrap();
assert_eq!(latest_version.version_number, 3);
},
Err(e) => {
cleanup_test_data(Some(metric_id), None).await?;
@ -223,6 +274,40 @@ async fn test_update_specific_metric_fields() -> Result<()> {
// Verify other fields remain from previous updates
assert_eq!(metric.title, "Title Only Update");
assert_eq!(metric.status, Verification::Verified);
// Verify version number increased to 4
assert_eq!(metric.version_number, 4);
// Verify in the database
let mut conn = get_pg_pool().get().await?;
let db_metric = metric_files::table
.filter(metric_files::id.eq(metric_id))
.first::<database::models::MetricFile>(&mut conn)
.await?;
// Check version history now has 4 versions
assert_eq!(db_metric.version_history.0.len(), 4);
// Verify all version numbers are present
for i in 1..=4 {
assert!(db_metric.version_history.0.contains_key(&i.to_string()),
"Version {} missing from history", i);
}
// Get the latest version
let latest_version = db_metric.version_history.get_latest_version().unwrap();
assert_eq!(latest_version.version_number, 4);
// Check the content of the latest version
if let database::types::VersionContent::MetricYml(latest_content) = &latest_version.content {
assert_eq!(latest_content.time_frame, "monthly");
// The title should be preserved from earlier updates
let yaml = serde_yaml::to_string(latest_content).unwrap();
assert!(yaml.contains("Title Only Update"));
} else {
panic!("Expected MetricYml content in version history");
}
},
Err(e) => {
cleanup_test_data(Some(metric_id), None).await?;