mirror of https://github.com/buster-so/buster.git
added in some tests and such for dashboard_ymls and metric_handlers
This commit is contained in:
parent
42f8226b2e
commit
2a33977a4e
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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?;
|
||||
|
|
Loading…
Reference in New Issue