Implement remaining Postgres storage adapters and contracts
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
defmodule Parrhesia.Storage.Adapters.Postgres.AdapterContractTest do
|
||||
use ExUnit.Case, async: false
|
||||
|
||||
alias Ecto.Adapters.SQL.Sandbox
|
||||
alias Parrhesia.Repo
|
||||
alias Parrhesia.Storage.Adapters.Postgres.Admin
|
||||
alias Parrhesia.Storage.Adapters.Postgres.Groups
|
||||
alias Parrhesia.Storage.Adapters.Postgres.Moderation
|
||||
|
||||
setup_all do
|
||||
start_supervised!(Repo)
|
||||
Sandbox.mode(Repo, :manual)
|
||||
:ok
|
||||
end
|
||||
|
||||
setup do
|
||||
:ok = Sandbox.checkout(Repo)
|
||||
end
|
||||
|
||||
test "moderation adapter persists pubkey/event/ip block state" do
|
||||
pubkey = String.duplicate("a", 64)
|
||||
event_id = String.duplicate("b", 64)
|
||||
|
||||
assert {:ok, false} = Moderation.pubkey_banned?(%{}, pubkey)
|
||||
assert :ok = Moderation.ban_pubkey(%{}, pubkey)
|
||||
assert :ok = Moderation.ban_pubkey(%{}, pubkey)
|
||||
assert {:ok, true} = Moderation.pubkey_banned?(%{}, pubkey)
|
||||
assert :ok = Moderation.unban_pubkey(%{}, pubkey)
|
||||
assert {:ok, false} = Moderation.pubkey_banned?(%{}, pubkey)
|
||||
|
||||
assert {:ok, false} = Moderation.pubkey_allowed?(%{}, pubkey)
|
||||
assert :ok = Moderation.allow_pubkey(%{}, pubkey)
|
||||
assert {:ok, true} = Moderation.pubkey_allowed?(%{}, pubkey)
|
||||
assert :ok = Moderation.disallow_pubkey(%{}, pubkey)
|
||||
assert {:ok, false} = Moderation.pubkey_allowed?(%{}, pubkey)
|
||||
|
||||
assert {:ok, false} = Moderation.event_banned?(%{}, event_id)
|
||||
assert :ok = Moderation.ban_event(%{}, event_id)
|
||||
assert {:ok, true} = Moderation.event_banned?(%{}, event_id)
|
||||
assert :ok = Moderation.unban_event(%{}, event_id)
|
||||
assert {:ok, false} = Moderation.event_banned?(%{}, event_id)
|
||||
|
||||
assert {:ok, false} = Moderation.ip_blocked?(%{}, "127.0.0.1")
|
||||
assert :ok = Moderation.block_ip(%{}, "127.0.0.1")
|
||||
assert {:ok, true} = Moderation.ip_blocked?(%{}, "127.0.0.1")
|
||||
assert :ok = Moderation.unblock_ip(%{}, "127.0.0.1")
|
||||
assert {:ok, false} = Moderation.ip_blocked?(%{}, "127.0.0.1")
|
||||
end
|
||||
|
||||
test "groups adapter upserts and lists memberships and roles" do
|
||||
group_id = "group-alpha"
|
||||
member_pubkey = String.duplicate("c", 64)
|
||||
|
||||
assert {:ok, membership} =
|
||||
Groups.put_membership(%{}, %{
|
||||
group_id: group_id,
|
||||
pubkey: member_pubkey,
|
||||
role: "member",
|
||||
metadata: %{"joined_via" => "invite"}
|
||||
})
|
||||
|
||||
assert membership.group_id == group_id
|
||||
assert membership.pubkey == member_pubkey
|
||||
assert membership.role == "member"
|
||||
|
||||
assert {:ok, fetched_membership} = Groups.get_membership(%{}, group_id, member_pubkey)
|
||||
assert fetched_membership.metadata == %{"joined_via" => "invite"}
|
||||
|
||||
assert {:ok, updated_membership} =
|
||||
Groups.put_membership(%{}, %{
|
||||
"group_id" => group_id,
|
||||
"pubkey" => member_pubkey,
|
||||
"role" => "admin",
|
||||
"metadata" => %{"joined_via" => "promoted"}
|
||||
})
|
||||
|
||||
assert updated_membership.role == "admin"
|
||||
|
||||
assert {:ok, memberships} = Groups.list_memberships(%{}, group_id)
|
||||
assert Enum.map(memberships, &{&1.pubkey, &1.role}) == [{member_pubkey, "admin"}]
|
||||
|
||||
assert {:ok, role} =
|
||||
Groups.put_role(%{}, %{
|
||||
group_id: group_id,
|
||||
pubkey: member_pubkey,
|
||||
role: "moderator",
|
||||
metadata: %{"scope" => "global"}
|
||||
})
|
||||
|
||||
assert role.role == "moderator"
|
||||
|
||||
assert {:ok, roles} = Groups.list_roles(%{}, group_id, member_pubkey)
|
||||
assert Enum.map(roles, & &1.role) == ["moderator"]
|
||||
|
||||
assert :ok = Groups.delete_role(%{}, group_id, member_pubkey, "moderator")
|
||||
assert {:ok, []} = Groups.list_roles(%{}, group_id, member_pubkey)
|
||||
|
||||
assert :ok = Groups.delete_membership(%{}, group_id, member_pubkey)
|
||||
assert {:ok, nil} = Groups.get_membership(%{}, group_id, member_pubkey)
|
||||
end
|
||||
|
||||
test "admin adapter appends and filters audit logs" do
|
||||
actor_pubkey = String.duplicate("d", 64)
|
||||
|
||||
assert :ok =
|
||||
Admin.append_audit_log(%{}, %{
|
||||
method: "ban_pubkey",
|
||||
actor_pubkey: actor_pubkey,
|
||||
params: %{"pubkey" => String.duplicate("e", 64)},
|
||||
result: %{"ok" => true}
|
||||
})
|
||||
|
||||
assert :ok =
|
||||
Admin.append_audit_log(%{}, %{
|
||||
method: "stats",
|
||||
params: %{"window" => "24h"}
|
||||
})
|
||||
|
||||
assert {:ok, logs} = Admin.list_audit_logs(%{}, limit: 10)
|
||||
assert length(logs) == 2
|
||||
|
||||
assert {:ok, actor_logs} = Admin.list_audit_logs(%{}, actor_pubkey: actor_pubkey)
|
||||
assert Enum.map(actor_logs, & &1.method) == ["ban_pubkey"]
|
||||
|
||||
assert {:ok, stats_logs} = Admin.list_audit_logs(%{}, method: :stats)
|
||||
assert Enum.map(stats_logs, & &1.method) == ["stats"]
|
||||
|
||||
assert {:error, {:unsupported_method, "status"}} = Admin.execute(%{}, :status, %{})
|
||||
end
|
||||
end
|
||||
@@ -152,6 +152,71 @@ defmodule Parrhesia.Storage.Adapters.Postgres.EventsQueryCountTest do
|
||||
assert {:ok, 2} = Events.count(%{}, filters, now: now)
|
||||
end
|
||||
|
||||
test "replaceable events expose only the current winner" do
|
||||
author = String.duplicate("a", 64)
|
||||
|
||||
older =
|
||||
persist_event(%{
|
||||
"pubkey" => author,
|
||||
"created_at" => 1_700_000_300,
|
||||
"kind" => 0,
|
||||
"content" => "profile-v1"
|
||||
})
|
||||
|
||||
newer =
|
||||
persist_event(%{
|
||||
"pubkey" => author,
|
||||
"created_at" => 1_700_000_301,
|
||||
"kind" => 0,
|
||||
"content" => "profile-v2"
|
||||
})
|
||||
|
||||
assert {:ok, [result]} = Events.query(%{}, [%{"authors" => [author], "kinds" => [0]}], [])
|
||||
assert result["id"] == newer["id"]
|
||||
|
||||
assert {:ok, nil} = Events.get_event(%{}, older["id"])
|
||||
assert {:ok, persisted_newer} = Events.get_event(%{}, newer["id"])
|
||||
assert persisted_newer["id"] == newer["id"]
|
||||
|
||||
assert {:ok, 1} = Events.count(%{}, [%{"ids" => [older["id"], newer["id"]]}], [])
|
||||
end
|
||||
|
||||
test "addressable events tie-break by lexical id for identical timestamps" do
|
||||
author = String.duplicate("b", 64)
|
||||
|
||||
first =
|
||||
persist_event(%{
|
||||
"pubkey" => author,
|
||||
"created_at" => 1_700_000_400,
|
||||
"kind" => 30_023,
|
||||
"tags" => [["d", "topic"]],
|
||||
"content" => "version-a"
|
||||
})
|
||||
|
||||
second =
|
||||
persist_event(%{
|
||||
"pubkey" => author,
|
||||
"created_at" => 1_700_000_400,
|
||||
"kind" => 30_023,
|
||||
"tags" => [["d", "topic"]],
|
||||
"content" => "version-b"
|
||||
})
|
||||
|
||||
winner_id = Enum.min([first["id"], second["id"]])
|
||||
loser_id = Enum.max([first["id"], second["id"]])
|
||||
|
||||
assert {:ok, [result]} =
|
||||
Events.query(
|
||||
%{},
|
||||
[%{"authors" => [author], "kinds" => [30_023], "#d" => ["topic"]}],
|
||||
[]
|
||||
)
|
||||
|
||||
assert result["id"] == winner_id
|
||||
assert {:ok, nil} = Events.get_event(%{}, loser_id)
|
||||
assert {:ok, 1} = Events.count(%{}, [%{"ids" => [first["id"], second["id"]]}], [])
|
||||
end
|
||||
|
||||
defp persist_event(overrides) do
|
||||
event = build_event(overrides)
|
||||
assert {:ok, _persisted} = Events.put_event(%{}, event)
|
||||
|
||||
Reference in New Issue
Block a user