forked from 1b-agent/opencadstudio-upstream
Merge pull request #1695 from YsDirector/pr/d9-task-completion
Track zero-unit task completion
This commit is contained in:
commit
cd494de5fb
1 file changed
+96
-1
+96
-1
@@ -1159,7 +1159,22 @@ impl OpenCADStudio {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn control_track(&mut self, task: Task<Message>) -> Task<Message> {
|
pub(super) fn control_track(&mut self, task: Task<Message>) -> Task<Message> {
|
||||||
if task.units() == 0 {
|
let track_zero_unit = self.control.pending.as_ref().is_some_and(|p| {
|
||||||
|
p.request["op"] == "run"
|
||||||
|
&& p.request["cmd"]
|
||||||
|
.as_str()
|
||||||
|
.is_some_and(|cmd| {
|
||||||
|
matches!(
|
||||||
|
cmd.trim().to_ascii_uppercase().as_str(),
|
||||||
|
"SAVE" | "QSAVE"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
// Most zero-unit tasks are `Task::none()` and have already completed
|
||||||
|
// synchronously. SAVE/QSAVE are the deliberate exception: the command
|
||||||
|
// dispatcher returns a zero-unit Task::done(Message::SaveFile), and
|
||||||
|
// the operation must wait for that message before reporting its state.
|
||||||
|
if task.units() == 0 && !track_zero_unit {
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
let Some(p) = self.control.pending.as_mut() else {
|
let Some(p) = self.control.pending.as_mut() else {
|
||||||
@@ -1548,6 +1563,86 @@ mod tests {
|
|||||||
r
|
r
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[test]
|
||||||
|
fn qsave_completion_reports_clean_document_state() {
|
||||||
|
let mut app = OpenCADStudio::new_for_test();
|
||||||
|
assert_eq!(request(&mut app, json!({"op":"new"}))["ok"], true);
|
||||||
|
assert_eq!(
|
||||||
|
request(&mut app, json!({"op":"run","cmd":"LINE 0,0 10,0"}))["status"],
|
||||||
|
"completed"
|
||||||
|
);
|
||||||
|
let path = std::env::temp_dir().join(format!(
|
||||||
|
"ocs_qsave_state_{}_{}.dwg",
|
||||||
|
std::process::id(),
|
||||||
|
std::time::SystemTime::now()
|
||||||
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_nanos(),
|
||||||
|
));
|
||||||
|
let _ = std::fs::remove_file(&path);
|
||||||
|
let saved = request(
|
||||||
|
&mut app,
|
||||||
|
json!({"op":"save","path":path,"overwrite":true}),
|
||||||
|
);
|
||||||
|
assert_eq!(saved["ok"], true, "{saved}");
|
||||||
|
assert_eq!(
|
||||||
|
request(&mut app, json!({"op":"run","cmd":"LINE 0,5 10,5"}))["status"],
|
||||||
|
"completed"
|
||||||
|
);
|
||||||
|
let qsave = request(&mut app, json!({"op":"run","cmd":"QSAVE"}));
|
||||||
|
assert_eq!(qsave["status"], "completed", "{qsave}");
|
||||||
|
let document_id = qsave["state"]["document_id"].as_u64().unwrap();
|
||||||
|
let dirty = qsave["state"]["documents"]
|
||||||
|
.as_array()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.find(|document| document["id"].as_u64() == Some(document_id))
|
||||||
|
.and_then(|document| document["dirty"].as_bool());
|
||||||
|
assert_eq!(dirty, Some(false), "{qsave}");
|
||||||
|
let _ = std::fs::remove_file(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn qsave_save_failure_settles_instead_of_hanging() {
|
||||||
|
let mut app = OpenCADStudio::new_for_test();
|
||||||
|
assert_eq!(request(&mut app, json!({"op":"new"}))["ok"], true);
|
||||||
|
assert_eq!(
|
||||||
|
request(&mut app, json!({"op":"run","cmd":"LINE 0,0 10,0"}))["status"],
|
||||||
|
"completed"
|
||||||
|
);
|
||||||
|
let dir = std::env::temp_dir().join(format!(
|
||||||
|
"ocs_qsave_fail_{}_{}",
|
||||||
|
std::process::id(),
|
||||||
|
std::time::SystemTime::now()
|
||||||
|
.duration_since(std::time::UNIX_EPOCH)
|
||||||
|
.unwrap()
|
||||||
|
.as_nanos(),
|
||||||
|
));
|
||||||
|
std::fs::create_dir_all(&dir).unwrap();
|
||||||
|
let path = dir.join("blocked.dwg");
|
||||||
|
let saved = request(
|
||||||
|
&mut app,
|
||||||
|
json!({"op":"save","path":path,"overwrite":true}),
|
||||||
|
);
|
||||||
|
assert_eq!(saved["ok"], true, "{saved}");
|
||||||
|
// A directory at the target path makes the next write fail
|
||||||
|
// deterministically; the operation must settle as failed instead of
|
||||||
|
// waiting forever on its task counter.
|
||||||
|
std::fs::remove_file(&path).unwrap();
|
||||||
|
std::fs::create_dir(&path).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
request(&mut app, json!({"op":"run","cmd":"LINE 0,5 10,5"}))["status"],
|
||||||
|
"completed"
|
||||||
|
);
|
||||||
|
let qsave = request(&mut app, json!({"op":"run","cmd":"QSAVE"}));
|
||||||
|
assert_eq!(qsave["status"], "failed", "{qsave}");
|
||||||
|
assert!(
|
||||||
|
qsave["error"].as_str().is_some_and(|error| !error.is_empty()),
|
||||||
|
"{qsave}"
|
||||||
|
);
|
||||||
|
let _ = std::fs::remove_dir_all(&dir);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn control_stepwise_drawing_undo_and_properties() {
|
fn control_stepwise_drawing_undo_and_properties() {
|
||||||
let mut app = OpenCADStudio::new_for_test();
|
let mut app = OpenCADStudio::new_for_test();
|
||||||
|
|||||||
Reference in new issue
Block a user