Browse Source

Set up integration tests for REST endpoints

master
buttercat1791 2 months ago
parent
commit
8fc8cb9924
  1. 5
      config/test.exs
  2. 134
      test/gc_index_relay_web/controllers/event_controller_test.exs
  3. 283
      test/gc_index_relay_web/controllers/filter_controller_test.exs

5
config/test.exs

@ -1,8 +1,6 @@ @@ -1,8 +1,6 @@
import Config
# Allow tests to run without database by default
# Set REQUIRE_DB=true to enable database for integration tests
config :gc_index_relay, :start_repo, System.get_env("REQUIRE_DB") == "true"
config :gc_index_relay, :start_repo, true
# Configure your database
#
@ -10,6 +8,7 @@ config :gc_index_relay, :start_repo, System.get_env("REQUIRE_DB") == "true" @@ -10,6 +8,7 @@ config :gc_index_relay, :start_repo, System.get_env("REQUIRE_DB") == "true"
# to provide built-in test partitioning in CI environment.
# Run `mix help test` for more information.
config :gc_index_relay, GcIndexRelay.Repo,
port: 5455,
username: "postgres",
password: "postgres",
hostname: "localhost",

134
test/gc_index_relay_web/controllers/event_controller_test.exs

@ -2,101 +2,93 @@ defmodule GcIndexRelayWeb.EventControllerTest do @@ -2,101 +2,93 @@ defmodule GcIndexRelayWeb.EventControllerTest do
use GcIndexRelayWeb.ConnCase
import GcIndexRelay.NostrFixtures
alias GcIndexRelay.Nostr.Event
@moduletag :integration
@create_attrs %{
sig: "some sig",
kind: 42,
pubkey: "some pubkey",
created_at: ~U[2026-01-28 03:51:00Z],
content: "some content"
}
@update_attrs %{
sig: "some updated sig",
kind: 43,
pubkey: "some updated pubkey",
created_at: ~U[2026-01-29 03:51:00Z],
content: "some updated content"
}
@invalid_attrs %{sig: nil, kind: nil, pubkey: nil, created_at: nil, content: nil}
setup %{conn: conn} do
{:ok, conn: put_req_header(conn, "accept", "application/json")}
end
conn =
conn
|> put_req_header("accept", "application/json")
|> put_req_header("content-type", "application/json")
describe "index" do
test "lists all events", %{conn: conn} do
conn = get(conn, ~p"/api/events")
assert json_response(conn, 200)["data"] == []
end
{:ok, conn: conn}
end
describe "create event" do
test "renders event when data is valid", %{conn: conn} do
conn = post(conn, ~p"/api/events", event: @create_attrs)
assert %{"id" => id} = json_response(conn, 201)["data"]
conn = get(conn, ~p"/api/events/#{id}")
assert %{
"id" => ^id,
"content" => "some content",
"created_at" => "2026-01-28T03:51:00Z",
"kind" => 42,
"pubkey" => "some pubkey",
"sig" => "some sig"
} = json_response(conn, 200)["data"]
describe "POST /api/events" do
test "returns published event when request succeeds", %{conn: conn} do
pub_event = valid_pub_event_fixture()
conn = post(conn, ~p"/api/events", %{"event" => Map.from_struct(pub_event)})
assert %{"data" => data} = json_response(conn, 201)
assert data["id"] == pub_event.id
assert data["pubkey"] == pub_event.pubkey
assert data["kind"] == pub_event.kind
assert data["content"] == pub_event.content
assert data["sig"] == pub_event.sig
end
test "renders errors when data is invalid", %{conn: conn} do
conn = post(conn, ~p"/api/events", event: @invalid_attrs)
assert json_response(conn, 422)["errors"] != %{}
test "returns 409 Conflict for duplicate event", %{conn: conn} do
pub_event = valid_pub_event_fixture()
post(conn, ~p"/api/events", %{"event" => Map.from_struct(pub_event)})
conn = post(conn, ~p"/api/events", %{"event" => Map.from_struct(pub_event)})
assert json_response(conn, 409)
end
end
describe "update event" do
setup [:create_event]
test "returns 422 for event with invalid kind", %{conn: conn} do
pub_event = valid_pub_event_fixture(%{kind: -1})
conn = post(conn, ~p"/api/events", %{"event" => Map.from_struct(pub_event)})
test "renders event when data is valid", %{conn: conn, event: %Event{id: id} = event} do
conn = put(conn, ~p"/api/events/#{event}", event: @update_attrs)
assert %{"id" => ^id} = json_response(conn, 200)["data"]
assert json_response(conn, 422)
end
conn = get(conn, ~p"/api/events/#{id}")
test "returns 400 for invalid event ID", %{conn: conn} do
pub_event = invalid_id_pub_event_fixture()
conn = post(conn, ~p"/api/events", %{"event" => Map.from_struct(pub_event)})
assert %{
"id" => ^id,
"content" => "some updated content",
"created_at" => "2026-01-29T03:51:00Z",
"kind" => 43,
"pubkey" => "some updated pubkey",
"sig" => "some updated sig"
} = json_response(conn, 200)["data"]
assert json_response(conn, 400)
end
test "renders errors when data is invalid", %{conn: conn, event: event} do
conn = put(conn, ~p"/api/events/#{event}", event: @invalid_attrs)
assert json_response(conn, 422)["errors"] != %{}
test "returns 400 for invalid signature", %{conn: conn} do
pub_event = invalid_sig_pub_event_fixture()
conn = post(conn, ~p"/api/events", %{"event" => Map.from_struct(pub_event)})
assert json_response(conn, 400)
end
end
describe "delete event" do
setup [:create_event]
describe "GET /api/events/:id" do
test "returns event when found", %{conn: conn} do
event = event_fixture()
hex_id = Base.encode16(event.id, case: :lower)
conn = get(conn, ~p"/api/events/#{hex_id}")
test "deletes chosen event", %{conn: conn, event: event} do
conn = delete(conn, ~p"/api/events/#{event}")
assert response(conn, 204)
assert %{"data" => data} = json_response(conn, 200)
assert data["id"] == hex_id
end
test "returns 404 when event not found", %{conn: conn} do
nonexistent_id = String.duplicate("a", 64)
conn = get(conn, ~p"/api/events/#{nonexistent_id}")
assert_error_sent 404, fn ->
get(conn, ~p"/api/events/#{event}")
end
assert json_response(conn, 404)
end
end
defp create_event(_) do
event = event_fixture(%{})
describe "DELETE /api/events/:id" do
test "deletes event and returns 204", %{conn: conn} do
event = event_fixture()
hex_id = Base.encode16(event.id, case: :lower)
conn = delete(conn, ~p"/api/events/#{hex_id}")
%{event: event}
assert response(conn, 204)
end
test "returns 404 when event not found", %{conn: conn} do
nonexistent_id = String.duplicate("a", 64)
conn = delete(conn, ~p"/api/events/#{nonexistent_id}")
assert json_response(conn, 404)
end
end
end

