app
Fusion - the Fusion 360 Bridge
Public Made by Adomby adom
Drive Autodesk Fusion 360 from the cloud via Adom Bridge: component libraries, IPC package generation, board layout, exports (STEP/Gerbers/BOM/CPL), fast APS cloud search, and parametric modeling.
master
Drew Owens
Port occurrence translation and contract authoring to Rust; publish verified R21 source
a06dfd7
26d ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
struct PlacementRig {
common: Rig,
backend: crate::assembly::placement_tests::PlacementFake,
book: RefCell<crate::assembly::Book<u64>>,
}
impl PlacementRig {
fn new() -> Self {
Self {
common: Rig::new(),
backend: Default::default(),
book: Default::default(),
}
}
fn request(&self, id: &str) -> PreparedRequest {
crate::assembly::placement_tests::request_for(
&mut self.book.borrow_mut(),
&self.backend,
&self.common.queue.epoch().to_string(),
id,
[25., -10., 5.],
)
}
fn reply(&self, t: &mut Task) -> Result<Reply, String> {
match t {
Task::AssemblyPreflight(r) => {
Ok(match self.book.borrow_mut().preflight(&self.backend, r) {
Ok(p) => Reply::AssemblyPlan(p),
Err(e) => Reply::Value(
json!({"success":false,"errorCode":e,"nativeExecutionStarted":false}),
),
})
}
Task::AssemblyExecute(p) => Ok(Reply::Value(
self.book
.borrow_mut()
.execute(&self.backend, p.take().unwrap()),
)),
_ => Err("unexpected placement task".into()),
}
}
fn execute(&self, r: PreparedRequest) -> Response {
let op = r.arguments()["operationId"].as_str().unwrap().to_owned();
let client = self.common.spawn(r, Duration::from_secs(5));
let end = Instant::now() + Duration::from_secs(6);
while !client.is_finished() {
assert!(Instant::now() < end);
if let Some(mut c) = self
.common
.queue
.take_next(self.common.queue.epoch())
.unwrap()
{
if matches!(c.task(), Task::AssemblyExecute(_)) {
assert_eq!(
self.common
.reader
.journal()
.unwrap()
.status(&self.common.queue.epoch().to_string(), &op)
.unwrap()
.durable
.unwrap()
.record
.unwrap()
.phase,
Phase::Executing
);
}
let v = self.reply(c.task_mut());
c.complete(v).unwrap();
} else {
thread::sleep(Duration::from_millis(1));
}
}
client.join().unwrap()
}
}
#[test]
fn placement_durable_start_two_stages_replay_conflict_and_noop() {
let rig = PlacementRig::new();
let r = rig.request("move");
let (code, v) = rig.execute(r.clone());
assert_eq!(code, 200, "{v}");
assert_eq!(v["operationStatus"]["authority"], "durable_terminal");
assert_eq!(v["stages"].as_array().unwrap().len(), 2);
let (_, again) = rig.execute(r.clone());
assert_eq!(again["replayed"], true);
assert_eq!(again["data"], v["data"]);
assert_eq!(
(rig.backend.transforms.get(), rig.backend.captures.get()),
(1, 1)
);
let mut conflict = r.arguments().clone();
conflict["transform"]["position"] = json!([1, 2, 3]);
assert_eq!(
rig.execute(prepare_request(conflict, &rig.common.queue.epoch().to_string()).unwrap())
.0,
409
);
let fresh = rig.request("noop");
let (_, no) = rig.execute(fresh);
assert_eq!(no["errorCode"], "native_placement_no_change");
assert_eq!(no["operationStatus"]["authority"], "durable_terminal");
assert_eq!(
(rig.backend.transforms.get(), rig.backend.captures.get()),
(1, 1)
);
}
#[test]
fn placement_unknown_snapshot_ack_remains_unknown_without_any_effect_replay() {
let rig = PlacementRig::new();
let r = rig.request("unknown-capture");
rig.backend.mode.set(7);
let (code, v) = rig.execute(r.clone());
assert_eq!(code, 503, "{v}");
assert_eq!(v["outcome"], "unknown");
assert_eq!(v["stages"][0]["attempt"]["acknowledged"], true);
assert_eq!(v["stages"][1]["attempt"]["invoked"], true);
assert_eq!(v["stages"][1]["attempt"]["acknowledged"], false);
let (_, again) = rig.execute(r);
assert_eq!(again["replayed"], true);
assert_eq!(again["outcome"], "unknown");
assert_eq!(
(rig.backend.transforms.get(), rig.backend.captures.get()),
(1, 1)
);
}
#[test]
fn placement_terminal_storage_loss_retains_pose_and_snapshot_evidence() {
let rig = PlacementRig::new();
let r = rig.request("lost-placement");
let client = rig.common.spawn(r.clone(), Duration::from_secs(5));
let end = Instant::now() + Duration::from_secs(6);
loop {
assert!(Instant::now() < end);
if let Some(mut c) = rig
.common
.queue
.take_next(rig.common.queue.epoch())
.unwrap()
{
let execute = matches!(c.task(), Task::AssemblyExecute(_));
let v = rig.reply(c.task_mut());
if execute {
let path = rig
.common
.directory
.join(fusion_mechanical_journal::DATABASE_NAME);
let held = rig.common.directory.with_extension("placement-held");
std::fs::rename(&path, &held).unwrap();
c.complete(v).unwrap();
let (code, v) = client.join().unwrap();
assert_eq!(code, 503, "{v}");
assert_ne!(v["operationStatus"]["authority"], "durable_terminal");
assert_eq!(
v["placementEvidence"]["after"]["snapshots"]
.as_array()
.unwrap()
.len(),
1
);
std::fs::rename(held, path).unwrap();
let (_, again) = rig.execute(r);
assert_eq!(again["replayed"], true);
assert_eq!(
(rig.backend.transforms.get(), rig.backend.captures.get()),
(1, 1)
);
break;
}
c.complete(v).unwrap();
} else {
thread::sleep(Duration::from_millis(1));
}
}
}