Skip to content

Commit

Permalink
Add an invalidation unit test to replace some integration-level tests…
Browse files Browse the repository at this point in the history
… on the python side.
  • Loading branch information
stuhood committed Jul 3, 2018
1 parent 43f2aae commit 27455ef
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 10 deletions.
41 changes: 40 additions & 1 deletion src/rust/engine/graph/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -791,7 +791,7 @@ impl<'a, N: Node + 'a, P: Fn(EntryId, Level) -> bool> Iterator for LeveledWalk<'

#[cfg(test)]
mod tests {
use std::sync::Arc;
use std::sync::{Arc, Mutex};
use std::thread;

use boxfuture::{BoxFuture, Boxable};
Expand All @@ -810,6 +810,29 @@ mod tests {
);
}

#[test]
fn invalidate() {
let graph = Arc::new(Graph::new());
let context = TContext::new(graph.clone());

// Create three nodes.
assert_eq!(
graph.create(TNode(2), &context).wait(),
Ok("2/1/0".to_string())
);
assert_eq!(context.spawn_count(), 3);

// Invalidate and re-request the upper two nodes.
assert_eq!(graph.invalidate_from_roots(|&TNode(n)| n == 1), 2);

// Confirm that the right number of nodes re-run.
assert_eq!(
graph.create(TNode(2), &context).wait(),
Ok("2/1/0".to_string())
);
assert_eq!(context.spawn_count(), 5);
}

///
/// A node that builds a string by recursively requesting itself and prepending its value
/// to the result.
Expand Down Expand Up @@ -842,16 +865,25 @@ mod tests {
}
}

///
/// A context that keeps a count of spawned Nodes. This is a very basic way to confirm that Nodes
/// have (re-)run.
///
/// TODO: This is potentially error prone, but is much simpler than actually tracking precisely
/// which Nodes ran and in which order. Future work.
///
#[derive(Clone)]
struct TContext {
graph: Arc<Graph<TNode>>,
spawn_count: Arc<Mutex<usize>>,
entry_id: Option<EntryId>,
}
impl NodeContext for TContext {
type Node = TNode;
fn clone_for(&self, entry_id: EntryId) -> TContext {
TContext {
graph: self.graph.clone(),
spawn_count: self.spawn_count.clone(),
entry_id: Some(entry_id),
}
}
Expand All @@ -868,20 +900,27 @@ mod tests {
thread::spawn(move || {
future.wait().unwrap();
});
let mut spawn_count = self.spawn_count.lock().unwrap();
*spawn_count += 1
}
}

impl TContext {
fn new(graph: Arc<Graph<TNode>>) -> TContext {
TContext {
graph,
spawn_count: Arc::new(Mutex::new(0)),
entry_id: None,
}
}

fn get(&self, dst: TNode) -> BoxFuture<String, TError> {
self.graph.get(self.entry_id.unwrap(), self, dst)
}

fn spawn_count(&self) -> usize {
*self.spawn_count.lock().unwrap()
}
}

#[derive(Clone, Debug, Eq, PartialEq)]
Expand Down
11 changes: 2 additions & 9 deletions tests/python/pants_test/engine/legacy/test_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,28 +141,21 @@ def test_inject_bad_dir(self):
class GraphInvalidationTest(GraphTestBase):

def test_invalidate_fsnode(self):
# NB: Invalidation is now more directly tested in unit tests in the `graph` crate.
with self.open_scheduler(['3rdparty/python::']) as (_, _, scheduler):
initial_node_count = scheduler.node_count()
self.assertGreater(initial_node_count, 0)

invalidated_count = scheduler.invalidate_files(['3rdparty/python/BUILD'])
self.assertGreater(invalidated_count, 0)
self.assertLess(scheduler.node_count(), initial_node_count)

def test_invalidate_fsnode_incremental(self):
# NB: Invalidation is now more directly tested in unit tests in the `graph` crate.
with self.open_scheduler(['//:', '3rdparty/::']) as (_, _, scheduler):
node_count = scheduler.node_count()
self.assertGreater(node_count, 0)

# Invalidate the '3rdparty/python' DirectoryListing, the `3rdparty` DirectoryListing,
# and then the root DirectoryListing by "touching" files/dirs.
for filename in ('3rdparty/python/BUILD', '3rdparty/jvm', 'non_existing_file'):
invalidated_count = scheduler.invalidate_files([filename])
self.assertGreater(invalidated_count,
0,
'File {} did not invalidate any Nodes.'.format(filename))
node_count, last_node_count = scheduler.node_count(), node_count
self.assertLess(node_count, last_node_count)

def _ordering_test(self, spec, expected_sources=None):
expected_sources = expected_sources or ['p', 'a', 'n', 't', 's', 'b', 'u', 'i', 'l', 'd']
Expand Down

0 comments on commit 27455ef

Please sign in to comment.