Use CF-IPLatitude/CF-IPLongitude headers instead of making HTTP calls to ip-api.com on every page load. Eliminates ~500ms latency, external API dependency, and flaky tests. Also disable test server to prevent port conflicts during development.
127 lines
3.7 KiB
Elixir
127 lines
3.7 KiB
Elixir
defmodule AprsmeWeb.Plugs.IPGeolocationTest do
|
|
use AprsmeWeb.ConnCase
|
|
|
|
alias AprsmeWeb.Plugs.IPGeolocation
|
|
|
|
setup %{conn: conn} do
|
|
conn =
|
|
conn
|
|
|> Plug.Session.call(Plug.Session.init(store: :cookie, key: "_aprs_key", signing_salt: "test"))
|
|
|> fetch_session()
|
|
|
|
{:ok, conn: conn}
|
|
end
|
|
|
|
describe "call/2 with Cloudflare headers" do
|
|
test "sets session from CF-IPLatitude and CF-IPLongitude headers on root GET", %{conn: conn} do
|
|
conn =
|
|
conn
|
|
|> put_req_header("cf-iplatitude", "37.7749")
|
|
|> put_req_header("cf-iplongitude", "-122.4194")
|
|
|> IPGeolocation.call([])
|
|
|
|
geo = get_session(conn, :ip_geolocation)
|
|
assert geo == %{"lat" => 37.7749, "lng" => -122.4194}
|
|
end
|
|
|
|
test "skips when CF headers are missing", %{conn: conn} do
|
|
conn = IPGeolocation.call(conn, [])
|
|
|
|
assert get_session(conn, :ip_geolocation) == nil
|
|
end
|
|
|
|
test "skips when only latitude header is present", %{conn: conn} do
|
|
conn =
|
|
conn
|
|
|> put_req_header("cf-iplatitude", "37.7749")
|
|
|> IPGeolocation.call([])
|
|
|
|
assert get_session(conn, :ip_geolocation) == nil
|
|
end
|
|
|
|
test "skips when only longitude header is present", %{conn: conn} do
|
|
conn =
|
|
conn
|
|
|> put_req_header("cf-iplongitude", "-122.4194")
|
|
|> IPGeolocation.call([])
|
|
|
|
assert get_session(conn, :ip_geolocation) == nil
|
|
end
|
|
|
|
test "skips non-root paths", %{conn: conn} do
|
|
conn =
|
|
conn
|
|
|> Map.put(:request_path, "/about")
|
|
|> put_req_header("cf-iplatitude", "37.7749")
|
|
|> put_req_header("cf-iplongitude", "-122.4194")
|
|
|> IPGeolocation.call([])
|
|
|
|
assert get_session(conn, :ip_geolocation) == nil
|
|
end
|
|
|
|
test "skips non-GET requests", %{conn: conn} do
|
|
conn =
|
|
conn
|
|
|> Map.put(:method, "POST")
|
|
|> put_req_header("cf-iplatitude", "37.7749")
|
|
|> put_req_header("cf-iplongitude", "-122.4194")
|
|
|> IPGeolocation.call([])
|
|
|
|
assert get_session(conn, :ip_geolocation) == nil
|
|
end
|
|
|
|
test "uses cached session data without re-reading headers", %{conn: conn} do
|
|
geo_data = %{"lat" => 40.7128, "lng" => -74.006}
|
|
|
|
conn =
|
|
conn
|
|
|> put_session(:ip_geolocation, geo_data)
|
|
|> put_req_header("cf-iplatitude", "37.7749")
|
|
|> put_req_header("cf-iplongitude", "-122.4194")
|
|
|> IPGeolocation.call([])
|
|
|
|
assert get_session(conn, :ip_geolocation) == geo_data
|
|
end
|
|
|
|
test "rejects latitude out of range", %{conn: conn} do
|
|
conn =
|
|
conn
|
|
|> put_req_header("cf-iplatitude", "91.0")
|
|
|> put_req_header("cf-iplongitude", "-122.4194")
|
|
|> IPGeolocation.call([])
|
|
|
|
assert get_session(conn, :ip_geolocation) == nil
|
|
end
|
|
|
|
test "rejects longitude out of range", %{conn: conn} do
|
|
conn =
|
|
conn
|
|
|> put_req_header("cf-iplatitude", "37.7749")
|
|
|> put_req_header("cf-iplongitude", "181.0")
|
|
|> IPGeolocation.call([])
|
|
|
|
assert get_session(conn, :ip_geolocation) == nil
|
|
end
|
|
|
|
test "rejects non-numeric header values", %{conn: conn} do
|
|
conn =
|
|
conn
|
|
|> put_req_header("cf-iplatitude", "not_a_number")
|
|
|> put_req_header("cf-iplongitude", "-122.4194")
|
|
|> IPGeolocation.call([])
|
|
|
|
assert get_session(conn, :ip_geolocation) == nil
|
|
end
|
|
|
|
test "handles boundary coordinate values", %{conn: conn} do
|
|
conn =
|
|
conn
|
|
|> put_req_header("cf-iplatitude", "-90.0")
|
|
|> put_req_header("cf-iplongitude", "180.0")
|
|
|> IPGeolocation.call([])
|
|
|
|
geo = get_session(conn, :ip_geolocation)
|
|
assert geo == %{"lat" => -90.0, "lng" => 180.0}
|
|
end
|
|
end
|
|
end
|