argand-site-registry/crates/argand-site-registry/tests/coverage.rs

133 lines
5.6 KiB
Rust

// By Nic Weyand!
//! Active coverage, delta masking, and audit-retention acceptance proof.
#[allow(dead_code)]
mod common;
use argand_site_registry::{
model::{CoverageKind, Format, Source, SourceCoverage},
query::Registry,
store,
};
use serde_json::json;
use std::fs;
#[test]
#[allow(clippy::too_many_lines)] // One scenario proves full, delta, tombstone, active, and audit behavior.
fn typed_full_and_delta_replace_active_records_but_preserve_audit_history() -> anyhow::Result<()> {
let root = tempfile::tempdir()?;
let mut db = common::fixture(root.path())?;
let original_bytes = serde_json::to_vec(&common::wikidata())?;
let original = common::manifest(Source::Wikidata, Format::WikidataEntities, &original_bytes)?;
let full_bytes = serde_json::to_vec(&common::wikidata())?;
let mut full = common::manifest(Source::Wikidata, Format::WikidataEntities, &full_bytes)?;
full.schema = "argand.site-source/v2".into();
full.snapshot = "synthetic-full-v2".into();
full.scope = "entities-full".into();
full.retrieved_at += chrono::Duration::hours(1);
full.coverage = Some(SourceCoverage {
collection: "entities".into(),
kind: CoverageKind::Full,
partition: None,
base: None,
sequence: None,
supersedes: vec![original.id()?],
});
let full_path = root.path().join("wikidata-full.json");
fs::write(&full_path, &full_bytes)?;
store::import(&mut db, &full, &full_path)?;
let delta_bytes = serde_json::to_vec(&json!({"entities":{"Q355":common::entity(
"Q355",
"Facebook",
&["Meta FB"],
&["https://facebook.com/"]
)}}))?;
let mut delta = common::manifest(Source::Wikidata, Format::WikidataEntities, &delta_bytes)?;
delta.schema = "argand.site-source/v2".into();
delta.snapshot = "synthetic-delta-v2".into();
delta.scope = "entities-delta-1".into();
delta.retrieved_at += chrono::Duration::hours(2);
delta.coverage = Some(SourceCoverage {
collection: "entities".into(),
kind: CoverageKind::Delta,
partition: None,
base: Some(full.id()?),
sequence: Some(1),
supersedes: vec![full.id()?],
});
let delta_path = root.path().join("wikidata-delta.json");
fs::write(&delta_path, &delta_bytes)?;
store::import(&mut db, &delta, &delta_path)?;
let generation = root.path().join("generation");
argand_site_registry::build::build_with_policy(
&db,
&generation,
&argand_site_registry::policy::ReviewPolicy::legacy_compatible(),
)?;
let pin = argand_site_registry::file_digest(&generation.join("COMPLETE.json"))?;
let registry = Registry::open(&generation, &pin)?;
assert_eq!(registry.lookup("FB", 20)?.total_entities, 0);
assert_eq!(registry.lookup("Meta FB", 20)?.total_entities, 1);
assert_eq!(registry.lookup("Atlas", 20)?.total_entities, 1);
let stats = registry.stats(common::timestamp()?)?;
assert_eq!(stats.selected_sources, 6);
assert_eq!(stats.superseded_source_snapshots, 1);
let active = root.path().join("active.jsonl");
let audit = root.path().join("audit.jsonl");
argand_site_registry::release::export(&registry, &active, false)?;
argand_site_registry::release::export_audit(&registry, &audit, false)?;
let active = fs::read_to_string(active)?;
let audit = fs::read_to_string(audit)?;
assert!(!active.contains("\"text\":\"FB\""));
assert!(active.contains("\"text\":\"Meta FB\""));
assert!(audit.contains("\"selection_state\":\"superseded\""));
assert!(audit.contains("\"text\":\"FB\""));
let tombstone_bytes = serde_json::to_vec(&json!({"entities":{"Q355":{
"id":"Q355",
"missing":""
}}}))?;
let mut tombstone =
common::manifest(Source::Wikidata, Format::WikidataEntities, &tombstone_bytes)?;
tombstone.schema = "argand.site-source/v2".into();
tombstone.snapshot = "synthetic-delta-v2-tombstone".into();
tombstone.scope = "entities-delta-2".into();
tombstone.retrieved_at += chrono::Duration::hours(3);
tombstone.coverage = Some(SourceCoverage {
collection: "entities".into(),
kind: CoverageKind::Delta,
partition: None,
base: Some(delta.id()?),
sequence: Some(2),
supersedes: vec![delta.id()?],
});
let tombstone_path = root.path().join("wikidata-tombstone.json");
fs::write(&tombstone_path, &tombstone_bytes)?;
store::import(&mut db, &tombstone, &tombstone_path)?;
let retired_path = root.path().join("retired");
argand_site_registry::build::build_with_policy(
&db,
&retired_path,
&argand_site_registry::policy::ReviewPolicy::legacy_compatible(),
)?;
let retired_pin = argand_site_registry::file_digest(&retired_path.join("COMPLETE.json"))?;
let retired = Registry::open(&retired_path, &retired_pin)?;
assert_eq!(retired.lookup("Facebook", 20)?.total_entities, 0);
assert_eq!(retired.lookup("Meta FB", 20)?.total_entities, 0);
let retired_active = root.path().join("retired-active.jsonl");
let retired_audit = root.path().join("retired-audit.jsonl");
argand_site_registry::release::export(&retired, &retired_active, false)?;
argand_site_registry::release::export_audit(&retired, &retired_audit, false)?;
assert!(
!fs::read_to_string(retired_active)?
.contains("\"subject\":\"argand:entity:wikidata:Q355\"")
);
let retired_audit = fs::read_to_string(retired_audit)?;
assert!(retired_audit.contains("\"type\":\"tombstone\""));
assert!(retired_audit.contains("\"selection_state\":\"tombstoned\""));
assert!(retired_audit.contains("\"source_identifier\":\"Q355\""));
Ok(())
}