symbiont_ex/test/symbiont/dispatcher_test.exs

75 lines
2.1 KiB
Elixir

defmodule Symbiont.DispatcherTest do
use ExUnit.Case, async: false
@moduletag :capture_log
setup do
tmp_dir = Path.join(System.tmp_dir!(), "symbiont_dispatch_test_#{:rand.uniform(999_999)}")
File.mkdir_p!(tmp_dir)
# Start a fresh ledger for logging
if Process.whereis(Symbiont.Ledger), do: GenServer.stop(Symbiont.Ledger)
{:ok, _pid} = Symbiont.Ledger.start_link(data_dir: tmp_dir)
on_exit(fn ->
if Process.whereis(Symbiont.Ledger), do: GenServer.stop(Symbiont.Ledger)
File.rm_rf!(tmp_dir)
end)
%{tmp_dir: tmp_dir}
end
test "invoke with echo CLI returns result and logs to ledger" do
# In test config, claude_cli is "echo" — so System.cmd("echo", [...], input: prompt)
# echo doesn't actually read stdin, it echoes its args
result = Symbiont.Dispatcher.invoke(:haiku, "Hello world")
case result do
{:ok, entry} ->
assert entry.model == "haiku"
assert entry.success == true
assert is_float(entry.elapsed_seconds)
assert entry.estimated_cost_usd >= 0
# Ledger should have recorded it
Process.sleep(50)
entries = Symbiont.Ledger.recent()
assert length(entries) >= 1
{:error, _reason} ->
# echo might not be on path in all environments
:ok
end
end
test "invoke records prompt preview in ledger entry" do
long_prompt = String.duplicate("x", 200)
result = Symbiont.Dispatcher.invoke(:sonnet, long_prompt)
case result do
{:ok, entry} ->
# Prompt preview should be truncated to 100 chars
assert String.length(entry.prompt_preview) <= 100
{:error, _} ->
:ok
end
end
test "cost estimation is reasonable" do
# Test that the internal cost math works
# Haiku: 0.00000025/input + 0.00000125/output
# 1000 input + 500 output = 0.00025 + 0.000625 = 0.000875
result = Symbiont.Dispatcher.invoke(:haiku, "test")
case result do
{:ok, entry} ->
assert entry.estimated_cost_usd >= 0
assert entry.estimated_cost_usd < 1.0
{:error, _} ->
:ok
end
end
end