use db::Db; use db::audit; use domain::{AuditAction, AuditActor, FieldChange, NewAuditEvent}; use serde_json::json; use sqlx::PgPool; use uuid::Uuid; fn created(entity_id: Uuid, name: &str) -> NewAuditEvent { NewAuditEvent { actor: AuditActor::System, action: AuditAction::Created, entity_type: "object".into(), entity_id, changes: vec![FieldChange { field: "name".into(), before: None, after: Some(json!(name)), }], } } #[sqlx::test] async fn records_and_reads_back_history_in_order(pool: PgPool) { let db = Db::from_pool(pool); let id = Uuid::new_v4(); let user = Uuid::new_v4(); audit::record(db.pool(), &created(id, "Vase")) .await .unwrap(); audit::record( db.pool(), &NewAuditEvent { actor: AuditActor::User(user), action: AuditAction::Updated, entity_type: "object".into(), entity_id: id, changes: vec![FieldChange { field: "name".into(), before: Some(json!("Vase")), after: Some(json!("Roman Vase")), }], }, ) .await .unwrap(); let history = audit::history_for(db.pool(), "object", id).await.unwrap(); assert_eq!(history.len(), 2); assert_eq!(history[0].action, AuditAction::Created); assert_eq!(history[0].actor, AuditActor::System); assert_eq!(history[1].action, AuditAction::Updated); assert_eq!(history[1].actor, AuditActor::User(user)); assert!(history[0].seq < history[1].seq, "ordered by seq"); assert_eq!(history[1].changes[0].field, "name"); assert_eq!(history[1].changes[0].after, Some(json!("Roman Vase"))); } #[sqlx::test] async fn history_is_scoped_to_one_entity(pool: PgPool) { let db = Db::from_pool(pool); let a = Uuid::new_v4(); let b = Uuid::new_v4(); audit::record(db.pool(), &created(a, "A")).await.unwrap(); audit::record(db.pool(), &created(b, "B")).await.unwrap(); let only_a = audit::history_for(db.pool(), "object", a).await.unwrap(); assert_eq!(only_a.len(), 1); assert_eq!(only_a[0].entity_id, a); }