1376 lines
39 KiB
Rust
1376 lines
39 KiB
Rust
//! Integration tests for Rule repository
|
|
//!
|
|
//! These tests verify CRUD operations, queries, and constraints
|
|
//! for the Rule repository.
|
|
|
|
mod helpers;
|
|
|
|
use attune_common::{
|
|
repositories::{
|
|
rule::{CreateRuleInput, RuleRepository, UpdateRuleInput},
|
|
Create, Delete, FindById, FindByRef, List, Update,
|
|
},
|
|
Error,
|
|
};
|
|
use helpers::*;
|
|
use serde_json::json;
|
|
|
|
// ============================================================================
|
|
// CREATE Tests
|
|
// ============================================================================
|
|
|
|
#[tokio::test]
|
|
async fn test_create_rule() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
// Setup: Create pack, action, and trigger
|
|
let pack = PackFixture::new_unique("test_pack")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action = ActionFixture::new_unique(pack.id, &pack.r#ref, "test_action")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger =
|
|
TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "test_trigger")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Create rule
|
|
let rule_ref = format!("{}.test_rule", pack.r#ref);
|
|
let input = CreateRuleInput {
|
|
r#ref: rule_ref.clone(),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: "Test Rule".to_string(),
|
|
description: "A test rule".to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!({"equals": {"event.status": "success"}}),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
let rule = RuleRepository::create(&pool, input).await.unwrap();
|
|
|
|
assert_eq!(rule.r#ref, rule_ref);
|
|
assert_eq!(rule.pack, pack.id);
|
|
assert_eq!(rule.pack_ref, pack.r#ref);
|
|
assert_eq!(rule.label, "Test Rule");
|
|
assert_eq!(rule.description, "A test rule");
|
|
assert_eq!(rule.action, action.id);
|
|
assert_eq!(rule.action_ref, action.r#ref);
|
|
assert_eq!(rule.trigger, trigger.id);
|
|
assert_eq!(rule.trigger_ref, trigger.r#ref);
|
|
assert_eq!(
|
|
rule.conditions,
|
|
json!({"equals": {"event.status": "success"}})
|
|
);
|
|
assert_eq!(rule.enabled, true);
|
|
assert!(rule.created.timestamp() > 0);
|
|
assert!(rule.updated.timestamp() > 0);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_create_rule_disabled() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let pack = PackFixture::new_unique("disabled_pack")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action = ActionFixture::new_unique(pack.id, &pack.r#ref, "action")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger = TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "trigger")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.disabled_rule", pack.r#ref),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: "Disabled Rule".to_string(),
|
|
description: "A disabled rule".to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: false,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
let rule = RuleRepository::create(&pool, input).await.unwrap();
|
|
|
|
assert_eq!(rule.enabled, false);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_create_rule_with_complex_conditions() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let pack = PackFixture::new_unique("complex_pack")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action = ActionFixture::new_unique(pack.id, &pack.r#ref, "action")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger = TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "trigger")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let conditions = json!({
|
|
"and": [
|
|
{"equals": {"event.type": "webhook"}},
|
|
{"greater_than": {"event.priority": 5}},
|
|
{"contains": {"event.tags": "important"}}
|
|
]
|
|
});
|
|
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.complex_rule", pack.r#ref),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: "Complex Rule".to_string(),
|
|
description: "Rule with complex conditions".to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: conditions.clone(),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
let rule = RuleRepository::create(&pool, input).await.unwrap();
|
|
|
|
assert_eq!(rule.conditions, conditions);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_create_rule_duplicate_ref() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let pack = PackFixture::new_unique("dup_pack")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action = ActionFixture::new_unique(pack.id, &pack.r#ref, "action")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger = TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "trigger")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let rule_ref = format!("{}.duplicate_rule", pack.r#ref);
|
|
|
|
// Create first rule
|
|
let input1 = CreateRuleInput {
|
|
r#ref: rule_ref.clone(),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: "First Rule".to_string(),
|
|
description: "First".to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
RuleRepository::create(&pool, input1).await.unwrap();
|
|
|
|
// Try to create second rule with same ref
|
|
let input2 = CreateRuleInput {
|
|
r#ref: rule_ref.clone(),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: "Second Rule".to_string(),
|
|
description: "Second".to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
let result = RuleRepository::create(&pool, input2).await;
|
|
|
|
assert!(result.is_err());
|
|
match result.unwrap_err() {
|
|
Error::AlreadyExists {
|
|
entity,
|
|
field,
|
|
value,
|
|
} => {
|
|
assert_eq!(entity, "Rule");
|
|
assert_eq!(field, "ref");
|
|
assert_eq!(value, rule_ref);
|
|
}
|
|
_ => panic!("Expected AlreadyExists error"),
|
|
}
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_create_rule_invalid_ref_format_uppercase() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let pack = PackFixture::new_unique("upper_pack")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action = ActionFixture::new_unique(pack.id, &pack.r#ref, "action")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger = TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "trigger")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.UPPERCASE_RULE", pack.r#ref),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: "Upper Rule".to_string(),
|
|
description: "Invalid uppercase ref".to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
let result = RuleRepository::create(&pool, input).await;
|
|
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_create_rule_invalid_ref_format_no_dot() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let pack = PackFixture::new_unique("nodot_pack")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action = ActionFixture::new_unique(pack.id, &pack.r#ref, "action")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger = TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "trigger")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let input = CreateRuleInput {
|
|
r#ref: "nodotinref".to_string(),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: "No Dot Rule".to_string(),
|
|
description: "Invalid ref without dot".to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
let result = RuleRepository::create(&pool, input).await;
|
|
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
// ============================================================================
|
|
// READ Tests
|
|
// ============================================================================
|
|
|
|
#[tokio::test]
|
|
async fn test_find_rule_by_id() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let pack = PackFixture::new_unique("find_pack")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action = ActionFixture::new_unique(pack.id, &pack.r#ref, "action")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger = TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "trigger")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.find_rule", pack.r#ref),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: "Find Rule".to_string(),
|
|
description: "Rule to find".to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
let created = RuleRepository::create(&pool, input).await.unwrap();
|
|
|
|
let found = RuleRepository::find_by_id(&pool, created.id)
|
|
.await
|
|
.unwrap()
|
|
.expect("Rule should exist");
|
|
|
|
assert_eq!(found.id, created.id);
|
|
assert_eq!(found.r#ref, created.r#ref);
|
|
assert_eq!(found.label, created.label);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_find_rule_by_id_not_found() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let result = RuleRepository::find_by_id(&pool, 999999).await.unwrap();
|
|
|
|
assert!(result.is_none());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_find_rule_by_ref() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let pack = PackFixture::new_unique("ref_pack")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action = ActionFixture::new_unique(pack.id, &pack.r#ref, "action")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger = TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "trigger")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let rule_ref = format!("{}.find_by_ref", pack.r#ref);
|
|
let input = CreateRuleInput {
|
|
r#ref: rule_ref.clone(),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: "Find By Ref Rule".to_string(),
|
|
description: "Find by ref".to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
let created = RuleRepository::create(&pool, input).await.unwrap();
|
|
|
|
let found = RuleRepository::find_by_ref(&pool, &rule_ref)
|
|
.await
|
|
.unwrap()
|
|
.expect("Rule should exist");
|
|
|
|
assert_eq!(found.id, created.id);
|
|
assert_eq!(found.r#ref, rule_ref);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_find_rule_by_ref_not_found() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let result = RuleRepository::find_by_ref(&pool, "nonexistent.rule")
|
|
.await
|
|
.unwrap();
|
|
|
|
assert!(result.is_none());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_list_rules() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let pack = PackFixture::new_unique("list_pack")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action = ActionFixture::new_unique(pack.id, &pack.r#ref, "action")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger = TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "trigger")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Create multiple rules
|
|
for i in 1..=3 {
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.list_rule_{}", pack.r#ref, i),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: format!("List Rule {}", i),
|
|
description: format!("Rule {}", i),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
RuleRepository::create(&pool, input).await.unwrap();
|
|
}
|
|
|
|
let rules = RuleRepository::list(&pool).await.unwrap();
|
|
|
|
// Should have at least our 3 rules (may have more from parallel tests)
|
|
let our_rules: Vec<_> = rules
|
|
.iter()
|
|
.filter(|r| r.r#ref.starts_with(&pack.r#ref))
|
|
.collect();
|
|
|
|
assert_eq!(our_rules.len(), 3);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_list_rules_ordered_by_ref() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let pack = PackFixture::new_unique("order_pack")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action = ActionFixture::new_unique(pack.id, &pack.r#ref, "action")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger = TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "trigger")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Create rules in non-alphabetical order
|
|
let names = vec!["charlie", "alice", "bob"];
|
|
for name in names {
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.{}", pack.r#ref, name),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: name.to_string(),
|
|
description: name.to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
RuleRepository::create(&pool, input).await.unwrap();
|
|
}
|
|
|
|
let rules = RuleRepository::list(&pool).await.unwrap();
|
|
let our_rules: Vec<_> = rules
|
|
.iter()
|
|
.filter(|r| r.r#ref.starts_with(&pack.r#ref))
|
|
.collect();
|
|
|
|
// Check they are ordered alphabetically
|
|
assert!(our_rules[0].r#ref.contains("alice"));
|
|
assert!(our_rules[1].r#ref.contains("bob"));
|
|
assert!(our_rules[2].r#ref.contains("charlie"));
|
|
}
|
|
|
|
// ============================================================================
|
|
// UPDATE Tests
|
|
// ============================================================================
|
|
|
|
#[tokio::test]
|
|
async fn test_update_rule_label() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let pack = PackFixture::new_unique("update_pack")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action = ActionFixture::new_unique(pack.id, &pack.r#ref, "action")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger = TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "trigger")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.update_rule", pack.r#ref),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: "Original Label".to_string(),
|
|
description: "Original".to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
let created = RuleRepository::create(&pool, input).await.unwrap();
|
|
|
|
let update = UpdateRuleInput {
|
|
label: Some("Updated Label".to_string()),
|
|
..Default::default()
|
|
};
|
|
|
|
let updated = RuleRepository::update(&pool, created.id, update)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(updated.label, "Updated Label");
|
|
assert_eq!(updated.description, "Original"); // unchanged
|
|
assert!(updated.updated > created.updated);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_update_rule_description() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let pack = PackFixture::new_unique("desc_pack")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action = ActionFixture::new_unique(pack.id, &pack.r#ref, "action")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger = TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "trigger")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.desc_rule", pack.r#ref),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: "Test".to_string(),
|
|
description: "Old description".to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
let created = RuleRepository::create(&pool, input).await.unwrap();
|
|
|
|
let update = UpdateRuleInput {
|
|
description: Some("New description".to_string()),
|
|
..Default::default()
|
|
};
|
|
|
|
let updated = RuleRepository::update(&pool, created.id, update)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(updated.description, "New description");
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_update_rule_conditions() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let pack = PackFixture::new_unique("cond_pack")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action = ActionFixture::new_unique(pack.id, &pack.r#ref, "action")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger = TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "trigger")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.cond_rule", pack.r#ref),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: "Test".to_string(),
|
|
description: "Test".to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!({"old": "condition"}),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
let created = RuleRepository::create(&pool, input).await.unwrap();
|
|
|
|
let new_conditions = json!({"new": "condition", "count": 42});
|
|
let update = UpdateRuleInput {
|
|
conditions: Some(new_conditions.clone()),
|
|
..Default::default()
|
|
};
|
|
|
|
let updated = RuleRepository::update(&pool, created.id, update)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(updated.conditions, new_conditions);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_update_rule_enabled() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let pack = PackFixture::new_unique("enabled_pack")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action = ActionFixture::new_unique(pack.id, &pack.r#ref, "action")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger = TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "trigger")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.enabled_rule", pack.r#ref),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: "Test".to_string(),
|
|
description: "Test".to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
let created = RuleRepository::create(&pool, input).await.unwrap();
|
|
|
|
let update = UpdateRuleInput {
|
|
enabled: Some(false),
|
|
action_params: None,
|
|
trigger_params: None,
|
|
..Default::default()
|
|
};
|
|
|
|
let updated = RuleRepository::update(&pool, created.id, update)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(updated.enabled, false);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_update_rule_multiple_fields() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let pack = PackFixture::new_unique("multi_pack")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action = ActionFixture::new_unique(pack.id, &pack.r#ref, "action")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger = TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "trigger")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.multi_rule", pack.r#ref),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: "Old".to_string(),
|
|
description: "Old".to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
let created = RuleRepository::create(&pool, input).await.unwrap();
|
|
|
|
let update = UpdateRuleInput {
|
|
label: Some("New Label".to_string()),
|
|
description: Some("New Description".to_string()),
|
|
conditions: Some(json!({"updated": true})),
|
|
action_params: None,
|
|
trigger_params: None,
|
|
enabled: Some(false),
|
|
};
|
|
|
|
let updated = RuleRepository::update(&pool, created.id, update)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(updated.label, "New Label");
|
|
assert_eq!(updated.description, "New Description");
|
|
assert_eq!(updated.conditions, json!({"updated": true}));
|
|
assert_eq!(updated.enabled, false);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_update_rule_no_changes() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let pack = PackFixture::new_unique("nochange_pack")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action = ActionFixture::new_unique(pack.id, &pack.r#ref, "action")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger = TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "trigger")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.nochange_rule", pack.r#ref),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: "Test".to_string(),
|
|
description: "Test".to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
let created = RuleRepository::create(&pool, input).await.unwrap();
|
|
|
|
let update = UpdateRuleInput::default();
|
|
|
|
let updated = RuleRepository::update(&pool, created.id, update)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(updated.label, created.label);
|
|
assert_eq!(updated.description, created.description);
|
|
}
|
|
|
|
// ============================================================================
|
|
// DELETE Tests
|
|
// ============================================================================
|
|
|
|
#[tokio::test]
|
|
async fn test_delete_rule() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let pack = PackFixture::new_unique("delete_pack")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action = ActionFixture::new_unique(pack.id, &pack.r#ref, "action")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger = TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "trigger")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.delete_rule", pack.r#ref),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: "To Delete".to_string(),
|
|
description: "Will be deleted".to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
let created = RuleRepository::create(&pool, input).await.unwrap();
|
|
|
|
let deleted = RuleRepository::delete(&pool, created.id).await.unwrap();
|
|
|
|
assert!(deleted);
|
|
|
|
let found = RuleRepository::find_by_id(&pool, created.id).await.unwrap();
|
|
|
|
assert!(found.is_none());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_delete_rule_not_found() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let deleted = RuleRepository::delete(&pool, 999999).await.unwrap();
|
|
|
|
assert!(!deleted);
|
|
}
|
|
|
|
// ============================================================================
|
|
// SPECIALIZED QUERY Tests
|
|
// ============================================================================
|
|
|
|
#[tokio::test]
|
|
async fn test_find_rules_by_pack() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let pack1 = PackFixture::new_unique("pack1")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let pack2 = PackFixture::new_unique("pack2")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action1 = ActionFixture::new_unique(pack1.id, &pack1.r#ref, "action1")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action2 = ActionFixture::new_unique(pack2.id, &pack2.r#ref, "action2")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger1 =
|
|
TriggerFixture::new_unique(Some(pack1.id), Some(pack1.r#ref.clone()), "trigger1")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger2 =
|
|
TriggerFixture::new_unique(Some(pack2.id), Some(pack2.r#ref.clone()), "trigger2")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Create 2 rules for pack1
|
|
for i in 1..=2 {
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.rule{}", pack1.r#ref, i),
|
|
pack: pack1.id,
|
|
pack_ref: pack1.r#ref.clone(),
|
|
label: format!("Rule {}", i),
|
|
description: format!("Rule {}", i),
|
|
action: action1.id,
|
|
action_ref: action1.r#ref.clone(),
|
|
trigger: trigger1.id,
|
|
trigger_ref: trigger1.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
RuleRepository::create(&pool, input).await.unwrap();
|
|
}
|
|
|
|
// Create 1 rule for pack2
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.rule1", pack2.r#ref),
|
|
pack: pack2.id,
|
|
pack_ref: pack2.r#ref.clone(),
|
|
label: "Pack2 Rule".to_string(),
|
|
description: "Pack2".to_string(),
|
|
action: action2.id,
|
|
action_ref: action2.r#ref.clone(),
|
|
trigger: trigger2.id,
|
|
trigger_ref: trigger2.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
RuleRepository::create(&pool, input).await.unwrap();
|
|
|
|
let pack1_rules = RuleRepository::find_by_pack(&pool, pack1.id).await.unwrap();
|
|
|
|
assert_eq!(pack1_rules.len(), 2);
|
|
assert!(pack1_rules.iter().all(|r| r.pack == pack1.id));
|
|
|
|
let pack2_rules = RuleRepository::find_by_pack(&pool, pack2.id).await.unwrap();
|
|
|
|
assert_eq!(pack2_rules.len(), 1);
|
|
assert_eq!(pack2_rules[0].pack, pack2.id);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_find_rules_by_action() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let pack = PackFixture::new_unique("action_pack")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action1 = ActionFixture::new_unique(pack.id, &pack.r#ref, "action1")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action2 = ActionFixture::new_unique(pack.id, &pack.r#ref, "action2")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger = TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "trigger")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Create 2 rules for action1
|
|
for i in 1..=2 {
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.rule_a1_{}", pack.r#ref, i),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: format!("Action1 Rule {}", i),
|
|
description: "Test".to_string(),
|
|
action: action1.id,
|
|
action_ref: action1.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
RuleRepository::create(&pool, input).await.unwrap();
|
|
}
|
|
|
|
// Create 1 rule for action2
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.rule_a2_1", pack.r#ref),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: "Action2 Rule".to_string(),
|
|
description: "Test".to_string(),
|
|
action: action2.id,
|
|
action_ref: action2.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
RuleRepository::create(&pool, input).await.unwrap();
|
|
|
|
let action1_rules = RuleRepository::find_by_action(&pool, action1.id)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(action1_rules.len(), 2);
|
|
assert!(action1_rules.iter().all(|r| r.action == action1.id));
|
|
|
|
let action2_rules = RuleRepository::find_by_action(&pool, action2.id)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(action2_rules.len(), 1);
|
|
assert_eq!(action2_rules[0].action, action2.id);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_find_rules_by_trigger() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let pack = PackFixture::new_unique("trigger_pack")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action = ActionFixture::new_unique(pack.id, &pack.r#ref, "action")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger1 = TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "trigger1")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger2 = TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "trigger2")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Create 2 rules for trigger1
|
|
for i in 1..=2 {
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.rule_t1_{}", pack.r#ref, i),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: format!("Trigger1 Rule {}", i),
|
|
description: "Test".to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger1.id,
|
|
trigger_ref: trigger1.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
RuleRepository::create(&pool, input).await.unwrap();
|
|
}
|
|
|
|
// Create 1 rule for trigger2
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.rule_t2_1", pack.r#ref),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: "Trigger2 Rule".to_string(),
|
|
description: "Test".to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger2.id,
|
|
trigger_ref: trigger2.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
RuleRepository::create(&pool, input).await.unwrap();
|
|
|
|
let trigger1_rules = RuleRepository::find_by_trigger(&pool, trigger1.id)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(trigger1_rules.len(), 2);
|
|
assert!(trigger1_rules.iter().all(|r| r.trigger == trigger1.id));
|
|
|
|
let trigger2_rules = RuleRepository::find_by_trigger(&pool, trigger2.id)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(trigger2_rules.len(), 1);
|
|
assert_eq!(trigger2_rules[0].trigger, trigger2.id);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_find_enabled_rules() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let pack = PackFixture::new_unique("enabled_filter_pack")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action = ActionFixture::new_unique(pack.id, &pack.r#ref, "action")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger = TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "trigger")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Create enabled rules
|
|
for i in 1..=2 {
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.enabled_{}", pack.r#ref, i),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: format!("Enabled {}", i),
|
|
description: "Test".to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
RuleRepository::create(&pool, input).await.unwrap();
|
|
}
|
|
|
|
// Create disabled rules
|
|
for i in 1..=2 {
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.disabled_{}", pack.r#ref, i),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: format!("Disabled {}", i),
|
|
description: "Test".to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: false,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
RuleRepository::create(&pool, input).await.unwrap();
|
|
}
|
|
|
|
let enabled_rules = RuleRepository::find_enabled(&pool).await.unwrap();
|
|
|
|
// Filter to only our pack's rules
|
|
let our_enabled: Vec<_> = enabled_rules
|
|
.iter()
|
|
.filter(|r| r.r#ref.starts_with(&pack.r#ref))
|
|
.collect();
|
|
|
|
assert_eq!(our_enabled.len(), 2);
|
|
assert!(our_enabled.iter().all(|r| r.enabled));
|
|
}
|
|
|
|
// ============================================================================
|
|
// FOREIGN KEY CONSTRAINT Tests
|
|
// ============================================================================
|
|
|
|
#[tokio::test]
|
|
async fn test_cascade_delete_pack_deletes_rules() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let pack = PackFixture::new_unique("cascade_pack")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action = ActionFixture::new_unique(pack.id, &pack.r#ref, "action")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger = TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "trigger")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.cascade_rule", pack.r#ref),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: "Cascade Rule".to_string(),
|
|
description: "Will be cascade deleted".to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
let rule = RuleRepository::create(&pool, input).await.unwrap();
|
|
|
|
// Delete the pack
|
|
sqlx::query("DELETE FROM pack WHERE id = $1")
|
|
.bind(pack.id)
|
|
.execute(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
// Rule should be cascade deleted
|
|
let found = RuleRepository::find_by_id(&pool, rule.id).await.unwrap();
|
|
|
|
assert!(found.is_none());
|
|
}
|
|
|
|
// ============================================================================
|
|
// TIMESTAMP Tests
|
|
// ============================================================================
|
|
|
|
#[tokio::test]
|
|
async fn test_rule_timestamps() {
|
|
let pool = create_test_pool().await.unwrap();
|
|
|
|
let pack = PackFixture::new_unique("timestamp_pack")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let action = ActionFixture::new_unique(pack.id, &pack.r#ref, "action")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let trigger = TriggerFixture::new_unique(Some(pack.id), Some(pack.r#ref.clone()), "trigger")
|
|
.create(&pool)
|
|
.await
|
|
.unwrap();
|
|
|
|
let input = CreateRuleInput {
|
|
r#ref: format!("{}.ts_rule", pack.r#ref),
|
|
pack: pack.id,
|
|
pack_ref: pack.r#ref.clone(),
|
|
label: "Timestamp Rule".to_string(),
|
|
description: "Test timestamps".to_string(),
|
|
action: action.id,
|
|
action_ref: action.r#ref.clone(),
|
|
trigger: trigger.id,
|
|
trigger_ref: trigger.r#ref.clone(),
|
|
conditions: json!([]),
|
|
action_params: json!({}),
|
|
trigger_params: json!({}),
|
|
enabled: true,
|
|
is_adhoc: false,
|
|
};
|
|
|
|
let created = RuleRepository::create(&pool, input).await.unwrap();
|
|
|
|
assert!(created.created.timestamp() > 0);
|
|
assert!(created.updated.timestamp() > 0);
|
|
assert_eq!(created.created, created.updated);
|
|
|
|
// Sleep briefly to ensure timestamp difference
|
|
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
|
|
|
|
let update = UpdateRuleInput {
|
|
label: Some("Updated".to_string()),
|
|
..Default::default()
|
|
};
|
|
|
|
let updated = RuleRepository::update(&pool, created.id, update)
|
|
.await
|
|
.unwrap();
|
|
|
|
assert_eq!(updated.created, created.created); // created unchanged
|
|
assert!(updated.updated > created.updated); // updated changed
|
|
}
|