docs+nix: add deployment README and align release packaging

This commit is contained in:
2026-03-13 22:54:18 +01:00
parent f2a6ab5150
commit cc9c18b38c
19 changed files with 282 additions and 128 deletions

View File

@@ -7,7 +7,7 @@ defmodule Parrhesia.Auth.Nip98Test do
test "validates authorization header with matching method and url tags" do
url = "http://example.com/management"
event = nip98_event("POST", url)
header = "Nostr " <> Base.encode64(Jason.encode!(event))
header = "Nostr " <> Base.encode64(JSON.encode!(event))
assert {:ok, parsed_event} = Nip98.validate_authorization_header(header, "POST", url)
assert parsed_event["id"] == event["id"]
@@ -16,7 +16,7 @@ defmodule Parrhesia.Auth.Nip98Test do
test "rejects mismatched method and url" do
url = "http://example.com/management"
event = nip98_event("POST", url)
header = "Nostr " <> Base.encode64(Jason.encode!(event))
header = "Nostr " <> Base.encode64(JSON.encode!(event))
assert {:error, :invalid_method_tag} =
Nip98.validate_authorization_header(header, "GET", url)

View File

@@ -41,12 +41,12 @@ defmodule Parrhesia.FaultInjectionGroupFlowTest do
"content" => Base.encode64("commit")
})
payload = Jason.encode!(["EVENT", group_event])
payload = JSON.encode!(["EVENT", group_event])
assert {:push, {:text, error_response}, ^state} =
Connection.handle_in({payload, [opcode: :text]}, state)
assert Jason.decode!(error_response) == ["OK", group_event["id"], false, "error: :db_down"]
assert JSON.decode!(error_response) == ["OK", group_event["id"], false, "error: :db_down"]
Application.put_env(
:parrhesia,
@@ -57,7 +57,7 @@ defmodule Parrhesia.FaultInjectionGroupFlowTest do
assert {:push, {:text, ok_response}, ^state} =
Connection.handle_in({payload, [opcode: :text]}, state)
assert Jason.decode!(ok_response) == ["OK", group_event["id"], true, "ok: event stored"]
assert JSON.decode!(ok_response) == ["OK", group_event["id"], true, "ok: event stored"]
assert {:ok, persisted_group_event} = Storage.events().get_event(%{}, group_event["id"])
assert persisted_group_event["id"] == group_event["id"]
@@ -89,11 +89,11 @@ defmodule Parrhesia.FaultInjectionGroupFlowTest do
assert {:push, {:text, outage_response}, ^state} =
Connection.handle_in(
{Jason.encode!(["EVENT", older_event]), [opcode: :text]},
{JSON.encode!(["EVENT", older_event]), [opcode: :text]},
state
)
assert Jason.decode!(outage_response) == ["OK", older_event["id"], false, "error: :db_down"]
assert JSON.decode!(outage_response) == ["OK", older_event["id"], false, "error: :db_down"]
Application.put_env(
:parrhesia,
@@ -103,19 +103,19 @@ defmodule Parrhesia.FaultInjectionGroupFlowTest do
assert {:push, {:text, newer_response}, ^state} =
Connection.handle_in(
{Jason.encode!(["EVENT", newer_event]), [opcode: :text]},
{JSON.encode!(["EVENT", newer_event]), [opcode: :text]},
state
)
assert Jason.decode!(newer_response) == ["OK", newer_event["id"], true, "ok: event stored"]
assert JSON.decode!(newer_response) == ["OK", newer_event["id"], true, "ok: event stored"]
assert {:push, {:text, older_response}, ^state} =
Connection.handle_in(
{Jason.encode!(["EVENT", older_event]), [opcode: :text]},
{JSON.encode!(["EVENT", older_event]), [opcode: :text]},
state
)
assert Jason.decode!(older_response) == ["OK", older_event["id"], true, "ok: event stored"]
assert JSON.decode!(older_response) == ["OK", older_event["id"], true, "ok: event stored"]
assert {:ok, results} =
Storage.events().query(

View File

@@ -30,19 +30,19 @@ defmodule Parrhesia.FaultInjectionTest do
event = valid_event()
assert {:push, {:text, response}, ^state} =
Connection.handle_in({Jason.encode!(["EVENT", event]), [opcode: :text]}, state)
Connection.handle_in({JSON.encode!(["EVENT", event]), [opcode: :text]}, state)
assert Jason.decode!(response) == ["OK", event["id"], false, "error: :db_down"]
assert JSON.decode!(response) == ["OK", event["id"], false, "error: :db_down"]
end
test "REQ closes with storage error when query fails" do
{:ok, state} = Connection.init(subscription_index: nil)
payload = Jason.encode!(["REQ", "sub-db-down", %{"kinds" => [1]}])
payload = JSON.encode!(["REQ", "sub-db-down", %{"kinds" => [1]}])
assert {:push, {:text, response}, ^state} =
Connection.handle_in({payload, [opcode: :text]}, state)
assert Jason.decode!(response) == ["CLOSED", "sub-db-down", "error: :db_down"]
assert JSON.decode!(response) == ["CLOSED", "sub-db-down", "error: :db_down"]
end
defp valid_event do

View File

@@ -11,7 +11,7 @@ defmodule Parrhesia.Performance.LoadSoakTest do
{:ok, state} = Connection.init(subscription_index: nil, max_outbound_queue: 10_000)
req_payload = Jason.encode!(["REQ", "sub-load", %{"kinds" => [1]}])
req_payload = JSON.encode!(["REQ", "sub-load", %{"kinds" => [1]}])
assert {:push, _frames, subscribed_state} =
Connection.handle_in({req_payload, [opcode: :text]}, state)

View File

@@ -5,7 +5,7 @@ defmodule Parrhesia.ProtocolTest do
alias Parrhesia.Protocol.EventValidator
test "decodes EVENT frame shape" do
payload = Jason.encode!(["EVENT", valid_event()])
payload = JSON.encode!(["EVENT", valid_event()])
assert {:ok, {:event, event}} = Protocol.decode_client(payload)
assert event["kind"] == 1
@@ -13,9 +13,9 @@ defmodule Parrhesia.ProtocolTest do
end
test "decodes valid REQ, COUNT and CLOSE frames" do
req_payload = Jason.encode!(["REQ", "sub-1", %{"authors" => [String.duplicate("a", 64)]}])
count_payload = Jason.encode!(["COUNT", "sub-1", %{"kinds" => [1]}, %{"hll" => true}])
close_payload = Jason.encode!(["CLOSE", "sub-1"])
req_payload = JSON.encode!(["REQ", "sub-1", %{"authors" => [String.duplicate("a", 64)]}])
count_payload = JSON.encode!(["COUNT", "sub-1", %{"kinds" => [1]}, %{"hll" => true}])
close_payload = JSON.encode!(["CLOSE", "sub-1"])
assert {:ok, {:req, "sub-1", [%{"authors" => [_author]}]}} =
Protocol.decode_client(req_payload)
@@ -27,8 +27,8 @@ defmodule Parrhesia.ProtocolTest do
end
test "rejects invalid subscription ids" do
empty_sub_payload = Jason.encode!(["REQ", "", %{"kinds" => [1]}])
long_sub_payload = Jason.encode!(["CLOSE", String.duplicate("x", 65)])
empty_sub_payload = JSON.encode!(["REQ", "", %{"kinds" => [1]}])
long_sub_payload = JSON.encode!(["CLOSE", String.duplicate("x", 65)])
assert {:error, :invalid_subscription_id} = Protocol.decode_client(empty_sub_payload)
assert {:error, :invalid_subscription_id} = Protocol.decode_client(long_sub_payload)
@@ -39,25 +39,25 @@ defmodule Parrhesia.ProtocolTest do
auth_event = Map.put(auth_event, "id", EventValidator.compute_id(auth_event))
assert {:ok, {:auth, ^auth_event}} =
Protocol.decode_client(Jason.encode!(["AUTH", auth_event]))
Protocol.decode_client(JSON.encode!(["AUTH", auth_event]))
assert {:ok, {:neg_open, "sub-neg", %{"cursor" => 0}}} =
Protocol.decode_client(Jason.encode!(["NEG-OPEN", "sub-neg", %{"cursor" => 0}]))
Protocol.decode_client(JSON.encode!(["NEG-OPEN", "sub-neg", %{"cursor" => 0}]))
assert {:ok, {:neg_msg, "sub-neg", %{"delta" => "abc"}}} =
Protocol.decode_client(Jason.encode!(["NEG-MSG", "sub-neg", %{"delta" => "abc"}]))
Protocol.decode_client(JSON.encode!(["NEG-MSG", "sub-neg", %{"delta" => "abc"}]))
assert {:ok, {:neg_close, "sub-neg"}} =
Protocol.decode_client(Jason.encode!(["NEG-CLOSE", "sub-neg"]))
Protocol.decode_client(JSON.encode!(["NEG-CLOSE", "sub-neg"]))
end
test "returns decode errors for malformed messages" do
assert {:error, :invalid_json} = Protocol.decode_client("not-json")
assert {:error, :invalid_filters} = Protocol.decode_client(Jason.encode!(["REQ", "sub-1"]))
assert {:error, :invalid_count} = Protocol.decode_client(Jason.encode!(["COUNT", "sub-1"]))
assert {:error, :invalid_filters} = Protocol.decode_client(JSON.encode!(["REQ", "sub-1"]))
assert {:error, :invalid_count} = Protocol.decode_client(JSON.encode!(["COUNT", "sub-1"]))
assert {:error, :invalid_event} =
Protocol.decode_client(Jason.encode!(["EVENT", "not-a-map"]))
Protocol.decode_client(JSON.encode!(["EVENT", "not-a-map"]))
end
test "validates strict NIP-01 event fields" do
@@ -83,13 +83,13 @@ defmodule Parrhesia.ProtocolTest do
test "encodes relay messages" do
frame = Protocol.encode_relay({:closed, "sub-1", "error: subscription closed"})
assert Jason.decode!(frame) == ["CLOSED", "sub-1", "error: subscription closed"]
assert JSON.decode!(frame) == ["CLOSED", "sub-1", "error: subscription closed"]
auth_frame = Protocol.encode_relay({:auth, "challenge"})
assert Jason.decode!(auth_frame) == ["AUTH", "challenge"]
assert JSON.decode!(auth_frame) == ["AUTH", "challenge"]
count_frame = Protocol.encode_relay({:count, "sub-1", %{"count" => 1}})
assert Jason.decode!(count_frame) == ["COUNT", "sub-1", %{"count" => 1}]
assert JSON.decode!(count_frame) == ["COUNT", "sub-1", %{"count" => 1}]
end
defp valid_event do

View File

@@ -15,20 +15,20 @@ defmodule Parrhesia.Web.ConformanceTest do
test "REQ -> EOSE emitted once and CLOSE emits CLOSED" do
{:ok, state} = Connection.init(subscription_index: nil)
req_payload = Jason.encode!(["REQ", "sub-e2e", %{"kinds" => [1]}])
req_payload = JSON.encode!(["REQ", "sub-e2e", %{"kinds" => [1]}])
assert {:push, frames, subscribed_state} =
Connection.handle_in({req_payload, [opcode: :text]}, state)
decoded = Enum.map(frames, fn {:text, frame} -> Jason.decode!(frame) end)
decoded = Enum.map(frames, fn {:text, frame} -> JSON.decode!(frame) end)
assert ["EOSE", "sub-e2e"] = List.last(decoded)
close_payload = Jason.encode!(["CLOSE", "sub-e2e"])
close_payload = JSON.encode!(["CLOSE", "sub-e2e"])
assert {:push, {:text, closed_frame}, closed_state} =
Connection.handle_in({close_payload, [opcode: :text]}, subscribed_state)
assert Jason.decode!(closed_frame) == ["CLOSED", "sub-e2e", "error: subscription closed"]
assert JSON.decode!(closed_frame) == ["CLOSED", "sub-e2e", "error: subscription closed"]
refute Map.has_key?(closed_state.subscriptions, "sub-e2e")
end
@@ -38,9 +38,9 @@ defmodule Parrhesia.Web.ConformanceTest do
event = valid_event()
assert {:push, {:text, frame}, ^state} =
Connection.handle_in({Jason.encode!(["EVENT", event]), [opcode: :text]}, state)
Connection.handle_in({JSON.encode!(["EVENT", event]), [opcode: :text]}, state)
assert Jason.decode!(frame) == ["OK", event["id"], true, "ok: event stored"]
assert JSON.decode!(frame) == ["OK", event["id"], true, "ok: event stored"]
end
test "wrapped kind 1059 welcome delivery is recipient-gated" do
@@ -56,19 +56,19 @@ defmodule Parrhesia.Web.ConformanceTest do
assert {:push, {:text, ok_frame}, ^state} =
Connection.handle_in(
{Jason.encode!(["EVENT", wrapped_welcome]), [opcode: :text]},
{JSON.encode!(["EVENT", wrapped_welcome]), [opcode: :text]},
state
)
assert Jason.decode!(ok_frame) == ["OK", wrapped_welcome["id"], true, "ok: event stored"]
assert JSON.decode!(ok_frame) == ["OK", wrapped_welcome["id"], true, "ok: event stored"]
req_payload = Jason.encode!(["REQ", "sub-welcome", %{"kinds" => [1059], "#p" => [recipient]}])
req_payload = JSON.encode!(["REQ", "sub-welcome", %{"kinds" => [1059], "#p" => [recipient]}])
assert {:push, restricted_frames, ^state} =
Connection.handle_in({req_payload, [opcode: :text]}, state)
decoded_restricted =
Enum.map(restricted_frames, fn {:text, frame} -> Jason.decode!(frame) end)
Enum.map(restricted_frames, fn {:text, frame} -> JSON.decode!(frame) end)
assert [
"CLOSED",
@@ -80,14 +80,14 @@ defmodule Parrhesia.Web.ConformanceTest do
auth_event = valid_auth_event(state.auth_challenge, recipient)
assert {:push, {:text, auth_frame}, authed_state} =
Connection.handle_in({Jason.encode!(["AUTH", auth_event]), [opcode: :text]}, state)
Connection.handle_in({JSON.encode!(["AUTH", auth_event]), [opcode: :text]}, state)
assert Jason.decode!(auth_frame) == ["OK", auth_event["id"], true, "ok: auth accepted"]
assert JSON.decode!(auth_frame) == ["OK", auth_event["id"], true, "ok: auth accepted"]
assert {:push, frames, _next_state} =
Connection.handle_in({req_payload, [opcode: :text]}, authed_state)
decoded = Enum.map(frames, fn {:text, frame} -> Jason.decode!(frame) end)
decoded = Enum.map(frames, fn {:text, frame} -> JSON.decode!(frame) end)
assert ["EVENT", "sub-welcome", result_event] =
Enum.find(decoded, fn frame -> List.first(frame) == "EVENT" end)
@@ -108,11 +108,11 @@ defmodule Parrhesia.Web.ConformanceTest do
assert {:push, {:text, commit_ok_frame}, ^state} =
Connection.handle_in(
{Jason.encode!(["EVENT", commit_event]), [opcode: :text]},
{JSON.encode!(["EVENT", commit_event]), [opcode: :text]},
state
)
assert Jason.decode!(commit_ok_frame) == ["OK", commit_event["id"], true, "ok: event stored"]
assert JSON.decode!(commit_ok_frame) == ["OK", commit_event["id"], true, "ok: event stored"]
assert {:ok, persisted_commit} = Storage.events().get_event(%{}, commit_event["id"])
assert persisted_commit["id"] == commit_event["id"]
@@ -126,11 +126,11 @@ defmodule Parrhesia.Web.ConformanceTest do
assert {:push, {:text, welcome_ok_frame}, ^state} =
Connection.handle_in(
{Jason.encode!(["EVENT", wrapped_welcome]), [opcode: :text]},
{JSON.encode!(["EVENT", wrapped_welcome]), [opcode: :text]},
state
)
assert Jason.decode!(welcome_ok_frame) == [
assert JSON.decode!(welcome_ok_frame) == [
"OK",
wrapped_welcome["id"],
true,
@@ -189,11 +189,11 @@ defmodule Parrhesia.Web.ConformanceTest do
assert {:push, {:text, relay_ok_frame}, ^state} =
Connection.handle_in(
{Jason.encode!(["EVENT", relay_list_event]), [opcode: :text]},
{JSON.encode!(["EVENT", relay_list_event]), [opcode: :text]},
state
)
assert Jason.decode!(relay_ok_frame) == [
assert JSON.decode!(relay_ok_frame) == [
"OK",
relay_list_event["id"],
true,
@@ -202,11 +202,11 @@ defmodule Parrhesia.Web.ConformanceTest do
assert {:push, {:text, trigger_ok_frame}, ^state} =
Connection.handle_in(
{Jason.encode!(["EVENT", push_trigger]), [opcode: :text]},
{JSON.encode!(["EVENT", push_trigger]), [opcode: :text]},
state
)
assert Jason.decode!(trigger_ok_frame) == ["OK", push_trigger["id"], true, "ok: event stored"]
assert JSON.decode!(trigger_ok_frame) == ["OK", push_trigger["id"], true, "ok: event stored"]
assert {:ok, persisted_relay_list} = Storage.events().get_event(%{}, relay_list_event["id"])
assert persisted_relay_list["id"] == relay_list_event["id"]

View File

@@ -14,7 +14,7 @@ defmodule Parrhesia.Web.ConnectionTest do
test "REQ registers subscription, streams initial events and replies with EOSE" do
state = connection_state()
req_payload = Jason.encode!(["REQ", "sub-123", %{"kinds" => [1]}])
req_payload = JSON.encode!(["REQ", "sub-123", %{"kinds" => [1]}])
assert {:push, responses, next_state} =
Connection.handle_in({req_payload, [opcode: :text]}, state)
@@ -23,7 +23,7 @@ defmodule Parrhesia.Web.ConnectionTest do
assert next_state.subscriptions["sub-123"].filters == [%{"kinds" => [1]}]
assert next_state.subscriptions["sub-123"].eose_sent?
assert List.last(Enum.map(responses, fn {:text, frame} -> Jason.decode!(frame) end)) == [
assert List.last(Enum.map(responses, fn {:text, frame} -> JSON.decode!(frame) end)) == [
"EOSE",
"sub-123"
]
@@ -32,12 +32,12 @@ defmodule Parrhesia.Web.ConnectionTest do
test "COUNT returns exact count payload" do
state = connection_state()
payload = Jason.encode!(["COUNT", "sub-count", %{"kinds" => [1]}])
payload = JSON.encode!(["COUNT", "sub-count", %{"kinds" => [1]}])
assert {:push, {:text, response}, ^state} =
Connection.handle_in({payload, [opcode: :text]}, state)
assert ["COUNT", "sub-count", payload] = Jason.decode!(response)
assert ["COUNT", "sub-count", payload] = JSON.decode!(response)
assert payload["count"] >= 0
assert payload["approximate"] == false
end
@@ -46,12 +46,12 @@ defmodule Parrhesia.Web.ConnectionTest do
state = connection_state()
auth_event = valid_auth_event(state.auth_challenge)
payload = Jason.encode!(["AUTH", auth_event])
payload = JSON.encode!(["AUTH", auth_event])
assert {:push, {:text, response}, next_state} =
Connection.handle_in({payload, [opcode: :text]}, state)
assert Jason.decode!(response) == ["OK", auth_event["id"], true, "ok: auth accepted"]
assert JSON.decode!(response) == ["OK", auth_event["id"], true, "ok: auth accepted"]
assert MapSet.member?(next_state.authenticated_pubkeys, auth_event["pubkey"])
refute next_state.auth_challenge == state.auth_challenge
end
@@ -60,11 +60,11 @@ defmodule Parrhesia.Web.ConnectionTest do
state = connection_state()
auth_event = valid_auth_event("wrong-challenge")
payload = Jason.encode!(["AUTH", auth_event])
payload = JSON.encode!(["AUTH", auth_event])
assert {:push, frames, ^state} = Connection.handle_in({payload, [opcode: :text]}, state)
decoded = Enum.map(frames, fn {:text, frame} -> Jason.decode!(frame) end)
decoded = Enum.map(frames, fn {:text, frame} -> JSON.decode!(frame) end)
assert Enum.any?(decoded, fn frame -> frame == ["AUTH", state.auth_challenge] end)
@@ -81,11 +81,11 @@ defmodule Parrhesia.Web.ConnectionTest do
|> Map.put("tags", [["-"]])
|> then(&Map.put(&1, "id", EventValidator.compute_id(&1)))
payload = Jason.encode!(["EVENT", event])
payload = JSON.encode!(["EVENT", event])
assert {:push, frames, ^state} = Connection.handle_in({payload, [opcode: :text]}, state)
decoded = Enum.map(frames, fn {:text, frame} -> Jason.decode!(frame) end)
decoded = Enum.map(frames, fn {:text, frame} -> JSON.decode!(frame) end)
assert ["OK", _, false, "auth-required: protected events require authenticated pubkey"] =
Enum.find(decoded, fn frame -> List.first(frame) == "OK" end)
@@ -96,11 +96,11 @@ defmodule Parrhesia.Web.ConnectionTest do
test "kind 445 REQ without #h is rejected" do
state = connection_state()
req_payload = Jason.encode!(["REQ", "sub-445", %{"kinds" => [445]}])
req_payload = JSON.encode!(["REQ", "sub-445", %{"kinds" => [445]}])
assert {:push, frames, ^state} = Connection.handle_in({req_payload, [opcode: :text]}, state)
decoded = Enum.map(frames, fn {:text, frame} -> Jason.decode!(frame) end)
decoded = Enum.map(frames, fn {:text, frame} -> JSON.decode!(frame) end)
assert ["CLOSED", "sub-445", "restricted: kind 445 queries must include a #h tag"] =
Enum.find(decoded, fn frame -> List.first(frame) == "CLOSED" end)
@@ -110,24 +110,24 @@ defmodule Parrhesia.Web.ConnectionTest do
state = connection_state()
event = valid_event()
payload = Jason.encode!(["EVENT", event])
payload = JSON.encode!(["EVENT", event])
assert {:push, {:text, response}, ^state} =
Connection.handle_in({payload, [opcode: :text]}, state)
assert Jason.decode!(response) == ["OK", event["id"], true, "ok: event stored"]
assert JSON.decode!(response) == ["OK", event["id"], true, "ok: event stored"]
end
test "invalid EVENT replies with OK false invalid prefix" do
state = connection_state()
event = valid_event() |> Map.put("sig", "nope")
payload = Jason.encode!(["EVENT", event])
payload = JSON.encode!(["EVENT", event])
assert {:push, {:text, response}, ^state} =
Connection.handle_in({payload, [opcode: :text]}, state)
assert Jason.decode!(response) == [
assert JSON.decode!(response) == [
"OK",
event["id"],
false,
@@ -145,12 +145,12 @@ defmodule Parrhesia.Web.ConnectionTest do
|> Map.put("content", "ciphertext")
|> then(&Map.put(&1, "id", EventValidator.compute_id(&1)))
payload = Jason.encode!(["EVENT", event])
payload = JSON.encode!(["EVENT", event])
assert {:push, {:text, response}, ^state} =
Connection.handle_in({payload, [opcode: :text]}, state)
assert Jason.decode!(response) == [
assert JSON.decode!(response) == [
"OK",
event["id"],
false,
@@ -168,12 +168,12 @@ defmodule Parrhesia.Web.ConnectionTest do
|> Map.put("content", "not-base64")
|> then(&Map.put(&1, "id", EventValidator.compute_id(&1)))
payload = Jason.encode!(["EVENT", event])
payload = JSON.encode!(["EVENT", event])
assert {:push, {:text, response}, ^state} =
Connection.handle_in({payload, [opcode: :text]}, state)
assert Jason.decode!(response) == [
assert JSON.decode!(response) == [
"OK",
event["id"],
false,
@@ -202,12 +202,12 @@ defmodule Parrhesia.Web.ConnectionTest do
])
|> then(&Map.put(&1, "id", EventValidator.compute_id(&1)))
payload = Jason.encode!(["EVENT", event])
payload = JSON.encode!(["EVENT", event])
assert {:push, {:text, response}, ^state} =
Connection.handle_in({payload, [opcode: :text]}, state)
assert Jason.decode!(response) == [
assert JSON.decode!(response) == [
"OK",
event["id"],
false,
@@ -253,12 +253,12 @@ defmodule Parrhesia.Web.ConnectionTest do
|> Map.put("content", "encrypted")
|> then(&Map.put(&1, "id", EventValidator.compute_id(&1)))
payload = Jason.encode!(["EVENT", event])
payload = JSON.encode!(["EVENT", event])
assert {:push, {:text, response}, ^state} =
Connection.handle_in({payload, [opcode: :text]}, state)
assert Jason.decode!(response) == [
assert JSON.decode!(response) == [
"OK",
event["id"],
false,
@@ -304,17 +304,17 @@ defmodule Parrhesia.Web.ConnectionTest do
|> Map.put("content", "encrypted")
|> then(&Map.put(&1, "id", EventValidator.compute_id(&1)))
payload = Jason.encode!(["EVENT", event])
payload = JSON.encode!(["EVENT", event])
assert {:push, {:text, first_response}, ^state} =
Connection.handle_in({payload, [opcode: :text]}, state)
assert Jason.decode!(first_response) == ["OK", event["id"], true, "ok: event stored"]
assert JSON.decode!(first_response) == ["OK", event["id"], true, "ok: event stored"]
assert {:push, {:text, second_response}, ^state} =
Connection.handle_in({payload, [opcode: :text]}, state)
assert Jason.decode!(second_response) == [
assert JSON.decode!(second_response) == [
"OK",
event["id"],
false,
@@ -325,32 +325,32 @@ defmodule Parrhesia.Web.ConnectionTest do
test "NEG sessions open and close" do
state = connection_state()
open_payload = Jason.encode!(["NEG-OPEN", "neg-1", %{"cursor" => 0}])
open_payload = JSON.encode!(["NEG-OPEN", "neg-1", %{"cursor" => 0}])
assert {:push, {:text, open_response}, ^state} =
Connection.handle_in({open_payload, [opcode: :text]}, state)
assert ["NEG-MSG", "neg-1", %{"status" => "open", "cursor" => 0}] =
Jason.decode!(open_response)
JSON.decode!(open_response)
close_payload = Jason.encode!(["NEG-CLOSE", "neg-1"])
close_payload = JSON.encode!(["NEG-CLOSE", "neg-1"])
assert {:push, {:text, close_response}, ^state} =
Connection.handle_in({close_payload, [opcode: :text]}, state)
assert Jason.decode!(close_response) == ["NEG-MSG", "neg-1", %{"status" => "closed"}]
assert JSON.decode!(close_response) == ["NEG-MSG", "neg-1", %{"status" => "closed"}]
end
test "CLOSE removes subscription and replies with CLOSED" do
state = subscribed_connection_state([])
close_payload = Jason.encode!(["CLOSE", "sub-1"])
close_payload = JSON.encode!(["CLOSE", "sub-1"])
assert {:push, {:text, response}, next_state} =
Connection.handle_in({close_payload, [opcode: :text]}, state)
refute Map.has_key?(next_state.subscriptions, "sub-1")
assert Jason.decode!(response) == ["CLOSED", "sub-1", "error: subscription closed"]
assert JSON.decode!(response) == ["CLOSED", "sub-1", "error: subscription closed"]
end
test "fanout_event enqueues and drains matching events" do
@@ -366,7 +366,7 @@ defmodule Parrhesia.Web.ConnectionTest do
Connection.handle_info(:drain_outbound_queue, queued_state)
assert drained_state.outbound_queue_size == 0
assert Jason.decode!(payload) == ["EVENT", "sub-1", event]
assert JSON.decode!(payload) == ["EVENT", "sub-1", event]
end
test "high-volume kind 445 fanout drains in order across batches" do
@@ -392,7 +392,7 @@ defmodule Parrhesia.Web.ConnectionTest do
delivered_ids =
frames
|> Enum.map(fn {:text, payload} -> Jason.decode!(payload) end)
|> Enum.map(fn {:text, payload} -> JSON.decode!(payload) end)
|> Enum.map(fn ["EVENT", "sub-group", event] -> event["id"] end)
assert delivered_ids == Enum.map(events, & &1["id"])
@@ -418,12 +418,12 @@ defmodule Parrhesia.Web.ConnectionTest do
)
assert message == "rate-limited: outbound queue overflow"
assert Jason.decode!(notice_payload) == ["NOTICE", message]
assert JSON.decode!(notice_payload) == ["NOTICE", message]
end
defp subscribed_connection_state(opts) do
state = connection_state(opts)
req_payload = Jason.encode!(["REQ", "sub-1", %{"kinds" => [1]}])
req_payload = JSON.encode!(["REQ", "sub-1", %{"kinds" => [1]}])
assert {:push, _, subscribed_state} =
Connection.handle_in({req_payload, [opcode: :text]}, state)
@@ -433,7 +433,7 @@ defmodule Parrhesia.Web.ConnectionTest do
defp subscribed_group_connection_state(group_id, opts) do
state = connection_state(opts)
req_payload = Jason.encode!(["REQ", "sub-group", %{"kinds" => [445], "#h" => [group_id]}])
req_payload = JSON.encode!(["REQ", "sub-group", %{"kinds" => [445], "#h" => [group_id]}])
assert {:push, _, subscribed_state} =
Connection.handle_in({req_payload, [opcode: :text]}, state)

View File

@@ -37,7 +37,7 @@ defmodule Parrhesia.Web.RouterTest do
assert conn.status == 200
assert get_resp_header(conn, "content-type") == ["application/nostr+json; charset=utf-8"]
body = Jason.decode!(conn.resp_body)
body = JSON.decode!(conn.resp_body)
assert body["name"] == "Parrhesia"
assert 11 in body["supported_nips"]
@@ -52,29 +52,29 @@ defmodule Parrhesia.Web.RouterTest do
test "POST /management requires authorization" do
conn =
conn(:post, "/management", Jason.encode!(%{"method" => "ping", "params" => %{}}))
conn(:post, "/management", JSON.encode!(%{"method" => "ping", "params" => %{}}))
|> put_req_header("content-type", "application/json")
|> Router.call([])
assert conn.status == 401
assert Jason.decode!(conn.resp_body) == %{"ok" => false, "error" => "auth-required"}
assert JSON.decode!(conn.resp_body) == %{"ok" => false, "error" => "auth-required"}
end
test "POST /management accepts valid NIP-98 header" do
management_url = "http://www.example.com/management"
auth_event = nip98_event("POST", management_url)
authorization = "Nostr " <> Base.encode64(Jason.encode!(auth_event))
authorization = "Nostr " <> Base.encode64(JSON.encode!(auth_event))
conn =
conn(:post, "/management", Jason.encode!(%{"method" => "ping", "params" => %{}}))
conn(:post, "/management", JSON.encode!(%{"method" => "ping", "params" => %{}}))
|> put_req_header("content-type", "application/json")
|> put_req_header("authorization", authorization)
|> Router.call([])
assert conn.status == 200
assert Jason.decode!(conn.resp_body) == %{
assert JSON.decode!(conn.resp_body) == %{
"ok" => true,
"result" => %{"status" => "ok"}
}