Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 123 additions & 0 deletions tests/http_api/schema_audit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -488,3 +488,126 @@ fn validate_refuses_an_invalid_proposed_document() {
assert_eq!(status, 400, "{body}");
assert_eq!(body["code"], "invalid_argument", "{body}");
}

// --- MAX_AUDIT_NAMES (100): each name-list section truncates -----------

/// `untyped_concepts` past `MAX_AUDIT_NAMES` (100): `total` reports the
/// true count, `names` is a name-ordered (`BTreeSet`) prefix capped at
/// 100 — zero-padded objects keep lexicographic and numeric order
/// identical, so the excluded one is deterministically the highest.
#[test]
fn audit_untyped_concepts_truncates_past_max_audit_names() {
let server = Server::start("schema-audit-untyped-cap");
server.ok("PUT", "/contexts/sake", Some(json!({"description": "d"})));
let mut ops: Vec<serde_json::Value> = vec![json!({
"subject": "青嶺酒造", "label": "schema:type", "object": "Brewery",
"weight": 1.0, "source": "a.md",
})];
ops.extend((0..101).map(|i| {
json!({
"subject": "青嶺酒造", "label": "所在地", "object": format!("個人{i:03}"),
"weight": 1.0, "source": "a.md",
})
}));
server.ok(
"POST",
"/contexts/sake/associations",
Some(serde_json::Value::Array(ops)),
);
server.ok("PUT", "/contexts/sake/schema", Some(strict_document()));

let audit = server.ok("POST", "/contexts/sake/schema/audit", None);
assert_eq!(audit["untyped_concepts"]["total"], json!(101), "{audit}");
let names: Vec<&str> = audit["untyped_concepts"]["names"]
.as_array()
.unwrap()
.iter()
.map(|v| v.as_str().unwrap())
.collect();
assert_eq!(names.len(), 100, "{audit}");
assert!(names.contains(&"個人000"), "{audit:?}");
assert!(names.contains(&"個人099"), "{audit:?}");
assert!(
!names.contains(&"個人100"),
"the 101st name (highest-ordered) is the one past the cap: {names:?}"
);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

/// `undeclared_types` past `MAX_AUDIT_NAMES` (100) — same truncation
/// contract, over asserted `schema:type` objects instead.
#[test]
fn audit_undeclared_types_truncates_past_max_audit_names() {
let server = Server::start("schema-audit-undeclared-cap");
server.ok("PUT", "/contexts/sake", Some(json!({"description": "d"})));
let ops: Vec<serde_json::Value> = (0..101)
.map(|i| {
json!({
"subject": format!("組織{i:03}"), "label": "schema:type", "object": format!("型{i:03}"),
"weight": 1.0, "source": "a.md",
})
})
.collect();
server.ok(
"POST",
"/contexts/sake/associations",
Some(serde_json::Value::Array(ops)),
);
server.ok("PUT", "/contexts/sake/schema", Some(strict_document()));

let audit = server.ok("POST", "/contexts/sake/schema/audit", None);
assert_eq!(audit["undeclared_types"]["total"], json!(101), "{audit}");
let names: Vec<&str> = audit["undeclared_types"]["names"]
.as_array()
.unwrap()
.iter()
.map(|v| v.as_str().unwrap())
.collect();
assert_eq!(names.len(), 100, "{audit}");
assert!(names.contains(&"型000"), "{audit:?}");
assert!(names.contains(&"型099"), "{audit:?}");
assert!(
!names.contains(&"型100"),
"the 101st name (highest-ordered) is the one past the cap: {names:?}"
);
}

/// `unknown_labels` past `MAX_AUDIT_NAMES` (100) — only populated under
/// `closed_labels`, same truncation contract as the other two sections.
#[test]
fn audit_unknown_labels_truncates_past_max_audit_names() {
let server = Server::start("schema-audit-unknown-labels-cap");
server.ok("PUT", "/contexts/sake", Some(json!({"description": "d"})));
let ops: Vec<serde_json::Value> = (0..101)
.map(|i| {
json!({
"subject": format!("s{i:03}"), "label": format!("未知{i:03}"), "object": format!("o{i:03}"),
"weight": 1.0, "source": "a.md",
})
})
.collect();
server.ok(
"POST",
"/contexts/sake/associations",
Some(serde_json::Value::Array(ops)),
);
let mut document = strict_document();
document["mode"] = json!("warn");
document["closed_labels"] = json!(true);
server.ok("PUT", "/contexts/sake/schema", Some(document));

let audit = server.ok("POST", "/contexts/sake/schema/audit", None);
assert_eq!(audit["unknown_labels"]["total"], json!(101), "{audit}");
let names: Vec<&str> = audit["unknown_labels"]["names"]
.as_array()
.unwrap()
.iter()
.map(|v| v.as_str().unwrap())
.collect();
assert_eq!(names.len(), 100, "{audit}");
assert!(names.contains(&"未知000"), "{audit:?}");
assert!(names.contains(&"未知099"), "{audit:?}");
assert!(
!names.contains(&"未知100"),
"the 101st name (highest-ordered) is the one past the cap: {names:?}"
);
}