Use SerializationService as a fallback for when patch application fails (#1030)

This commit is contained in:
Micah
2025-09-21 15:09:20 -07:00
committed by GitHub
parent 59e36491a5
commit 80a381dbb1
26 changed files with 793 additions and 108 deletions

View File

@@ -1,4 +1,5 @@
use std::{
fmt::Write as _,
fs,
path::{Path, PathBuf},
process::Command,
@@ -11,7 +12,7 @@ use rbx_dom_weak::types::Ref;
use tempfile::{tempdir, TempDir};
use librojo::web_api::{ReadResponse, ServerInfoResponse, SubscribeResponse};
use librojo::web_api::{ReadResponse, SerializeResponse, ServerInfoResponse, SubscribeResponse};
use rojo_insta_ext::RedactionMap;
use crate::rojo_test::io_util::{
@@ -174,6 +175,18 @@ impl TestServeSession {
reqwest::blocking::get(url)?.json()
}
pub fn get_api_serialize(&self, ids: &[Ref]) -> Result<SerializeResponse, reqwest::Error> {
let mut id_list = String::with_capacity(ids.len() * 33);
for id in ids {
write!(id_list, "{id},").unwrap();
}
id_list.pop();
let url = format!("http://localhost:{}/api/serialize/{}", self.port, id_list);
reqwest::blocking::get(url)?.json()
}
}
/// Probably-okay way to generate random enough port numbers for running the
@@ -187,3 +200,27 @@ fn get_port_number() -> usize {
NEXT_PORT_NUMBER.fetch_add(1, Ordering::SeqCst)
}
/// Takes a SerializeResponse and creates an XML model out of the response.
///
/// Since the provided structure intentionally includes unredacted referents,
/// some post-processing is done to ensure they don't show up in the model.
pub fn serialize_to_xml_model(response: &SerializeResponse, redactions: &RedactionMap) -> String {
let model_content = data_encoding::BASE64
.decode(response.model_contents.model().as_bytes())
.unwrap();
let mut dom = rbx_binary::from_reader(model_content.as_slice()).unwrap();
// This makes me realize that maybe we need a `descendants_mut` iter.
let ref_list: Vec<Ref> = dom.descendants().map(|inst| inst.referent()).collect();
for referent in ref_list {
let inst = dom.get_by_ref_mut(referent).unwrap();
if let Some(id) = redactions.get_id_for_value(&inst.name) {
inst.name = format!("id-{id}");
}
}
let mut data = Vec::new();
rbx_xml::to_writer_default(&mut data, &dom, dom.root().children()).unwrap();
String::from_utf8(data).expect("rbx_xml should never produce invalid utf-8")
}

View File

@@ -1,9 +1,12 @@
use std::fs;
use insta::{assert_yaml_snapshot, with_settings};
use insta::{assert_snapshot, assert_yaml_snapshot, with_settings};
use tempfile::tempdir;
use crate::rojo_test::{internable::InternAndRedact, serve_util::run_serve_test};
use crate::rojo_test::{
internable::InternAndRedact,
serve_util::{run_serve_test, serialize_to_xml_model},
};
#[test]
fn empty() {
@@ -591,3 +594,66 @@ fn model_pivot_migration() {
);
});
}
#[test]
fn meshpart_with_id() {
run_serve_test("meshpart_with_id", |session, mut redactions| {
let info = session.get_api_rojo().unwrap();
let root_id = info.root_instance_id;
assert_yaml_snapshot!("meshpart_with_id_info", redactions.redacted_yaml(&info));
let read_response = session.get_api_read(root_id).unwrap();
assert_yaml_snapshot!(
"meshpart_with_id_all",
read_response.intern_and_redact(&mut redactions, root_id)
);
// This is a bit awkward, but it's fine.
let (meshpart, _) = read_response
.instances
.iter()
.find(|(_, inst)| inst.class_name == "MeshPart")
.unwrap();
let (objectvalue, _) = read_response
.instances
.iter()
.find(|(_, inst)| inst.class_name == "ObjectValue")
.unwrap();
let serialize_response = session
.get_api_serialize(&[*meshpart, *objectvalue])
.unwrap();
// We don't assert a snapshot on the SerializeResponse because the model includes the
// Refs from the DOM as names, which means it will obviously be different every time
// this code runs. Still, we ensure that the SessionId is right at least.
assert_eq!(serialize_response.session_id, info.session_id);
let model = serialize_to_xml_model(&serialize_response, &redactions);
assert_snapshot!("meshpart_with_id_serialize_model", model);
});
}
#[test]
fn forced_parent() {
run_serve_test("forced_parent", |session, mut redactions| {
let info = session.get_api_rojo().unwrap();
let root_id = info.root_instance_id;
assert_yaml_snapshot!("forced_parent_info", redactions.redacted_yaml(&info));
let read_response = session.get_api_read(root_id).unwrap();
assert_yaml_snapshot!(
"forced_parent_all",
read_response.intern_and_redact(&mut redactions, root_id)
);
let serialize_response = session.get_api_serialize(&[root_id]).unwrap();
assert_eq!(serialize_response.session_id, info.session_id);
let model = serialize_to_xml_model(&serialize_response, &redactions);
assert_snapshot!("forced_parent_serialize_model", model);
});
}