use super::*;
#[tokio::test(flavor = "multi_thread")]
async fn repository_navigator_warms_in_background_and_joins_complete() {
let workspace = tempfile::TempDir::new().unwrap();
std::fs::write(
workspace.path().join("main.rs"),
"pub fn warm_marker() {}\n",
)
.unwrap();
let workspace = workspace.path().to_string_lossy().into_owned();
let rt = tokio::runtime::Handle::current();
let mut warmup = Some(spawn_nav_warmup(
&rt,
&workspace,
&newt_core::Config::default(),
&newt_core::IndexStatus::default(),
));
let job = warmup.as_ref().unwrap().job.clone();
let mut where_is = None;
let mut nav = newt_core::NavigatorSession::default();
let deadline = std::time::Instant::now() + newt_core::test_guard::HANG_GUARD;
while !warmup.as_ref().is_some_and(|w| w.handle.is_finished()) {
assert!(
std::time::Instant::now() < deadline,
"the warm-up build never finished"
);
tokio::task::yield_now().await;
}
finish_nav_warmup(&rt, &mut warmup, &mut where_is, &mut nav);
assert!(warmup.is_none(), "a finished warm-up must be adopted");
assert!(
!job.is_running(),
"joining the warm-up must clear its generic liveness indicator"
);
assert!(where_is.is_some());
assert!(
nav.files.iter().any(|(path, _)| path == "main.rs"),
"the joined navigator must contain the real source file"
);
assert!(nav.usage.is_some() && nav.graph.is_some());
}
#[tokio::test(flavor = "multi_thread")]
async fn semantic_indexing_never_blocks_the_turn() {
struct GatedEmbedder(std::sync::Arc<tokio::sync::Notify>);
#[async_trait::async_trait]
impl newt_core::Embedder for GatedEmbedder {
async fn embed(&self, _text: &str) -> anyhow::Result<Vec<f32>> {
self.0.notified().await;
Ok(vec![1.0, 0.0])
}
}
let rt = tokio::runtime::Handle::current();
let release = std::sync::Arc::new(tokio::sync::Notify::new());
let embedder: std::sync::Arc<dyn newt_core::Embedder> =
std::sync::Arc::new(GatedEmbedder(std::sync::Arc::clone(&release)));
let index = std::sync::Arc::new(newt_core::SessionSemanticIndex::default());
let files = vec![("main.rs".to_string(), "pub fn f() {}".to_string())];
let mut warmup = Some(spawn_semantic_indexing(
&rt,
files,
embedder,
std::sync::Arc::clone(&index),
newt_core::OnEmbedFailure::default(),
));
assert!(
poll_semantic_indexing(&rt, &mut warmup).is_none(),
"an unfinished embed is never joined"
);
assert!(warmup.is_some(), "the running embed is left running");
{
use newt_core::SemanticIndex as _;
assert_eq!(index.chunks_indexed(), 0, "nothing adopted early");
}
release.notify_one();
let deadline = std::time::Instant::now() + newt_core::test_guard::HANG_GUARD;
while !warmup.as_ref().is_some_and(|w| w.handle.is_finished()) {
assert!(
std::time::Instant::now() < deadline,
"the released embed never finished"
);
tokio::task::yield_now().await;
}
let adopted = poll_semantic_indexing(&rt, &mut warmup);
assert!(warmup.is_none(), "a finished embed is consumed");
assert!(
adopted.is_some_and(|n| n >= 1),
"the finished embed reports its chunk count, got {adopted:?}"
);
}
#[tokio::test(flavor = "multi_thread")]
async fn unfinished_warmup_is_left_running_and_the_turn_degrades() {
let rt = tokio::runtime::Handle::current();
let (release, gate) = std::sync::mpsc::channel::<()>();
let job = BackgroundJob::start("indexing repository");
let completion = job.completion_guard();
let handle = rt.spawn_blocking(move || {
let _completion = completion;
let _ = gate.recv();
(None, newt_core::NavigatorSession::default())
});
let mut warmup = Some(NavWarmup { handle, job });
let mut where_is = None;
let mut nav = newt_core::NavigatorSession::default();
finish_nav_warmup(&rt, &mut warmup, &mut where_is, &mut nav);
assert!(
warmup.is_some(),
"a still-running warm-up must be left running for a later turn"
);
assert!(
where_is.is_none(),
"nothing adopted from an unfinished build"
);
release.send(()).unwrap();
let deadline = std::time::Instant::now() + newt_core::test_guard::HANG_GUARD;
while !warmup.as_ref().is_some_and(|w| w.handle.is_finished()) {
assert!(
std::time::Instant::now() < deadline,
"the released build never finished"
);
tokio::task::yield_now().await;
}
finish_nav_warmup(&rt, &mut warmup, &mut where_is, &mut nav);
assert!(warmup.is_none(), "the finished build is adopted next turn");
}