295 lines
12 KiB
Rust
295 lines
12 KiB
Rust
use std::fs;
|
|
|
|
use serde::Deserialize;
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct G3CandidateBatch {
|
|
#[serde(rename = "batchId")]
|
|
batch_id: String,
|
|
family: String,
|
|
source: String,
|
|
#[serde(rename = "ledgerClusterLabel")]
|
|
ledger_cluster_label: String,
|
|
#[serde(rename = "selectionRule")]
|
|
selection_rule: String,
|
|
#[serde(rename = "candidateCount")]
|
|
candidate_count: u32,
|
|
#[serde(rename = "representativeBaseline")]
|
|
representative_baseline: String,
|
|
#[serde(rename = "firstExpansionBaseline")]
|
|
first_expansion_baseline: String,
|
|
#[serde(rename = "promotedBatchExpansionBaselines")]
|
|
promoted_batch_expansion_baselines: Vec<PromotedExpansionBaseline>,
|
|
#[serde(rename = "expectedSharedContract")]
|
|
expected_shared_contract: SharedContract,
|
|
candidates: Vec<BatchCandidate>,
|
|
notes: Vec<String>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct SharedContract {
|
|
archetype: String,
|
|
#[serde(rename = "requiredPaginationFields")]
|
|
required_pagination_fields: Vec<String>,
|
|
#[serde(rename = "requiredJoinKeyPatterns")]
|
|
required_join_key_patterns: Vec<String>,
|
|
#[serde(rename = "requiredAggregateRulePatterns")]
|
|
required_aggregate_rule_patterns: Vec<String>,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct PromotedExpansionBaseline {
|
|
#[serde(rename = "fixtureDir")]
|
|
fixture_dir: String,
|
|
#[serde(rename = "sceneId")]
|
|
scene_id: String,
|
|
#[serde(rename = "sceneName")]
|
|
scene_name: String,
|
|
assertions: ExpansionAssertions,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct ExpansionAssertions {
|
|
#[serde(rename = "expectedPaginationField")]
|
|
expected_pagination_field: String,
|
|
#[serde(rename = "requiredJoinKey")]
|
|
required_join_key: String,
|
|
#[serde(rename = "requiredAggregateRule")]
|
|
required_aggregate_rule: String,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
struct BatchCandidate {
|
|
#[serde(rename = "sceneKey")]
|
|
scene_key: String,
|
|
#[serde(rename = "ledgerGroupingResult")]
|
|
ledger_grouping_result: String,
|
|
#[serde(rename = "ledgerFamilyJudgement")]
|
|
ledger_family_judgement: String,
|
|
#[serde(rename = "batchRole")]
|
|
batch_role: String,
|
|
}
|
|
|
|
#[test]
|
|
fn g3_candidate_batch_asset_is_actionable() {
|
|
let batch = load_batch();
|
|
|
|
assert_eq!(
|
|
batch.batch_id,
|
|
"g3-95598-ticket-family-candidates-2026-04-18"
|
|
);
|
|
assert_eq!(batch.family, "G3");
|
|
assert!(batch.source.ends_with(".json"));
|
|
assert_eq!(batch.ledger_cluster_label, "95598-ticket-family-candidate");
|
|
assert!(batch
|
|
.selection_rule
|
|
.contains("95598-ticket-family-candidate"));
|
|
assert_eq!(batch.candidate_count, 11);
|
|
assert_eq!(
|
|
batch.expected_shared_contract.archetype,
|
|
"paginated_enrichment"
|
|
);
|
|
assert!(batch
|
|
.expected_shared_contract
|
|
.required_pagination_fields
|
|
.iter()
|
|
.any(|item| item == "pageNum"));
|
|
assert!(batch
|
|
.expected_shared_contract
|
|
.required_pagination_fields
|
|
.iter()
|
|
.any(|item| item == "pageNo"));
|
|
assert!(batch
|
|
.expected_shared_contract
|
|
.required_join_key_patterns
|
|
.iter()
|
|
.any(|item| item == "ticketNo"));
|
|
assert!(batch
|
|
.expected_shared_contract
|
|
.required_aggregate_rule_patterns
|
|
.iter()
|
|
.any(|item| item == "aggregate:riskLevel"));
|
|
assert_eq!(batch.candidates.len() as u32, batch.candidate_count);
|
|
assert_eq!(batch.promoted_batch_expansion_baselines.len(), 10);
|
|
assert!(!batch.notes.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn g3_candidate_batch_promotes_second_round_expansion_baselines() {
|
|
let batch = load_batch();
|
|
|
|
assert!(batch
|
|
.promoted_batch_expansion_baselines
|
|
.iter()
|
|
.any(|item| item
|
|
.fixture_dir
|
|
.ends_with("paginated_enrichment_expansion_workorder")
|
|
&& item.scene_id == "p1-g3-paginated-expansion-workorder-report"
|
|
&& item.scene_name == "P1 G3 paginated expansion workorder report"
|
|
&& item.assertions.expected_pagination_field == "pageNo"
|
|
&& item.assertions.required_join_key == "workOrderNo"
|
|
&& item.assertions.required_aggregate_rule == "aggregate:sourceType"));
|
|
assert!(batch
|
|
.promoted_batch_expansion_baselines
|
|
.iter()
|
|
.any(|item| item
|
|
.fixture_dir
|
|
.ends_with("paginated_enrichment_expansion_orderno")
|
|
&& item.scene_id == "p1-g3-paginated-expansion-orderno-report"
|
|
&& item.scene_name == "P1 G3 paginated expansion orderno report"
|
|
&& item.assertions.expected_pagination_field == "page"
|
|
&& item.assertions.required_join_key == "orderNo"
|
|
&& item.assertions.required_aggregate_rule == "aggregate:sourceType"));
|
|
assert!(batch
|
|
.promoted_batch_expansion_baselines
|
|
.iter()
|
|
.any(|item| item
|
|
.fixture_dir
|
|
.ends_with("paginated_enrichment_expansion_source_distribution")
|
|
&& item.scene_id == "p1-g3-paginated-expansion-source-distribution-report"
|
|
&& item.scene_name == "P1 G3 paginated expansion source distribution report"
|
|
&& item.assertions.expected_pagination_field == "pageNum"
|
|
&& item.assertions.required_join_key == "ticketNo"
|
|
&& item.assertions.required_aggregate_rule == "aggregate:sourceType"));
|
|
assert!(batch
|
|
.promoted_batch_expansion_baselines
|
|
.iter()
|
|
.any(|item| item
|
|
.fixture_dir
|
|
.ends_with("paginated_enrichment_expansion_service_risk")
|
|
&& item.scene_id == "p1-g3-paginated-expansion-service-risk-report"
|
|
&& item.scene_name == "P1 G3 paginated expansion service risk report"
|
|
&& item.assertions.expected_pagination_field == "pageNo"
|
|
&& item.assertions.required_join_key == "ticketNo"
|
|
&& item.assertions.required_aggregate_rule == "aggregate:riskLevel"));
|
|
assert!(batch
|
|
.promoted_batch_expansion_baselines
|
|
.iter()
|
|
.any(|item| item
|
|
.fixture_dir
|
|
.ends_with("paginated_enrichment_expansion_timeout_warning")
|
|
&& item.scene_id == "p1-g3-paginated-expansion-timeout-warning-report"
|
|
&& item.scene_name == "P1 G3 paginated expansion timeout warning report"
|
|
&& item.assertions.expected_pagination_field == "pageNum"
|
|
&& item.assertions.required_join_key == "ticketNo"
|
|
&& item.assertions.required_aggregate_rule == "aggregate:riskLevel"));
|
|
assert!(batch
|
|
.promoted_batch_expansion_baselines
|
|
.iter()
|
|
.any(|item| item
|
|
.fixture_dir
|
|
.ends_with("paginated_enrichment_expansion_device_monitor_weekly")
|
|
&& item.scene_id == "p1-g3-paginated-expansion-device-monitor-weekly-report"
|
|
&& item.assertions.expected_pagination_field == "pageNo"
|
|
&& item.assertions.required_join_key == "ticketNo"
|
|
&& item.assertions.required_aggregate_rule == "aggregate:sourceType"));
|
|
assert!(batch
|
|
.promoted_batch_expansion_baselines
|
|
.iter()
|
|
.any(|item| item
|
|
.fixture_dir
|
|
.ends_with("paginated_enrichment_expansion_customer_satisfaction")
|
|
&& item.scene_id == "p1-g3-paginated-expansion-customer-satisfaction-report"
|
|
&& item.assertions.expected_pagination_field == "page"
|
|
&& item.assertions.required_join_key == "ticketNo"
|
|
&& item.assertions.required_aggregate_rule == "aggregate:sourceType"));
|
|
assert!(batch
|
|
.promoted_batch_expansion_baselines
|
|
.iter()
|
|
.any(|item| item
|
|
.fixture_dir
|
|
.ends_with("paginated_enrichment_expansion_repair_return")
|
|
&& item.scene_id == "p1-g3-paginated-expansion-repair-return-report"
|
|
&& item.assertions.expected_pagination_field == "pageNum"
|
|
&& item.assertions.required_join_key == "ticketNo"
|
|
&& item.assertions.required_aggregate_rule == "aggregate:riskLevel"));
|
|
assert!(batch
|
|
.promoted_batch_expansion_baselines
|
|
.iter()
|
|
.any(|item| item
|
|
.fixture_dir
|
|
.ends_with("paginated_enrichment_expansion_repair_daily_control")
|
|
&& item.scene_id == "p1-g3-paginated-expansion-repair-daily-control-report"
|
|
&& item.assertions.expected_pagination_field == "pageNo"
|
|
&& item.assertions.required_join_key == "ticketNo"
|
|
&& item.assertions.required_aggregate_rule == "aggregate:riskLevel"));
|
|
assert!(batch
|
|
.promoted_batch_expansion_baselines
|
|
.iter()
|
|
.any(|item| item
|
|
.fixture_dir
|
|
.ends_with("paginated_enrichment_expansion_business_stats")
|
|
&& item.scene_id == "p1-g3-paginated-expansion-business-stats-report"
|
|
&& item.assertions.expected_pagination_field == "page"
|
|
&& item.assertions.required_join_key == "ticketNo"
|
|
&& item.assertions.required_aggregate_rule == "aggregate:sourceType"));
|
|
}
|
|
|
|
#[test]
|
|
fn g3_candidate_batch_keeps_anchor_and_promoted_candidates_visible() {
|
|
let batch = load_batch();
|
|
|
|
assert!(batch
|
|
.candidates
|
|
.iter()
|
|
.any(|item| item.scene_key == "95598_ticket_detail" && item.batch_role == "p0-anchor"));
|
|
assert!(batch.candidates.iter().any(|item| {
|
|
item.scene_key == "95598_ticket_12398_process_timeout_detail"
|
|
&& item.batch_role == "first-expansion-anchor"
|
|
}));
|
|
assert!(batch.candidates.iter().any(|item| {
|
|
item.scene_key == "ticket_source_distribution_analysis"
|
|
&& item.batch_role == "fourth-expansion-anchor"
|
|
}));
|
|
assert!(batch.candidates.iter().any(|item| {
|
|
item.scene_key == "process_timeout_risk_ticket_detail"
|
|
&& item.batch_role == "fifth-expansion-anchor"
|
|
}));
|
|
assert!(batch.candidates.iter().any(|item| {
|
|
item.scene_key == "ticket_timeout_warning_detail"
|
|
&& item.batch_role == "sixth-expansion-anchor"
|
|
}));
|
|
assert!(batch.candidates.iter().any(|item| {
|
|
item.scene_key == "95598_ticket_12398_device_monitor_weekly"
|
|
&& item.batch_role == "seventh-expansion-anchor"
|
|
}));
|
|
assert!(batch.candidates.iter().any(|item| {
|
|
item.scene_key == "95598_ticket_customer_satisfaction_daily"
|
|
&& item.batch_role == "eighth-expansion-anchor"
|
|
}));
|
|
assert!(batch.candidates.iter().any(|item| {
|
|
item.scene_key == "95598_ticket_repair_return_analysis"
|
|
&& item.batch_role == "ninth-expansion-anchor"
|
|
}));
|
|
assert!(batch.candidates.iter().any(|item| {
|
|
item.scene_key == "95598_ticket_repair_daily_control"
|
|
&& item.batch_role == "tenth-expansion-anchor"
|
|
}));
|
|
assert!(batch.candidates.iter().any(|item| {
|
|
item.scene_key == "power_supply_service_ticket_business_stats"
|
|
&& item.batch_role == "eleventh-expansion-anchor"
|
|
}));
|
|
assert!(batch.candidates.iter().any(|item| {
|
|
item.scene_key == "service_risk_ticket_detail"
|
|
&& item.batch_role == "third-expansion-anchor"
|
|
}));
|
|
assert!(batch.candidates.iter().all(|item| {
|
|
item.ledger_grouping_result == "95598-ticket-family-candidate"
|
|
&& item.ledger_family_judgement == "pending-regroup"
|
|
}));
|
|
assert!(batch
|
|
.representative_baseline
|
|
.ends_with("paginated_enrichment"));
|
|
assert!(batch
|
|
.first_expansion_baseline
|
|
.ends_with("paginated_enrichment_expansion"));
|
|
}
|
|
|
|
fn load_batch() -> G3CandidateBatch {
|
|
serde_json::from_str(
|
|
&fs::read_to_string("tests/fixtures/generated_scene/g3_candidate_batch_2026-04-18.json")
|
|
.unwrap(),
|
|
)
|
|
.unwrap()
|
|
}
|