diff options
author | Aram Drevekenin <aram@poor.dev> | 2024-02-19 16:26:59 +0100 |
---|---|---|
committer | Aram Drevekenin <aram@poor.dev> | 2024-02-19 16:26:59 +0100 |
commit | 8183fe1f1cef448aecc57a1024d63d24b89c0763 (patch) | |
tree | 5ac40f8b4fb8932dd0c59ba80373fe1ac126db82 /zellij-server/src | |
parent | 7699efead491a8b52f62d12a021e9ee47f85a5dc (diff) |
new tests and passing plugin tests as well
Diffstat (limited to 'zellij-server/src')
9 files changed, 308 insertions, 22 deletions
diff --git a/zellij-server/src/panes/floating_panes/mod.rs b/zellij-server/src/panes/floating_panes/mod.rs index c8c8b42b6..572a75629 100644 --- a/zellij-server/src/panes/floating_panes/mod.rs +++ b/zellij-server/src/panes/floating_panes/mod.rs @@ -887,7 +887,8 @@ impl FloatingPanes { .find(|(_id, s_p)| { match s_p.invoked_with() { // Some(Run::Plugin(RunPluginOrAlias::Alias(pane_alias))) => pane_alias.name == plugin_alias.name, - Some(Run::Plugin(RunPluginOrAlias::Alias(pane_alias))) => pane_alias.name == plugin_alias.name && pane_alias.configuration == plugin_alias.configuration, + Some(Run::Plugin(RunPluginOrAlias::Alias(pane_alias))) => pane_alias.name == plugin_alias.name && + pane_alias.configuration.as_ref().and_then(|c| if c.inner().is_empty() { None } else { Some(c)} ) == plugin_alias.configuration.as_ref().and_then(|c| if c.inner().is_empty() { None } else { Some(c) }), _ => false } }) diff --git a/zellij-server/src/panes/tiled_panes/mod.rs b/zellij-server/src/panes/tiled_panes/mod.rs index 57444c4e9..be973444a 100644 --- a/zellij-server/src/panes/tiled_panes/mod.rs +++ b/zellij-server/src/panes/tiled_panes/mod.rs @@ -1754,11 +1754,15 @@ impl TiledPanes { .map(|(id, _)| *id) } RunPluginOrAlias::Alias(plugin_alias) => { + eprintln!("plugin_alias: {:?}", plugin_alias); self.panes .iter() .find(|(_id, s_p)| { + eprintln!("comparing with: {:?}", s_p.invoked_with()); match s_p.invoked_with() { - Some(Run::Plugin(RunPluginOrAlias::Alias(pane_alias))) => pane_alias.name == plugin_alias.name && pane_alias.configuration == plugin_alias.configuration, + Some(Run::Plugin(RunPluginOrAlias::Alias(pane_alias))) => pane_alias.name == plugin_alias.name && + pane_alias.configuration.as_ref().and_then(|c| if c.inner().is_empty() { None } else { Some(c)} ) == plugin_alias.configuration.as_ref().and_then(|c| if c.inner().is_empty() { None } else { Some(c) }), + // Some(Run::Plugin(RunPluginOrAlias::Alias(pane_alias))) => pane_alias.name == plugin_alias.name && pane_alias.configuration == plugin_alias.configuration, _ => false } }) diff --git a/zellij-server/src/plugins/mod.rs b/zellij-server/src/plugins/mod.rs index e816d1578..5c5903bc2 100644 --- a/zellij-server/src/plugins/mod.rs +++ b/zellij-server/src/plugins/mod.rs @@ -190,12 +190,16 @@ pub(crate) fn plugin_thread_main( let mut plugin_aliases = HashMap::new(); let mut filter_configuration = BTreeMap::new(); filter_configuration.insert("key_from_dict".to_owned(), "value_from_dict".to_owned()); + + // TODO: from config plugin_aliases.insert("session-manager-alias", RunPlugin::from_url("zellij:session-manager").unwrap()); plugin_aliases.insert("filepicker", RunPlugin::from_url("zellij:strider").unwrap()); + plugin_aliases.insert("fixture_plugin_for_tests", RunPlugin::from_url(&format!("file:{}/../target/e2e-data/plugins/fixture-plugin-for-tests.wasm", std::env::var_os("CARGO_MANIFEST_DIR").unwrap().to_string_lossy())).unwrap()); plugin_aliases.insert( "filter", RunPlugin::from_url("file:/home/aram/code/rust-plugin-example/target/wasm32-wasi/debug/rust-plugin-example.wasm").unwrap().with_configuration(filter_configuration) ); + layout.populate_plugin_aliases_in_layout(&plugin_aliases); let store = Arc::new(Mutex::new(store)); diff --git a/zellij-server/src/plugins/unit/plugin_tests.rs b/zellij-server/src/plugins/unit/plugin_tests.rs index ebec7bec5..5b2c71feb 100644 --- a/zellij-server/src/plugins/unit/plugin_tests.rs +++ b/zellij-server/src/plugins/unit/plugin_tests.rs @@ -8,7 +8,7 @@ use tempfile::tempdir; use wasmer::Store; use zellij_utils::data::{Event, Key, PermissionStatus, PermissionType, PluginCapabilities}; use zellij_utils::errors::ErrorContext; -use zellij_utils::input::layout::{Layout, PluginUserConfiguration, RunPlugin, RunPluginOrAlias, RunPluginLocation}; +use zellij_utils::input::layout::{Layout, PluginUserConfiguration, RunPlugin, RunPluginOrAlias, RunPluginLocation, PluginAlias}; use zellij_utils::input::permission::PermissionCache; use zellij_utils::input::plugins::PluginsConfig; use zellij_utils::ipc::ClientAttributes; @@ -621,6 +621,93 @@ pub fn load_new_plugin_from_hd() { #[test] #[ignore] +pub fn load_new_plugin_with_plugin_alias() { + // here we load our fixture plugin into the plugin thread, and then send it an update message + // expecting tha thte plugin will log the received event and render it later after the update + // message (this is what the fixture plugin does) + // we then listen on our mock screen receiver to make sure we got a PluginBytes instruction + // that contains said render, and assert against it + let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its + let plugin_host_folder = PathBuf::from(temp_folder.path()); + let cache_path = plugin_host_folder.join("permissions_test.kdl"); + let (plugin_thread_sender, screen_receiver, teardown) = create_plugin_thread(None); + let plugin_should_float = Some(false); + let plugin_title = Some("test_plugin".to_owned()); + // TODO: CONTINUE HERE (16/2) + // - add an alias version of this test - DONE + // - then make a version of the layout_with_plugin_panes test that also includes aliases (or + // add it to that test?) - N/A + // - then look through this file to see what other tests we can add, then look at more tests + // in these files: + // - plugin_tests + // - screen_tests + let run_plugin = RunPluginOrAlias::Alias(PluginAlias { + name: "fixture_plugin_for_tests".to_owned(), + configuration: Default::default(), + run_plugin: None, + }); + let tab_index = 1; + let client_id = 1; + let size = Size { + cols: 121, + rows: 20, + }; + let received_screen_instructions = Arc::new(Mutex::new(vec![])); + let screen_thread = grant_permissions_and_log_actions_in_thread!( + received_screen_instructions, + ScreenInstruction::PluginBytes, + screen_receiver, + 1, + &PermissionType::ChangeApplicationState, + cache_path, + plugin_thread_sender, + client_id + ); + + let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id)); + let _ = plugin_thread_sender.send(PluginInstruction::Load( + plugin_should_float, + false, + plugin_title, + run_plugin, + tab_index, + None, + client_id, + size, + None, + false, + )); + std::thread::sleep(std::time::Duration::from_millis(500)); + let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![( + None, + Some(client_id), + Event::InputReceived, + )])); // will be cached and sent to the plugin once it's loaded + screen_thread.join().unwrap(); // this might take a while if the cache is cold + teardown(); + let plugin_bytes_event = received_screen_instructions + .lock() + .unwrap() + .iter() + .find_map(|i| { + if let ScreenInstruction::PluginBytes(plugin_render_assets) = i { + for plugin_render_asset in plugin_render_assets { + let plugin_id = plugin_render_asset.plugin_id; + let client_id = plugin_render_asset.client_id; + let plugin_bytes = plugin_render_asset.bytes.clone(); + let plugin_bytes = String::from_utf8_lossy(plugin_bytes.as_slice()).to_string(); + if plugin_bytes.contains("InputReceived") { + return Some((plugin_id, client_id, plugin_bytes)); + } + } + } + None + }); + assert_snapshot!(format!("{:#?}", plugin_bytes_event)); +} + +#[test] +#[ignore] pub fn plugin_workers() { let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its // destructor removes the directory @@ -5324,7 +5411,7 @@ pub fn granted_permission_request_result() { let permission_cache = PermissionCache::from_path_or_default(Some(cache_path)); let mut permissions = permission_cache - .get_permissions(run_plugin.location_string()) + .get_permissions(PathBuf::from(&*PLUGIN_FIXTURE).display().to_string()) .clone(); let permissions = permissions.as_mut().map(|p| { let mut permissions = p.clone(); @@ -5413,7 +5500,7 @@ pub fn denied_permission_request_result() { teardown(); let permission_cache = PermissionCache::from_path_or_default(Some(cache_path)); - let permissions = permission_cache.get_permissions(run_plugin.location_string()); + let permissions = permission_cache.get_permissions(PathBuf::from(&*PLUGIN_FIXTURE).display().to_string()); assert_snapshot!(format!("{:#?}", permissions)); } diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__load_new_plugin_with_plugin_alias.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__load_new_plugin_with_plugin_alias.snap new file mode 100644 index 000000000..b5b7ef4a3 --- /dev/null +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__load_new_plugin_with_plugin_alias.snap @@ -0,0 +1,12 @@ +--- +source: zellij-server/src/plugins/./unit/plugin_tests.rs +assertion_line: 706 +expression: "format!(\"{:#?}\", plugin_bytes_event)" +--- +Some( + ( + 0, + 1, + "Rows: 20, Cols: 121, Received events: [InputReceived]\n\r", + ), +) diff --git a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__start_or_reload_plugin.snap b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__start_or_reload_plugin.snap index 05002124a..a55b17ecf 100644 --- a/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__start_or_reload_plugin.snap +++ b/zellij-server/src/plugins/unit/snapshots/zellij_server__plugins__plugin_tests__start_or_reload_plugin.snap @@ -1,19 +1,21 @@ --- source: zellij-server/src/plugins/./unit/plugin_tests.rs -assertion_line: 2931 +assertion_line: 3700 expression: "format!(\"{:#?}\", new_tab_event)" --- Some( StartOrReloadPluginPane( - RunPlugin { - _allow_exec_host_cmd: false, - location: File( - "/path/to/my/plugin.wasm", - ), - configuration: PluginUserConfiguration( - {}, - ), - }, + RunPlugin( + RunPlugin { + _allow_exec_host_cmd: false, + location: File( + "/path/to/my/plugin.wasm", + ), + configuration: PluginUserConfiguration( + {}, + ), + }, + ), None, ), ) diff --git a/zellij-server/src/screen.rs b/zellij-server/src/screen.rs index 03b768586..d0789e9ce 100644 --- a/zellij-server/src/screen.rs +++ b/zellij-server/src/screen.rs @@ -1747,13 +1747,16 @@ impl Screen { client_id: ClientId, ) -> Result<bool> { // true => found and focused, false => not + log::info!("focus_plugin_pane"); let err_context = || format!("failed to focus_plugin_pane"); let mut tab_index_and_plugin_pane_id = None; let mut plugin_pane_to_move_to_active_tab = None; let focused_tab_index = *self.active_tab_indices.get(&client_id).unwrap_or(&0); let all_tabs = self.get_tabs_mut(); for (tab_index, tab) in all_tabs.iter_mut() { + log::info!("finding plugin..."); if let Some(plugin_pane_id) = tab.find_plugin(&run_plugin) { + log::info!("found it!"); tab_index_and_plugin_pane_id = Some((*tab_index, plugin_pane_id)); if move_to_focused_tab && focused_tab_index != *tab_index { plugin_pane_to_move_to_active_tab = @@ -3474,7 +3477,7 @@ pub(crate) fn screen_thread_main( skip_cache, client_id, ) => match pane_id_to_replace { - Some(pane_id_to_replace) => match screen.active_tab_indices.values().next() { + Some(pane_id_to_replace) if should_open_in_place => match screen.active_tab_indices.values().next() { Some(tab_index) => { let size = Size::default(); screen @@ -3500,8 +3503,7 @@ pub(crate) fn screen_thread_main( ); }, }, - None => { - log::info!("run_plugin: {:?}", run_plugin); + _ => { let client_id = if screen.active_tab_indices.contains_key(&client_id) { Some(client_id) } else { @@ -3515,15 +3517,18 @@ pub(crate) fn screen_thread_main( }); match client_id_and_focused_tab { Some((tab_index, client_id)) => { + eprintln!("focus plugin pane??: {:?}", run_plugin); if screen.focus_plugin_pane( &run_plugin, should_float, move_to_focused_tab, client_id, )? { + eprintln!("can has focus plugin pane"); screen.render(None)?; screen.log_and_report_session_state()?; } else { + eprintln!("no!!"); screen .bus .senders diff --git a/zellij-server/src/tab/layout_applier.rs b/zellij-server/src/tab/layout_applier.rs index 34a71b22e..4f5246d33 100644 --- a/zellij-server/src/tab/layout_applier.rs +++ b/zellij-server/src/tab/layout_applier.rs @@ -269,11 +269,13 @@ impl<'a> LayoutApplier<'a> { // if let Some(run_plugin) = layout.run.as_ref().and_then(|r| r.get_run_plugin()) { if let Some(Run::Plugin(run)) = layout.run.clone() { let pane_title = run.location_string(); + eprintln!("new_plugin_ids: {:#?}, \nrun: {:#?}", new_plugin_ids, run); let pid = new_plugin_ids // .get_mut(&(run_plugin.location, run_plugin.configuration)) .get_mut(&run) .and_then(|ids| ids.pop()) .with_context(err_context)?; + eprintln!("not here!"); let mut new_plugin = PluginPane::new( pid, *position_and_size, diff --git a/zellij-server/src/unit/screen_tests.rs b/zellij-server/src/unit/screen_tests.rs index 78846947b..52486e31d 100644 --- a/zellij-server/src/unit/screen_tests.rs +++ b/zellij-server/src/unit/screen_tests.rs @@ -16,7 +16,7 @@ use zellij_utils::input::actions::Action; use zellij_utils::input::command::{RunCommand, TerminalAction}; use zellij_utils::input::layout::{ FloatingPaneLayout, Layout, Run, RunPlugin, RunPluginOrAlias, RunPluginLocation, SplitDirection, SplitSize, - TiledPaneLayout, + TiledPaneLayout, PluginAlias, PluginUserConfiguration, }; use zellij_utils::input::options::Options; use zellij_utils::ipc::IpcReceiverWithContext; @@ -374,6 +374,93 @@ impl MockScreen { self.last_opened_tab_index = Some(tab_index); screen_thread } + // same as the above function, but starts a plugin with a plugin alias + pub fn run_with_alias( + &mut self, + initial_layout: Option<TiledPaneLayout>, + initial_floating_panes_layout: Vec<FloatingPaneLayout>, + ) -> std::thread::JoinHandle<()> { + let config_options = self.config_options.clone(); + let client_attributes = self.client_attributes.clone(); + let screen_bus = Bus::new( + vec![self.screen_receiver.take().unwrap()], + None, + Some(&self.to_pty.clone()), + Some(&self.to_plugin.clone()), + Some(&self.to_server.clone()), + Some(&self.to_pty_writer.clone()), + Some(&self.to_background_jobs.clone()), + Some(Box::new(self.os_input.clone())), + ) + .should_silently_fail(); + let debug = false; + let screen_thread = std::thread::Builder::new() + .name("screen_thread".to_string()) + .spawn(move || { + set_var("ZELLIJ_SESSION_NAME", "zellij-test"); + screen_thread_main( + screen_bus, + None, + client_attributes, + Box::new(config_options), + debug, + Box::new(Layout::default()), + ) + .expect("TEST") + }) + .unwrap(); + let pane_layout = initial_layout.unwrap_or_default(); + let pane_count = pane_layout.extract_run_instructions().len(); + let floating_pane_count = initial_floating_panes_layout.len(); + let mut pane_ids = vec![]; + let mut floating_pane_ids = vec![]; + let mut plugin_ids = HashMap::new(); + plugin_ids.insert( + RunPluginOrAlias::Alias(PluginAlias { + name: "fixture_plugin_for_tests".to_owned(), + configuration: Some(Default::default()), + run_plugin: Some(RunPlugin { + location: RunPluginLocation::parse("file:/path/to/fake/plugin", None).unwrap(), + configuration: PluginUserConfiguration::default(), + ..Default::default() + }), + ..Default::default() + }), + vec![1], + ); + for i in 0..pane_count { + pane_ids.push((i as u32, None)); + } + for i in 0..floating_pane_count { + floating_pane_ids.push((i as u32, None)); + } + let default_shell = None; + let tab_name = None; + let tab_index = self.last_opened_tab_index.map(|l| l + 1).unwrap_or(0); + let _ = self.to_screen.send(ScreenInstruction::NewTab( + None, + default_shell, + Some(pane_layout.clone()), + initial_floating_panes_layout.clone(), + // vec![], // floating_panes_layout + tab_name, + (vec![], vec![]), // swap layouts + self.main_client_id, + )); + let _ = self.to_screen.send(ScreenInstruction::ApplyLayout( + pane_layout, + initial_floating_panes_layout, + // vec![], // floating panes layout + pane_ids, + floating_pane_ids, + // vec![], // floating pane ids + plugin_ids, + tab_index, + self.main_client_id, + )); + self.last_opened_tab_index = Some(tab_index); + screen_thread + } pub fn new_tab(&mut self, tab_layout: TiledPaneLayout) { let pane_count = tab_layout.extract_run_instructions().len(); let mut pane_ids = vec![]; @@ -2737,7 +2824,7 @@ pub fn send_cli_launch_or_focus_plugin_action() { floating: true, in_place: false, move_to_focused_tab: true, - url: url::Url::parse("file:/path/to/fake/plugin").unwrap(), + url: "file:/path/to/fake/plugin".to_owned(), configuration: Default::default(), skip_plugin_cache: false, }; @@ -2797,7 +2884,90 @@ pub fn send_cli_launch_or_focus_plugin_action_when_plugin_is_already_loaded() { floating: true, in_place: false, move_to_focused_tab: true, - url: url::Url::parse("file:/path/to/fake/plugin").unwrap(), + url: "file:/path/to/fake/plugin".to_owned(), + configuration: Default::default(), + skip_plugin_cache: false, + }; + send_cli_action_to_server(&session_metadata, cli_action, client_id); + std::thread::sleep(std::time::Duration::from_millis(100)); // give time for actions to be + mock_screen.teardown(vec![plugin_thread, server_thread, screen_thread]); + + let plugin_load_instruction_sent = received_plugin_instructions + .lock() + .unwrap() + .iter() + .find(|instruction| match instruction { + PluginInstruction::Load(..) => true, + _ => false, + }) + .is_some(); + assert!( + !plugin_load_instruction_sent, + "Plugin Load instruction should not be sent for an already loaded plugin" + ); + let snapshots = take_snapshots_and_cursor_coordinates_from_render_events( + received_server_instructions.lock().unwrap().iter(), + size, + ); + let snapshot_count = snapshots.len(); + assert_eq!( + snapshot_count, 2, + "Another render was sent for focusing the already loaded plugin" + ); + for (cursor_coordinates, _snapshot) in snapshots.iter().skip(1) { + assert!( + cursor_coordinates.is_none(), + "Cursor moved to existing plugin in final snapshot indicating focus changed" + ); + } +} + +#[test] +pub fn send_cli_launch_or_focus_plugin_action_when_plugin_is_already_loaded_for_plugin_alias() { + let size = Size { + cols: 121, + rows: 20, + }; + let client_id = 10; // fake client id should not appear in the screen's state + let mut mock_screen = MockScreen::new(size); + let plugin_receiver = mock_screen.plugin_receiver.take().unwrap(); + let session_metadata = mock_screen.clone_session_metadata(); + let mut initial_layout = TiledPaneLayout::default(); + let existing_plugin_pane = TiledPaneLayout { + run: Some(Run::Plugin(RunPluginOrAlias::Alias(PluginAlias { + name: "fixture_plugin_for_tests".to_owned(), + configuration: Some(Default::default()), + run_plugin: Some(RunPlugin { + _allow_exec_host_cmd: false, + location: RunPluginLocation::File(PathBuf::from("/path/to/fake/plugin")), + configuration: Default::default(), + }), + ..Default::default() + }))), + ..Default::default() + }; + initial_layout.children_split_direction = SplitDirection::Vertical; + initial_layout.children = vec![TiledPaneLayout::default(), existing_plugin_pane]; + let screen_thread = mock_screen.run_with_alias(Some(initial_layout), vec![]); + let received_plugin_instructions = Arc::new(Mutex::new(vec![])); + let plugin_thread = log_actions_in_thread!( + received_plugin_instructions, + PluginInstruction::Exit, + plugin_receiver + ); + let received_server_instructions = Arc::new(Mutex::new(vec![])); + let server_receiver = mock_screen.server_receiver.take().unwrap(); + let server_thread = log_actions_in_thread!( + received_server_instructions, + ServerInstruction::KillSession, + server_receiver + ); + let cli_action = CliAction::LaunchOrFocusPlugin { + floating: true, + in_place: false, + move_to_focused_tab: true, + url: "fixture_plugin_for_tests".to_owned(), + // url: url::Url::parse("file:/path/to/fake/plugin").unwrap(), configuration: Default::default(), skip_plugin_cache: false, }; @@ -3135,7 +3305,6 @@ pub fn screen_can_break_floating_plugin_pane_to_a_new_tab() { // through the plugin and pty threads (to open extra stuff we need in the layout, eg. the // default plugins) floating_panes_layout.get_mut(0).unwrap().already_running = true; - eprintln!("floating_panes_layout: {:#?}", floating_panes_layout); let _ = mock_screen.to_screen.send(ScreenInstruction::ApplyLayout( TiledPaneLayout::default(), floating_panes_layout, |