defmodule Microwaveprop.CallsignLocationTest do use Microwaveprop.DataCase, async: false alias Microwaveprop.CallsignLocation alias Microwaveprop.CallsignLocation.Location alias Microwaveprop.Geocoder alias Microwaveprop.Qrz.Client setup do Client.reset_session() :ok end defp stub_qrz_lookup(opts \\ []) do lat = Keyword.get(opts, :lat) lon = Keyword.get(opts, :lon) lat_xml = if lat, do: "#{lat}", else: "" lon_xml = if lon, do: "#{lon}", else: "" Req.Test.expect(Client, 2, fn conn -> params = Plug.Conn.fetch_query_params(conn).query_params if Map.has_key?(params, "username") do Plug.Conn.send_resp(conn, 200, """ session123 """) else Plug.Conn.send_resp(conn, 200, """ W1AW Hiram Percy Maxim 225 Main St Newington CT 06111 United States #{lat_xml} #{lon_xml} session123 """) end end) end defp stub_geocoder do Req.Test.expect(Geocoder, fn conn -> conn |> Plug.Conn.put_resp_content_type("application/json") |> Plug.Conn.send_resp( 200, Jason.encode!(%{ "status" => "OK", "results" => [ %{ "geometry" => %{ "location" => %{"lat" => 41.714775, "lng" => -72.727260} } } ] }) ) end) end describe "lookup/1" do test "fetches from QRZ, geocodes, caches, and returns result" do stub_qrz_lookup() stub_geocoder() assert {:ok, result} = CallsignLocation.lookup("W1AW") assert result.callsign == "W1AW" assert_in_delta result.latitude, 41.714775, 0.001 assert_in_delta result.longitude, -72.727260, 0.001 assert is_binary(result.gridsquare) assert String.length(result.gridsquare) == 8 assert result.name == "Hiram Percy Maxim" assert result.address == "225 Main St, Newington, CT, 06111, United States" assert Repo.get_by(Location, callsign: "W1AW") end test "returns cached data without calling geocoder" do {:ok, _} = %Location{} |> Location.changeset(%{ callsign: "W1AW", latitude: 41.714, longitude: -72.727, gridsquare: "FN31pr58" }) |> Repo.insert() assert {:ok, result} = CallsignLocation.lookup("W1AW") assert result.callsign == "W1AW" assert_in_delta result.latitude, 41.714, 0.001 assert result.gridsquare == "FN31pr58" end test "returns error when QRZ lookup fails" do Req.Test.expect(Client, 2, fn conn -> params = Plug.Conn.fetch_query_params(conn).query_params if Map.has_key?(params, "username") do Plug.Conn.send_resp(conn, 200, """ session123 """) else Plug.Conn.send_resp(conn, 200, """ Not found: INVALID session123 """) end end) assert {:error, _} = CallsignLocation.lookup("INVALID") end test "uses QRZ lat/lon when available instead of geocoding" do stub_qrz_lookup(lat: 33.229, lon: -96.458) assert {:ok, result} = CallsignLocation.lookup("W1AW") assert result.callsign == "W1AW" assert_in_delta result.latitude, 33.229, 0.001 assert_in_delta result.longitude, -96.458, 0.001 assert is_binary(result.gridsquare) assert String.length(result.gridsquare) == 8 assert result.name == "Hiram Percy Maxim" assert result.address == "225 Main St, Newington, CT, 06111, United States" end test "falls back to geocoding when QRZ has no lat/lon" do stub_qrz_lookup() stub_geocoder() assert {:ok, result} = CallsignLocation.lookup("W1AW") assert_in_delta result.latitude, 41.714775, 0.001 assert_in_delta result.longitude, -72.727260, 0.001 end test "returns error when no address available" do Req.Test.expect(Client, 2, fn conn -> params = Plug.Conn.fetch_query_params(conn).query_params if Map.has_key?(params, "username") do Plug.Conn.send_resp(conn, 200, """ session123 """) else Plug.Conn.send_resp(conn, 200, """ W1AW session123 """) end end) assert {:error, "No address available for callsign"} = CallsignLocation.lookup("W1AW") end end end