Reqord.CassetteState (reqord v0.4.0)

View Source

Manages cassette entry state across multiple processes using GenServer.

This module solves the issue where concurrent requests (e.g., from Task.async) weren't being recorded because Reqord was using process-local storage.

Following ExVCR's pattern, this uses GenServer for robust state management that can be accessed from any process.

Additionally, this module manages per-process cassette context, which allows macro-generated tests to provide additional metadata for cassette naming.

Summary

Functions

Advances the replay position for a cassette. Creates the state if it doesn't exist.

Appends a new entry to the cassette state. Creates the state if it doesn't exist.

Returns a specification to start this module under a supervisor.

Clears cassette context for the current process.

Clears all entries for a cassette.

Retrieves cassette context for the current process.

Gets the current accumulated entries for a cassette. Returns empty list if no state exists.

Gets the current replay position for a cassette. Returns 0 if no state exists.

Stores cassette context for the current process.

Resets the replay position to 0 for a cassette.

Starts a named GenServer for a specific cassette.

Stops the named GenServer for a cassette.

Functions

advance_replay_position(cassette_path)

@spec advance_replay_position(String.t()) :: :ok

Advances the replay position for a cassette. Creates the state if it doesn't exist.

append_entry(cassette_path, entry)

@spec append_entry(String.t(), Reqord.CassetteEntry.t()) :: :ok

Appends a new entry to the cassette state. Creates the state if it doesn't exist.

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

clear_context(pid)

@spec clear_context(pid()) :: :ok

Clears cassette context for the current process.

clear_entries(cassette_path)

@spec clear_entries(String.t()) :: :ok

Clears all entries for a cassette.

get_context(pid)

@spec get_context(pid()) :: map()

Retrieves cassette context for the current process.

Returns an empty map if no context has been set.

Examples

iex> Reqord.CassetteState.get_context(self())
%{}

iex> Reqord.CassetteState.put_context(self(), %{model: "gpt-4"})
iex> Reqord.CassetteState.get_context(self())
%{model: "gpt-4"}

get_entries(cassette_path)

@spec get_entries(String.t()) :: [Reqord.CassetteEntry.t()]

Gets the current accumulated entries for a cassette. Returns empty list if no state exists.

get_replay_position(cassette_path)

@spec get_replay_position(String.t()) :: non_neg_integer()

Gets the current replay position for a cassette. Returns 0 if no state exists.

put_context(pid, context)

@spec put_context(pid(), map()) :: :ok

Stores cassette context for the current process.

This allows macro-generated tests to provide additional metadata that will be merged with the test context when determining cassette names.

Examples

# In a macro-generated test setup
Reqord.CassetteState.put_context(self(), %{
  provider: "google",
  model: "gemini-2.0-flash"
})

reset_replay_position(cassette_path)

@spec reset_replay_position(String.t()) :: :ok

Resets the replay position to 0 for a cassette.

start_for_cassette(cassette_path)

@spec start_for_cassette(String.t()) :: {:ok, pid()} | {:error, term()}

Starts a named GenServer for a specific cassette.

stop_for_cassette(cassette_path)

@spec stop_for_cassette(String.t()) :: :ok

Stops the named GenServer for a cassette.