283
test/gc_index_relay_web/controllers/filter_controller_test.exs

@ -0,0 +1,283 @@ @@ -0,0 +1,283 @@
defmodule GcIndexRelayWeb.FilterControllerTest do
use GcIndexRelayWeb.ConnCase
import GcIndexRelay.NostrFixtures
@moduletag :integration
setup %{conn: conn} do
conn =
conn
|> put_req_header("accept", "application/json")
|> put_req_header("content-type", "application/json")
{:ok, conn: conn}
end
describe "GET /api/events (index)" do
test "returns empty list when no events exist", %{conn: conn} do
conn = get(conn, ~p"/api/events?since=0&until=9999999999&limit=10")
assert %{"data" => []} = json_response(conn, 200)
end
test "returns events within time range", %{conn: conn} do
event_fixture(%{created_at: 1_640_000_100})
conn = get(conn, ~p"/api/events?since=0&until=9999999999&limit=10")
assert %{"data" => events} = json_response(conn, 200)
assert length(events) == 1
end
test "filters by authors", %{conn: conn} do
%{keypair1: keypair1, keypair2: keypair2} = test_keypairs()
event_fixture(%{keypair: :keypair1})
event_fixture(%{keypair: :keypair2})
conn =
get(
conn,
~p"/api/events?since=0&until=9999999999&limit=10&authors=#{keypair1.public_key_hex}"
)
assert %{"data" => events} = json_response(conn, 200)
assert length(events) == 1
assert hd(events)["pubkey"] == keypair1.public_key_hex
assert hd(events)["pubkey"] != keypair2.public_key_hex
end
test "filters by kinds", %{conn: conn} do
event_fixture(%{kind: 1})
event_fixture(%{kind: 2})
conn = get(conn, ~p"/api/events?since=0&until=9999999999&limit=10&kinds=1")
assert %{"data" => events} = json_response(conn, 200)
assert length(events) == 1
assert hd(events)["kind"] == 1
end
test "filters by ids", %{conn: conn} do
event1 = event_fixture(%{kind: 1})
_event2 = event_fixture(%{kind: 2, created_at: 1_640_000_001})
hex_id1 = Base.encode16(event1.id, case: :lower)
conn = get(conn, ~p"/api/events?since=0&until=9999999999&limit=10&ids=#{hex_id1}")
assert %{"data" => events} = json_response(conn, 200)
assert length(events) == 1
assert hd(events)["id"] == hex_id1
end
test "filters by tags", %{conn: conn} do
tagged_pub_event = valid_pub_event_fixture(%{tags: [["p", "abc123def456"]]})
{:ok, _} = GcIndexRelay.Nostr.create_event(tagged_pub_event)
event_fixture(%{kind: 2, created_at: 1_640_000_001})
conn = get(conn, ~p"/api/events?since=0&until=9999999999&limit=10&#p=abc123def456")
assert %{"data" => events} = json_response(conn, 200)
assert length(events) == 1
assert hd(events)["id"] == tagged_pub_event.id
end
test "respects limit parameter", %{conn: conn} do
event_fixture(%{kind: 1})
event_fixture(%{kind: 2, created_at: 1_640_000_001})
event_fixture(%{kind: 3, created_at: 1_640_000_002})
conn = get(conn, ~p"/api/events?since=0&until=9999999999&limit=2")
assert %{"data" => events} = json_response(conn, 200)
assert length(events) == 2
end
test "returns 400 when since is missing", %{conn: conn} do
conn = get(conn, ~p"/api/events?until=9999999999&limit=10")
assert json_response(conn, 400)
end
test "returns 400 when until is missing", %{conn: conn} do
conn = get(conn, ~p"/api/events?since=0&limit=10")
assert json_response(conn, 400)
end
test "returns 400 when limit is missing", %{conn: conn} do
conn = get(conn, ~p"/api/events?since=0&until=9999999999")
assert json_response(conn, 400)
end
test "returns 400 when limit is too large", %{conn: conn} do
conn = get(conn, ~p"/api/events?since=0&until=9999999999&limit=101")
assert json_response(conn, 400)
end
test "returns 400 for unknown query parameter", %{conn: conn} do
conn = get(conn, ~p"/api/events?since=0&until=9999999999&limit=10&unknown=foo")
assert json_response(conn, 400)
end
test "returns 400 for invalid (non-integer) limit value", %{conn: conn} do
conn = get(conn, ~p"/api/events?since=0&until=9999999999&limit=abc")
assert json_response(conn, 400)
end
test "returns 400 for invalid (non-integer) since value", %{conn: conn} do
conn = get(conn, ~p"/api/events?since=not_a_number&until=9999999999&limit=10")
assert json_response(conn, 400)
end
end
describe "POST /api/events/filter (query)" do
test "returns empty list when no events exist", %{conn: conn} do
conn = post(conn, ~p"/api/events/filter", %{"limit" => 10})
assert %{"data" => []} = json_response(conn, 200)
end
test "returns events with only limit specified", %{conn: conn} do
event_fixture()
conn = post(conn, ~p"/api/events/filter", %{"limit" => 10})
assert %{"data" => events} = json_response(conn, 200)
assert length(events) >= 1
assert length(events) <= 10
end
test "filters by authors", %{conn: conn} do
%{keypair1: keypair1, keypair2: keypair2} = test_keypairs()
event_fixture(%{keypair: :keypair1})
event_fixture(%{keypair: :keypair2})
conn =
post(conn, ~p"/api/events/filter", %{
"authors" => [keypair1.public_key_hex],
"limit" => 10
})
assert %{"data" => events} = json_response(conn, 200)
assert length(events) == 1
assert hd(events)["pubkey"] == keypair1.public_key_hex
assert hd(events)["pubkey"] != keypair2.public_key_hex
end
test "filters by kinds", %{conn: conn} do
event_fixture(%{kind: 1})
event_fixture(%{kind: 2, created_at: 1_640_000_001})
conn = post(conn, ~p"/api/events/filter", %{"kinds" => [1], "limit" => 10})
assert %{"data" => events} = json_response(conn, 200)
assert length(events) == 1
assert hd(events)["kind"] == 1
end
test "filters by ids", %{conn: conn} do
pub_event = valid_pub_event_fixture()
event_fixture(%{kind: 2, created_at: 1_640_000_001})
{:ok, _} = GcIndexRelay.Nostr.create_event(pub_event)
conn =
post(conn, ~p"/api/events/filter", %{
"ids" => [pub_event.id],
"limit" => 10
})
assert %{"data" => events} = json_response(conn, 200)
assert length(events) == 1
assert hd(events)["id"] == pub_event.id
end
test "filters by since timestamp", %{conn: conn} do
event_fixture(%{created_at: 1_639_999_999})
event_fixture(%{kind: 2, created_at: 1_640_000_100})
conn =
post(conn, ~p"/api/events/filter", %{
"since" => 1_640_000_000,
"limit" => 10
})
assert %{"data" => events} = json_response(conn, 200)
assert length(events) == 1
assert hd(events)["created_at"] == 1_640_000_100
end
test "filters by until timestamp", %{conn: conn} do
event_fixture(%{created_at: 1_639_999_999})
event_fixture(%{kind: 2, created_at: 1_640_000_100})
conn =
post(conn, ~p"/api/events/filter", %{
"until" => 1_640_000_000,
"limit" => 10
})
assert %{"data" => events} = json_response(conn, 200)
assert length(events) == 1
assert hd(events)["created_at"] == 1_639_999_999
end
test "filters by tags", %{conn: conn} do
tagged_pub_event = valid_pub_event_fixture(%{tags: [["p", "abc123def456"]]})
{:ok, _} = GcIndexRelay.Nostr.create_event(tagged_pub_event)
event_fixture(%{kind: 2, created_at: 1_640_000_001})
conn =
post(conn, ~p"/api/events/filter", %{
"#p" => ["abc123def456"],
"limit" => 10
})
assert %{"data" => events} = json_response(conn, 200)
assert length(events) == 1
assert hd(events)["id"] == tagged_pub_event.id
end
test "respects limit parameter", %{conn: conn} do
event_fixture(%{kind: 1})
event_fixture(%{kind: 2, created_at: 1_640_000_001})
event_fixture(%{kind: 3, created_at: 1_640_000_002})
conn = post(conn, ~p"/api/events/filter", %{"limit" => 2})
assert %{"data" => events} = json_response(conn, 200)
assert length(events) == 2
end
test "returns results in descending created_at order", %{conn: conn} do
event_fixture(%{kind: 1, created_at: 1_640_000_001})
event_fixture(%{kind: 2, created_at: 1_640_000_002})
event_fixture(%{kind: 3, created_at: 1_640_000_003})
conn = post(conn, ~p"/api/events/filter", %{"limit" => 10})
assert %{"data" => events} = json_response(conn, 200)
created_ats = Enum.map(events, & &1["created_at"])
assert created_ats == Enum.sort(created_ats, :desc)
end
test "returns 400 when limit is missing", %{conn: conn} do
conn = post(conn, ~p"/api/events/filter", %{"kinds" => [1]})
assert json_response(conn, 400)
end
test "returns 400 when limit is 0", %{conn: conn} do
conn = post(conn, ~p"/api/events/filter", %{"limit" => 0})
assert json_response(conn, 400)
end
test "returns 400 when limit exceeds 100", %{conn: conn} do
conn = post(conn, ~p"/api/events/filter", %{"limit" => 101})
assert json_response(conn, 400)
end
end
end
Loading…
Cancel
Save