address review: switch hive-c0re to hive-jobq-wire's shared parse_states/filter_nodes_by_state, note the generic shape in endpoint docs
This commit is contained in:
parent
08efd7875e
commit
eae04ac2c5
3 changed files with 29 additions and 108 deletions
|
|
@ -351,15 +351,16 @@ impl JobQueue {
|
|||
/// still-matching descendant one level higher rather than hiding or
|
||||
/// orphaning it.
|
||||
///
|
||||
/// The projection itself is [`hive_jobq_wire`]'s; all this layer supplies
|
||||
/// is *which* nodes to show — see [`visible_roots`] for why the graph
|
||||
/// can't decide the root-visibility half of that for itself.
|
||||
/// The projection and state filter are both [`hive_jobq_wire`]'s; this
|
||||
/// layer only supplies *which roots* are in view (see [`visible_roots`]
|
||||
/// for why the graph can't decide that itself) — an older, different
|
||||
/// question than state filtering, and neither replaces the other.
|
||||
#[must_use]
|
||||
pub fn graph_snapshot(&self, states: Option<&[State]>) -> Vec<GraphNode> {
|
||||
let inner = self.lock();
|
||||
let roots = visible_roots(&inner);
|
||||
let nodes = inner.graph().wire_snapshot(roots);
|
||||
filter_nodes_by_state(nodes, states)
|
||||
hive_jobq_wire::filter_nodes_by_state(nodes, states)
|
||||
}
|
||||
|
||||
/// Per-state counts over the **same** groups [`JobQueue::graph_snapshot`]
|
||||
|
|
@ -414,26 +415,6 @@ fn find_node(sched: &Sched, id: u64) -> Option<NodeId> {
|
|||
.find_map(|n| (n.id.get() == id).then_some(n.id))
|
||||
}
|
||||
|
||||
/// [`JobQueue::graph_snapshot`]'s `states` ask, applied to the already-
|
||||
/// projected node list: keeps every node — root or descendant — whose own
|
||||
/// `state` is named.
|
||||
///
|
||||
/// Applied *after* [`GraphWire::wire_snapshot`] rather than as a root
|
||||
/// pre-filter — narrowing which roots are visible at all is
|
||||
/// [`visible_roots`]'s job (a different question: how much settled work is
|
||||
/// retained, full stop); this is "of what's retained and live, which
|
||||
/// individual nodes does the caller want shown right now." `None` (or an
|
||||
/// unrecognised/absent query) is the identity filter.
|
||||
fn filter_nodes_by_state(nodes: Vec<GraphNode>, states: Option<&[State]>) -> Vec<GraphNode> {
|
||||
let Some(states) = states else {
|
||||
return nodes;
|
||||
};
|
||||
nodes
|
||||
.into_iter()
|
||||
.filter(|n| states.contains(&n.state))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// The visible **group** set for [`JobQueue::graph_snapshot`]: every live group
|
||||
/// root, plus the newest [`MAX_HISTORY_DAGS`] settled ones.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -1527,60 +1527,6 @@ fn graph_snapshot_states_filters_by_node_state() {
|
|||
);
|
||||
}
|
||||
|
||||
/// One hand-built node, bypassing the scheduler entirely — `filter_nodes_by_state`
|
||||
/// is a pure `Vec<GraphNode> -> Vec<GraphNode>` transform, so this exercises it
|
||||
/// directly rather than trying (and failing, per this module's own rule) to
|
||||
/// drive a live group into a genuinely mixed state through the real queue.
|
||||
fn node(id: u64, parent: Option<u64>, state: State) -> GraphNode {
|
||||
GraphNode {
|
||||
id,
|
||||
parent,
|
||||
state,
|
||||
deps: Vec::new(),
|
||||
created_at: Utc::now(),
|
||||
started_at: None,
|
||||
finished_at: None,
|
||||
error: None,
|
||||
payload: hive_jobq_wire::NodePayload {
|
||||
label: id.to_string(),
|
||||
data: serde_json::Value::Null,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// The case `graph_snapshot_states_filters_by_node_state` above can't reach:
|
||||
/// a still-live group (root `Running`) holding a mix of already-`Done` and
|
||||
/// still-`Pending` steps. Filtering out `Done` must drop exactly the `Done`
|
||||
/// node and nothing else — the root and the `Pending` sibling both stay,
|
||||
/// even though the root itself isn't in the requested state set.
|
||||
#[test]
|
||||
fn filter_nodes_by_state_keeps_matching_nodes_from_a_mixed_state_tree() {
|
||||
let nodes = vec![
|
||||
node(1, None, State::Running), // root: whole group still live
|
||||
node(2, Some(1), State::Done), // finished step, should be hidden
|
||||
node(3, Some(1), State::Pending), // not-yet-run step, should stay
|
||||
];
|
||||
|
||||
let mut kept: Vec<u64> =
|
||||
filter_nodes_by_state(nodes.clone(), Some(&[State::Running, State::Pending]))
|
||||
.into_iter()
|
||||
.map(|n| n.id)
|
||||
.collect();
|
||||
kept.sort_unstable();
|
||||
assert_eq!(
|
||||
kept,
|
||||
vec![1, 3],
|
||||
"Done is filtered out even though its still-live parent (root) isn't"
|
||||
);
|
||||
|
||||
let mut unfiltered: Vec<u64> = filter_nodes_by_state(nodes, None)
|
||||
.into_iter()
|
||||
.map(|n| n.id)
|
||||
.collect();
|
||||
unfiltered.sort_unstable();
|
||||
assert_eq!(unfiltered, vec![1, 2, 3], "None is the identity filter");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_truncation_cuts_on_a_char_boundary() {
|
||||
// `truncate_error` is a pure `&str -> String`. This used to submit a DAG,
|
||||
|
|
|
|||
Loading…
Reference in a new issue