- Add TestPythonAPIServerStartup: verify server starts and registrar called
- Add TestPythonAPIServerLifecycle: verify cleanup stops server properly
- Add TestPythonCommandWithAPIServer: verify env var not set when apiImpl is nil
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add apiServerCleanup call to supervisor Shutdown method
- Cleanup happens AFTER Python process terminates for graceful disconnect
- Fix test assertion to check for relative executable path
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add startAPIServer function to start gRPC server on random port
- Add APIServerRegistrar type to break import cycle with apiserver package
- Modify WithCommandFromManifest to accept apiImpl and registrar
- Update configurePythonCommand to start API server and set MATTERMOST_PLUGIN_API_TARGET env var
- Add apiServerCleanup field to supervisor struct for cleanup on shutdown
- Add SetAPIServerRegistrar method to Environment for dependency injection
- Wire up API server registrar in app/plugin.go
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add TestPythonPluginHookDispatch that verifies end-to-end hook dispatch
for Python plugins. The test:
- Creates a fake Python plugin with PluginHooks gRPC service
- Verifies hooks are properly wired through the supervisor
- Tests Implemented(), OnActivate, OnDeactivate, and MessageHasBeenPosted
Also update existing Phase 5 tests to implement PluginHooks service:
- TestPythonSupervisor_HealthCheckSuccess
- TestPythonPluginEnvironmentActivation
- TestPythonSupervisor_Restart
These tests now reflect the new architecture where Python plugins
have hooks wired via hooksGRPCClient.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace props.runtime test cases with Server.Runtime field tests:
- python runtime from manifest field (no .py extension)
- go runtime explicit (should not be Python)
- python with full config (PythonVersion, ManifestPython)
- Keep .py extension fallback test for backward compatibility
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add end-to-end test for restart behavior:
1. Activate healthy fake Python plugin
2. Verify health check succeeds
3. Kill process via supervisor.client.Kill() to simulate crash
4. Verify health check fails after crash
5. Call RestartPlugin and verify health check succeeds again
Uses polling loops instead of arbitrary sleeps for reliability.
Proves Environment.RestartPlugin can recover crashed Python plugins.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add tests for:
- Handshake timeout: fake interpreter blocks forever without printing
handshake, verifies supervisor times out within StartTimeout
- Invalid handshake: fake interpreter prints netrpc protocol instead of
grpc, verifies protocol mismatch error
- Malformed handshake: fake interpreter prints incomplete handshake line,
verifies parsing error
These tests use compiled Go binaries as fake "Python interpreters" to
validate supervisor error handling without requiring real Python.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- TestPythonSupervisor_HealthCheckSuccess: validates end-to-end spawning
of Python-style plugin with gRPC health check using fake interpreter
- TestPythonPluginEnvironmentActivation: validates Environment can
activate/deactivate Python plugins without panicking on nil hooks
- Update Environment.Activate to use WithCommandFromManifest which
handles both Go (netrpc) and Python (gRPC) plugins
The fake interpreter is a compiled Go binary that:
1. Starts a gRPC server on random port
2. Registers health service with "plugin" status SERVING
3. Prints go-plugin handshake line
4. Blocks until killed
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add helper functions for Python plugin support in the supervisor:
- isPythonPlugin: detects Python plugins via .py extension or props.runtime
- findPythonInterpreter: discovers venv-first Python with PATH fallback
- sanitizePythonScriptPath: validates script paths preventing traversal
- buildPythonCommand: creates exec.Cmd with proper working dir and WaitDelay
- WithCommandFromManifest: unified option for Go and Python plugin commands
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>