Session manager for concurrent test renderer sessions.
For :mock and :headless, owns a single renderer Port and multiplexes
multiple logical sessions over it. For :windowed, each logical session
gets its own renderer process because the real iced renderer only supports
one live app session per process.
Usage
Start the pool once (typically in test_helper.exs or setup_all):
{:ok, pool} = SessionPool.start_link(mode: :mock, max_sessions: 8)The Runtime test backend connects to the pool via a PoolAdapter:
session = Session.start(MyApp, backend: Backend.Runtime, pool: pool)The pool assigns session IDs, sends messages to the right renderer, and forwards replies back to the caller.
Summary
Functions
Returns a specification to start this module under a supervisor.
Register a new session. Returns a unique session ID.
Send an interact message that may produce intermediate steps.
Send a message to the renderer for the given session.
Start the pool, spawning a renderer process.
Unregister a session. Sends Reset to the renderer to free resources.
Unregister a session without waiting for the renderer reset.
Types
@type mode() :: :mock | :headless | :windowed
@type session_id() :: String.t()
@type t() :: %Plushie.Test.SessionPool{ closing_windowed: %{ required(session_id()) => {Plushie.Test.SessionPool.Windowed.close_kind(), port()} }, env: [{String.t(), String.t()}], format: Plushie.Test.SessionPool.Transport.format(), max_sessions: pos_integer(), mode: mode(), multiplexed: Plushie.Test.SessionPool.Multiplexed.t() | nil, next_id: pos_integer(), next_session: pos_integer(), renderer: String.t(), sessions: %{required(session_id()) => Plushie.Test.SessionPool.Windowed.t()} }
Pool state for the test renderer session manager.
The top-level struct keeps only pool-wide configuration and counters. Mode-
specific runtime state lives in Multiplexed or Windowed structs.
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec register(pool :: GenServer.server()) :: session_id()
Register a new session. Returns a unique session ID.
@spec send_interact( pool :: GenServer.server(), session_id(), msg :: map() ) :: String.t()
Send an interact message that may produce intermediate steps.
Unlike send_message/4, this does NOT block for the response.
Instead, interact_step and interact_response messages are
forwarded to the session owner via {:plushie_pool_event, ...}.
The caller is responsible for handling them in handle_info.
Returns the request ID assigned to this interact.
@spec send_message( pool :: GenServer.server(), session_id(), msg :: map(), expect_response :: String.t() | nil ) :: {:ok, map()} | {:error, term()} | :ok
Send a message to the renderer for the given session.
The session field is injected automatically. Synchronous -- waits
for the matching response if expect_response is a response type
string (e.g. "query_response"). For fire-and-forget messages
(snapshot, patch, subscription), pass nil.
@spec start_link(keyword()) :: GenServer.on_start()
Start the pool, spawning a renderer process.
Options
:renderer-- path to the plushie binary (required):mode--:mock(default),:headless, or:windowed:format--:msgpack(default) or:json:max_sessions-- maximum concurrent sessions (default 8):name-- optional registered name for the pool
@spec unregister(pool :: GenServer.server(), session_id()) :: :ok
Unregister a session. Sends Reset to the renderer to free resources.
@spec unregister_async(pool :: GenServer.server(), session_id()) :: :ok
Unregister a session without waiting for the renderer reset.
The session is removed from the active map immediately. The reset is still sent to the renderer, but the caller doesn't block on the response. Used by terminate/2 to avoid blocking on slow renderers.