test/build: Stability, compatibility

This commit is contained in:
2026-03-20 04:10:06 +01:00
parent 8b5231fa0d
commit 28c47ab435
4 changed files with 86 additions and 17 deletions

View File

@@ -1,5 +1,4 @@
set shell := ["bash", "-euo", "pipefail", "-c"] set shell := ["bash", "-euo", "pipefail", "-c"]
set script-interpreter := ["bash", "-euo", "pipefail"]
repo_root := justfile_directory() repo_root := justfile_directory()
@@ -12,8 +11,9 @@ help topic="":
@cd "{{repo_root}}" && ./scripts/just_help.sh "{{topic}}" @cd "{{repo_root}}" && ./scripts/just_help.sh "{{topic}}"
# Raw e2e harness commands. # Raw e2e harness commands.
[script] e2e subcommand *args:
e2e subcommand="help" *args: #!/usr/bin/env bash
set -euo pipefail
cd "{{repo_root}}" cd "{{repo_root}}"
subcommand="{{subcommand}}" subcommand="{{subcommand}}"
@@ -40,8 +40,9 @@ e2e subcommand="help" *args:
fi fi
# Benchmark flows (local/cloud/history + direct relay targets). # Benchmark flows (local/cloud/history + direct relay targets).
[script] bench subcommand *args:
bench subcommand="help" *args: #!/usr/bin/env bash
set -euo pipefail
cd "{{repo_root}}" cd "{{repo_root}}"
subcommand="{{subcommand}}" subcommand="{{subcommand}}"

View File

@@ -22,7 +22,17 @@ defmodule Parrhesia.Storage.Adapters.Memory.Store do
audit_logs: [] audit_logs: []
} }
def ensure_started, do: start_store() def start_link(opts \\ []) do
name = Keyword.get(opts, :name, @name)
Agent.start_link(&init_state/0, name: name)
end
def ensure_started do
case Process.whereis(@name) do
pid when is_pid(pid) -> :ok
nil -> start_store()
end
end
def put_event(event_id, event) when is_binary(event_id) and is_map(event) do def put_event(event_id, event) when is_binary(event_id) and is_map(event) do
:ok = ensure_started() :ok = ensure_started()
@@ -159,28 +169,72 @@ defmodule Parrhesia.Storage.Adapters.Memory.Store do
defp normalize_reduce_result(next_acc), do: next_acc defp normalize_reduce_result(next_acc), do: next_acc
def get(fun) do def get(fun) do
:ok = ensure_started() with_store(fn pid -> Agent.get(pid, fun) end)
Agent.get(@name, fun)
end end
def update(fun) do def update(fun) do
:ok = ensure_started() with_store(fn pid -> Agent.update(pid, fun) end)
Agent.update(@name, fun)
end end
def get_and_update(fun) do def get_and_update(fun) do
:ok = ensure_started() with_store(fn pid -> Agent.get_and_update(pid, fun) end)
Agent.get_and_update(@name, fun)
end end
defp start_store do defp start_store do
case Agent.start_link(&init_state/0, name: @name) do case start_link() do
{:ok, _pid} -> :ok {:ok, _pid} ->
{:error, {:already_started, _pid}} -> :ok :ok
{:error, reason} -> {:error, reason}
{:error, {:already_started, pid}} ->
if Process.alive?(pid) do
:ok
else
wait_for_store_exit(pid)
end
{:error, reason} ->
{:error, reason}
end end
end end
defp with_store(fun, attempts \\ 2)
defp with_store(fun, attempts) when attempts > 0 do
:ok = ensure_started()
case Process.whereis(@name) do
pid when is_pid(pid) ->
try do
fun.(pid)
catch
:exit, reason ->
if noproc_exit?(reason) and attempts > 1 do
with_store(fun, attempts - 1)
else
exit(reason)
end
end
nil ->
with_store(fun, attempts - 1)
end
end
defp with_store(_fun, 0), do: exit(:noproc)
defp wait_for_store_exit(pid) do
ref = Process.monitor(pid)
receive do
{:DOWN, ^ref, :process, ^pid, _reason} -> start_store()
after
100 -> start_store()
end
end
defp noproc_exit?({:noproc, _details}), do: true
defp noproc_exit?(_reason), do: false
defp init_state do defp init_state do
ensure_tables_started() ensure_tables_started()

View File

@@ -13,11 +13,19 @@ defmodule Parrhesia.Storage.Supervisor do
@impl true @impl true
def init(_init_arg) do def init(_init_arg) do
children = moderation_cache_children() ++ PostgresRepos.started_repos() children =
memory_store_children() ++ moderation_cache_children() ++ PostgresRepos.started_repos()
Supervisor.init(children, strategy: :one_for_one) Supervisor.init(children, strategy: :one_for_one)
end end
defp memory_store_children do
case Application.get_env(:parrhesia, :storage, [])[:backend] do
:memory -> [Parrhesia.Storage.Adapters.Memory.Store]
_other -> []
end
end
defp moderation_cache_children do defp moderation_cache_children do
if PostgresRepos.postgres_enabled?() and if PostgresRepos.postgres_enabled?() and
Application.get_env(:parrhesia, :moderation_cache_enabled, true) do Application.get_env(:parrhesia, :moderation_cache_enabled, true) do

View File

@@ -6,6 +6,12 @@ defmodule Parrhesia.Storage.Adapters.Memory.AdapterTest do
alias Parrhesia.Storage.Adapters.Memory.Events alias Parrhesia.Storage.Adapters.Memory.Events
alias Parrhesia.Storage.Adapters.Memory.Groups alias Parrhesia.Storage.Adapters.Memory.Groups
alias Parrhesia.Storage.Adapters.Memory.Moderation alias Parrhesia.Storage.Adapters.Memory.Moderation
alias Parrhesia.Storage.Adapters.Memory.Store
setup do
start_supervised!(Store)
:ok
end
test "memory adapter supports basic behavior contract operations" do test "memory adapter supports basic behavior contract operations" do
event_id = String.duplicate("a", 64) event_id = String.duplicate("a", 64)