aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/tests/plugin/subscriber_test.rs
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-08-04 04:07:41 +0900
committernsfisis <nsfisis@gmail.com>2026-08-04 05:43:24 +0900
commit695365a0ad68e4534425c64b7a6a4b6598b68ef7 (patch)
treea906972618f08e31012f721c717321bd08164cde /crates/shirabe/tests/plugin/subscriber_test.rs
parent261516d5ce6f8b0d69cf9e3da7dd2f0ef1cdc36a (diff)
downloadphp-shirabe-695365a0ad68e4534425c64b7a6a4b6598b68ef7.tar.gz
php-shirabe-695365a0ad68e4534425c64b7a6a4b6598b68ef7.tar.zst
php-shirabe-695365a0ad68e4534425c64b7a6a4b6598b68ef7.zip
feat(plugin): dispatch plugin event subscribers through the RPC worker
Wires the addPlugin subscriber branch end to end: EventSubscriberInterface and Capable become fallible and dyn-compatible (their sole implementor is the PHP plugin proxy, which answers getSubscribedEvents over RPC), listeners register as Callable::PhpMethod and are invoked with a per-call event handle, and the R table now drops entries when a child-side stub destructs. The R table keeps its IndexMap with monotonically increasing handles, so released handles are never reused and no generation counter is needed. Upstream has no subscriber-plugin test, so the path is covered by a Shirabe-owned fixture exercising all three getSubscribedEvents shapes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/tests/plugin/subscriber_test.rs')
-rw-r--r--crates/shirabe/tests/plugin/subscriber_test.rs109
1 files changed, 109 insertions, 0 deletions
diff --git a/crates/shirabe/tests/plugin/subscriber_test.rs b/crates/shirabe/tests/plugin/subscriber_test.rs
new file mode 100644
index 00000000..8de3d8c2
--- /dev/null
+++ b/crates/shirabe/tests/plugin/subscriber_test.rs
@@ -0,0 +1,109 @@
+//! Shirabe-specific integration tests for the subscriber plugin path: upstream Composer
+//! has no test that exercises `addSubscriber`/`getSubscribedEvents` through a real plugin, so
+//! these tests use a Shirabe-owned fixture (`fixtures/subscriber-v1`) instead of a ported one.
+
+use crate::async_runtime::run;
+use crate::plugin_installer_test::{lock_php_worker, new_installer, php_runtime_available, set_up};
+use shirabe::installer::InstallerInterface;
+use shirabe::package::PackageInterfaceHandle;
+use shirabe::package::loader::{ArrayLoader, JsonLoader, JsonLoaderInput};
+
+fn subscriber_fixture_package() -> PackageInterfaceHandle {
+ let loader = JsonLoader::new(Box::new(ArrayLoader::new(None, false)));
+ let path = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
+ .join("tests/plugin/fixtures/subscriber-v1/composer.json");
+ loader
+ .load(JsonLoaderInput::String(
+ path.canonicalize().unwrap().to_str().unwrap().to_string(),
+ ))
+ .unwrap()
+}
+
+/// Installs the subscriber fixture plugin: activate runs in the PHP child and
+/// `addSubscriber` registers its listeners with the event dispatcher.
+fn install_subscriber_plugin(set_up: &crate::plugin_installer_test::SetUp) {
+ let installer = new_installer(set_up);
+ set_up.pm.borrow_mut().load_installed_plugins().unwrap();
+ run(installer.install(&set_up.repository, subscriber_fixture_package())).unwrap();
+ assert_eq!("activate subscriber-v1\n", set_up.io.borrow().get_output());
+}
+
+fn dispatch(set_up: &crate::plugin_installer_test::SetUp, event_name: &str) -> i64 {
+ let dispatcher = set_up.composer.borrow().get_event_dispatcher();
+ let result = dispatcher.borrow_mut().dispatch(Some(event_name), None);
+ result.unwrap()
+}
+
+#[test]
+fn test_subscriber_listener_receives_event() {
+ if !php_runtime_available() {
+ return;
+ }
+ let _worker = lock_php_worker();
+ let set_up = set_up();
+ install_subscriber_plugin(&set_up);
+
+ // 'post-install-cmd' => 'onPostInstall' (bare method-name shape); the listener calls
+ // $event->getName() back over RPC.
+ let return_code = dispatch(&set_up, "post-install-cmd");
+
+ assert_eq!(0, return_code);
+ assert_eq!(
+ "activate subscriber-v1\nsubscriber saw post-install-cmd\n",
+ set_up.io.borrow().get_output()
+ );
+}
+
+#[test]
+fn test_subscriber_listeners_run_in_priority_order() {
+ if !php_runtime_available() {
+ return;
+ }
+ let _worker = lock_php_worker();
+ let set_up = set_up();
+ install_subscriber_plugin(&set_up);
+
+ // 'shirabe-priority-event' => [['early', 10], ['late', -10]] (multi-handler shape).
+ let return_code = dispatch(&set_up, "shirabe-priority-event");
+
+ assert_eq!(0, return_code);
+ assert_eq!(
+ "activate subscriber-v1\nearly listener\nlate listener\n",
+ set_up.io.borrow().get_output()
+ );
+}
+
+#[test]
+fn test_subscriber_listener_returning_false_sets_return_code() {
+ if !php_runtime_available() {
+ return;
+ }
+ let _worker = lock_php_worker();
+ let set_up = set_up();
+ install_subscriber_plugin(&set_up);
+
+ // 'shirabe-false-event' => ['returnsFalse', 0] (method+priority shape); PHP maps a false
+ // listener return to exit code 1.
+ let return_code = dispatch(&set_up, "shirabe-false-event");
+
+ assert_eq!(1, return_code);
+ assert_eq!(
+ "activate subscriber-v1\nfailing listener\n",
+ set_up.io.borrow().get_output()
+ );
+}
+
+#[test]
+fn test_unrelated_event_does_not_reach_the_subscriber() {
+ if !php_runtime_available() {
+ return;
+ }
+ let _worker = lock_php_worker();
+ let set_up = set_up();
+ install_subscriber_plugin(&set_up);
+
+ let return_code = dispatch(&set_up, "shirabe-unrelated-event");
+
+ assert_eq!(0, return_code);
+ assert_eq!("activate subscriber-v1\n", set_up.io.borrow().get_output());
+}