aprs.me/test/aprsme_web/plugs/api_csrf_test.exs
Graham McIntire 403300f696
test: broaden unit & property-test coverage (61.8% → 64.7%)
Adds ~800 new tests (incl. 27 StreamData properties) across 22 modules
that previously had little or no coverage. Highlights:

- Pure utility modules (LogSanitizer, PacketFieldWhitelist,
  PacketSanitizer, DeviceParser, CoordinateUtils, BoundsUtils,
  ParamUtils, Convert, WeatherUnits) get thorough unit + property
  coverage including UTF-8 truncation boundaries, antimeridian
  longitude wrap, Haversine symmetry, and unit-conversion inverses.
- JSON view modules (CallsignJSON, ErrorJSON, ChangesetJSON) verified
  for envelope shape and error templating.
- Plugs (HealthCheck, RateLimiter, ApiCSRF) exercised for happy-path
  and halt paths.
- GenServer modules (RegexCache, CleanupScheduler, DeploymentNotifier)
  tested without touching the supervised singleton where possible.
- Drops the orphaned map_live/map_helpers_test.exs whose module name
  collided with the new live/shared/coordinate_utils_test.exs.
2026-04-23 13:32:09 -05:00

89 lines
2.5 KiB
Elixir

defmodule AprsmeWeb.Plugs.ApiCSRFTest do
use AprsmeWeb.ConnCase, async: true
alias AprsmeWeb.Plugs.ApiCSRF
test "allows JSON requests with XMLHttpRequest header", %{conn: conn} do
conn =
conn
|> init_test_session(%{})
|> put_req_header("content-type", "application/json")
|> put_req_header("x-requested-with", "XMLHttpRequest")
|> ApiCSRF.call([])
refute conn.halted
end
test "rejects JSON requests with arbitrary bearer token", %{conn: conn} do
conn =
conn
|> init_test_session(%{})
|> put_req_header("content-type", "application/json")
|> put_req_header("authorization", "Bearer definitely-not-valid")
|> ApiCSRF.call([])
assert conn.halted
assert conn.status == 403
assert Jason.decode!(conn.resp_body)["error"] == "CSRF protection failed"
end
test "allows non-JSON requests without CSRF headers", %{conn: conn} do
conn =
conn
|> init_test_session(%{})
|> put_req_header("content-type", "text/plain")
|> ApiCSRF.call([])
refute conn.halted
end
test "allows JSON with utf-8 content type and XHR header", %{conn: conn} do
conn =
conn
|> init_test_session(%{})
|> put_req_header("content-type", "application/json; charset=utf-8")
|> put_req_header("x-requested-with", "XMLHttpRequest")
|> ApiCSRF.call([])
refute conn.halted
end
test "rejects JSON request with empty csrf-token header", %{conn: conn} do
conn =
conn
|> init_test_session(%{})
|> put_req_header("content-type", "application/json")
|> put_req_header("x-csrf-token", "")
|> ApiCSRF.call([])
assert conn.halted
assert conn.status == 403
end
test "rejects JSON request with token but no session token", %{conn: conn} do
conn =
conn
|> init_test_session(%{})
|> put_req_header("content-type", "application/json")
|> put_req_header("x-csrf-token", "any-token")
|> ApiCSRF.call([])
assert conn.halted
end
test "rejects JSON request with mismatched csrf token", %{conn: conn} do
conn =
conn
|> init_test_session(%{"_csrf_token" => "a-session-token"})
|> put_req_header("content-type", "application/json")
|> put_req_header("x-csrf-token", "wrong-token")
|> ApiCSRF.call([])
assert conn.halted
end
test "init/1 returns opts unchanged" do
assert ApiCSRF.init([]) == []
assert ApiCSRF.init(foo: :bar) == [foo: :bar]
end
end