Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
6 changes: 6 additions & 0 deletions crates/carchompd/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1173,6 +1173,12 @@ mod tests {
drive.points.len()
);
assert_kept_from(&sent_timed.points, &drive.points);
// At this speed a fix is due about every 20 s, so a longer gap means
// thinning threw away more than it should.
for pair in drive.points.windows(2) {
let gap = pair[1].time.unwrap() - pair[0].time.unwrap();
assert!(gap.whole_seconds() <= 25, "thinned too hard: {gap}");
}

// Export all holds both, the same as exporting each alone.
let (code, all) = http(addr, "GET", "/api/tracks/export.gpx", "").await;
Expand Down
59 changes: 58 additions & 1 deletion crates/carchompd/src/recorder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ mod tests {
(
Some(60.0),
true,
"inside road_heading: current tolerance, not a ruling",
"crossing inside road_heading counts as known",
),
(None, true, "no course: nearness alone decides"),
] {
Expand Down Expand Up @@ -620,4 +620,61 @@ mod tests {
rec.fix(source, &stopped).await.unwrap();
assert_eq!(*rec.status.borrow(), Status::default(), "idle ended it");
}

/// Needs PostGIS: see `known_road_query`. Its own database, as it commits.
/// The receiver is unplugged: no fix ever arrives to say the car stopped,
/// so only the local deadline can end the track. The car never moves, so
/// each track is too short to keep and finishing removes it. A slow start
/// can let the deadline beat queued fixes, which start another track, so
/// this waits for all of them to go rather than following one.
#[tokio::test]
#[ignore = "needs PostGIS at DATABASE_URL"]
async fn silence_ends_the_track_at_the_deadline() {
let db = crate::test_db::create("idle_deadline").await;
let source = source_id(&db, "gps", "test").await.unwrap();
let (bus, _) = tokio::sync::broadcast::channel(16);
let (status, seen) = watch::channel(Status::default());
let config = Config {
track_idle: 0.5,
..Config::default()
};
tokio::spawn(run(db.clone(), bus.clone(), status, &config));

// The recorder subscribes once it first runs, so keep sending until it
// has heard: fixes sent before then are lost. Then fall silent.
let start = OffsetDateTime::now_utc();
let mut sent = 0;
while seen.borrow().track.is_none() {
let _ = bus.send(Event {
source,
obs: Observation::Fix(Fix {
time: start + Duration::milliseconds(10 * sent),
lat: 45.5,
lon: -122.7,
alt: None,
speed: Some(20.0),
course: Some(90.0),
h_err: None,
}),
});
sent += 1;
tokio::time::sleep(std::time::Duration::from_millis(10)).await;
}

let gone = async {
loop {
let tracks: i64 = sqlx::query_scalar("SELECT count(*) FROM track")
.fetch_one(&db)
.await
.unwrap();
if tracks == 0 && seen.borrow().track.is_none() {
return;
}
tokio::time::sleep(std::time::Duration::from_millis(50)).await;
}
};
tokio::time::timeout(std::time::Duration::from_secs(10), gone)
.await
.expect("silence should end the track");
}
}