diff --git a/benches/build.rs b/benches/build.rs index 5a560153..e502de1e 100644 --- a/benches/build.rs +++ b/benches/build.rs @@ -1,4 +1,4 @@ -use std::path::{Path, PathBuf}; +use std::path::{Path}; use criterion::{criterion_group, criterion_main, BatchSize, Criterion}; use tempfile::{tempdir, TempDir}; diff --git a/rojo-test/serve-test-snapshots/serve_test__just_txt-2.snap b/rojo-test/serve-test-snapshots/serve_test__just_txt-2.snap new file mode 100644 index 00000000..03a0565f --- /dev/null +++ b/rojo-test/serve-test-snapshots/serve_test__just_txt-2.snap @@ -0,0 +1,19 @@ +--- +source: rojo-test/src/serve_test.rs +expression: read_result +--- +sessionId: id-1 +messageCursor: 0 +instances: + id-2: + Id: id-2 + Parent: ~ + Name: just-txt + ClassName: StringValue + Properties: + Value: + Type: String + Value: "Hello, world!" + Children: [] + Metadata: + ignoreUnknownInstances: false diff --git a/rojo-test/serve-test-snapshots/serve_test__just_txt.snap b/rojo-test/serve-test-snapshots/serve_test__just_txt.snap new file mode 100644 index 00000000..5f830821 --- /dev/null +++ b/rojo-test/serve-test-snapshots/serve_test__just_txt.snap @@ -0,0 +1,9 @@ +--- +source: rojo-test/src/serve_test.rs +expression: info +--- +sessionId: id-1 +serverVersion: 0.6.0-dev +protocolVersion: 3 +expectedPlaceIds: ~ +rootInstanceId: id-2 diff --git a/rojo-test/serve-tests/just-txt.txt b/rojo-test/serve-tests/just-txt.txt new file mode 100644 index 00000000..5dd01c17 --- /dev/null +++ b/rojo-test/serve-tests/just-txt.txt @@ -0,0 +1 @@ +Hello, world! \ No newline at end of file diff --git a/rojo-test/src/lib.rs b/rojo-test/src/lib.rs index 786d9410..218b3483 100644 --- a/rojo-test/src/lib.rs +++ b/rojo-test/src/lib.rs @@ -2,4 +2,5 @@ mod build_test; mod serve_test; +mod serve_util; mod util; diff --git a/rojo-test/src/serve_test.rs b/rojo-test/src/serve_test.rs index fa6cedd9..e488cebc 100644 --- a/rojo-test/src/serve_test.rs +++ b/rojo-test/src/serve_test.rs @@ -1,24 +1,12 @@ -use std::{ - fs, - path::{Path, PathBuf}, - process::Command, - sync::atomic::{AtomicUsize, Ordering}, -}; +use std::fs; use insta::assert_yaml_snapshot; -use rbx_dom_weak::RbxId; -use tempfile::{tempdir, TempDir}; -use librojo::web_interface::{ReadResponse, ServerInfoResponse}; -use rojo_insta_ext::RedactionMap; - -use crate::util::{ - copy_recursive, get_rojo_path, get_serve_tests_path, get_working_dir_path, KillOnDrop, -}; +use crate::serve_util::run_serve_test; #[test] fn empty() { - run_serve_test(|session, mut redactions| { + run_serve_test("empty", |session, mut redactions| { let info = session.get_api_rojo().unwrap(); let root_id = info.root_instance_id; @@ -37,112 +25,29 @@ fn empty() { }); } -fn run_serve_test(callback: impl FnOnce(TestServeSession, RedactionMap)) { - let _ = env_logger::try_init(); +#[test] +fn just_txt() { + run_serve_test("just-txt.txt", |session, mut redactions| { + let info = session.get_api_rojo().unwrap(); - let mut settings = insta::Settings::new(); + let root_id = info.root_instance_id; + let info = redactions.redacted_yaml(info); - let snapshot_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("serve-test-snapshots"); - settings.set_snapshot_path(snapshot_path); + assert_yaml_snapshot!(info); - let mut redactions = RedactionMap::new(); + let read_result = session.get_api_read(root_id).unwrap(); + redactions.intern_iter(read_result.instances.keys().copied()); + let read_result = redactions.redacted_yaml(read_result); - let mut session = TestServeSession::new("empty"); - let info = session.wait_to_come_online(); + assert_yaml_snapshot!(read_result); - redactions.intern(info.session_id); - redactions.intern(info.root_instance_id); + fs::write(session.path(), "Changed content!").unwrap(); - settings.bind(move || callback(session, redactions)); -} - -fn get_port_number() -> usize { - static NEXT_PORT_NUMBER: AtomicUsize = AtomicUsize::new(35103); - - NEXT_PORT_NUMBER.fetch_add(1, Ordering::SeqCst) -} - -struct TestServeSession { - // Drop order is important here: we want the process to be killed before the - // directory it's operating on is destroyed. - rojo_process: KillOnDrop, - _dir: TempDir, - - port: usize, - project_path: PathBuf, -} - -impl TestServeSession { - pub fn new(name: &str) -> Self { - let serve_test_path = get_serve_tests_path(); - let working_dir = get_working_dir_path(); - let exe_path = get_rojo_path(); - - let source_path = serve_test_path.join(name); - let dir = tempdir().expect("Couldn't create temporary directory"); - let project_path = dir.path().join(name); - - fs::create_dir(&project_path).expect("Couldn't create temporary project subdirectory"); - - copy_recursive(&source_path, &project_path) - .expect("Couldn't copy project to temporary directory"); - - let port = get_port_number(); - let port_string = port.to_string(); - - let rojo_process = Command::new(exe_path) - .args(&[ - "serve", - project_path.to_str().unwrap(), - "--port", - port_string.as_str(), - ]) - .current_dir(working_dir) - .spawn() - .expect("Couldn't start Rojo"); - - TestServeSession { - rojo_process: KillOnDrop(rojo_process), - _dir: dir, - port, - project_path, - } - } - - pub fn wait_to_come_online(&mut self) -> ServerInfoResponse { - loop { - match self.rojo_process.0.try_wait() { - Ok(Some(status)) => panic!("Rojo process exited with status {}", status), - Ok(None) => { /* process is still running */ } - Err(err) => panic!("Failed to wait on Rojo process: {}", err), - } - - let info = match self.get_api_rojo() { - Ok(info) => info, - Err(err) => { - log::debug!("Server error, retrying: {}", err); - std::thread::sleep(std::time::Duration::from_millis(30)); - continue; - } - }; - - log::info!("Got session info: {:?}", info); - - return info; - } - } - - pub fn get_api_rojo(&self) -> Result { - let url = format!("http://localhost:{}/api/rojo", self.port); - let body = reqwest::get(&url)?.text()?; - - Ok(serde_json::from_str(&body).expect("Server returned malformed response")) - } - - pub fn get_api_read(&self, id: RbxId) -> Result { - let url = format!("http://localhost:{}/api/read/{}", self.port, id); - let body = reqwest::get(&url)?.text()?; - - Ok(serde_json::from_str(&body).expect("Server returned malformed response")) - } + // TODO: Directly served files currently don't trigger changed events! + + // let subscribe_result = session.get_api_subscribe(0).unwrap(); + // let subscribe_result = redactions.redacted_yaml(subscribe_result); + + // assert_yaml_snapshot!(subscribe_result); + }); } diff --git a/rojo-test/src/serve_util.rs b/rojo-test/src/serve_util.rs new file mode 100644 index 00000000..97e307ab --- /dev/null +++ b/rojo-test/src/serve_util.rs @@ -0,0 +1,145 @@ +use std::{ + fs, + path::{Path, PathBuf}, + process::Command, + sync::atomic::{AtomicUsize, Ordering}, +}; + +use rbx_dom_weak::RbxId; +use tempfile::{tempdir, TempDir}; + +use librojo::web_interface::{ReadResponse, ServerInfoResponse, SubscribeResponse}; +use rojo_insta_ext::RedactionMap; + +use crate::util::{ + copy_recursive, get_rojo_path, get_serve_tests_path, get_working_dir_path, KillOnDrop, +}; + +pub fn run_serve_test(test_name: &str, callback: impl FnOnce(TestServeSession, RedactionMap)) { + let _ = env_logger::try_init(); + + let mut settings = insta::Settings::new(); + + let snapshot_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("serve-test-snapshots"); + settings.set_snapshot_path(snapshot_path); + + let mut redactions = RedactionMap::new(); + + let mut session = TestServeSession::new(test_name); + let info = session.wait_to_come_online(); + + redactions.intern(info.session_id); + redactions.intern(info.root_instance_id); + + settings.bind(move || callback(session, redactions)); +} + +fn get_port_number() -> usize { + static NEXT_PORT_NUMBER: AtomicUsize = AtomicUsize::new(35103); + + NEXT_PORT_NUMBER.fetch_add(1, Ordering::SeqCst) +} + +pub struct TestServeSession { + // Drop order is important here: we want the process to be killed before the + // directory it's operating on is destroyed. + rojo_process: KillOnDrop, + _dir: TempDir, + + port: usize, + project_path: PathBuf, +} + +impl TestServeSession { + pub fn new(name: &str) -> Self { + let serve_test_path = get_serve_tests_path(); + let working_dir = get_working_dir_path(); + let exe_path = get_rojo_path(); + + let source_path = serve_test_path.join(name); + let dir = tempdir().expect("Couldn't create temporary directory"); + let project_path = dir.path().join(name); + + let source_is_file = fs::metadata(&source_path).unwrap().is_file(); + + if source_is_file { + fs::copy(&source_path, &project_path).expect("couldn't copy project file"); + } else { + fs::create_dir(&project_path).expect("Couldn't create temporary project subdirectory"); + + copy_recursive(&source_path, &project_path) + .expect("Couldn't copy project to temporary directory"); + }; + + let port = get_port_number(); + let port_string = port.to_string(); + + let rojo_process = Command::new(exe_path) + .args(&[ + "serve", + project_path.to_str().unwrap(), + "--port", + port_string.as_str(), + ]) + .current_dir(working_dir) + .spawn() + .expect("Couldn't start Rojo"); + + TestServeSession { + rojo_process: KillOnDrop(rojo_process), + _dir: dir, + port, + project_path, + } + } + + pub fn path(&self) -> &Path { + &self.project_path + } + + pub fn wait_to_come_online(&mut self) -> ServerInfoResponse { + loop { + match self.rojo_process.0.try_wait() { + Ok(Some(status)) => panic!("Rojo process exited with status {}", status), + Ok(None) => { /* process is still running */ } + Err(err) => panic!("Failed to wait on Rojo process: {}", err), + } + + let info = match self.get_api_rojo() { + Ok(info) => info, + Err(err) => { + log::debug!("Server error, retrying: {}", err); + std::thread::sleep(std::time::Duration::from_millis(30)); + continue; + } + }; + + log::info!("Got session info: {:?}", info); + + return info; + } + } + + pub fn get_api_rojo(&self) -> Result { + let url = format!("http://localhost:{}/api/rojo", self.port); + let body = reqwest::get(&url)?.text()?; + + Ok(serde_json::from_str(&body).expect("Server returned malformed response")) + } + + pub fn get_api_read(&self, id: RbxId) -> Result { + let url = format!("http://localhost:{}/api/read/{}", self.port, id); + let body = reqwest::get(&url)?.text()?; + + Ok(serde_json::from_str(&body).expect("Server returned malformed response")) + } + + pub fn get_api_subscribe( + &self, + cursor: u32, + ) -> Result, reqwest::Error> { + let url = format!("http://localhost:{}/api/subscribe/{}", self.port, cursor); + + reqwest::get(&url)?.json() + } +}