-module(logic_geo_tests). -include_lib("eunit/include/eunit.hrl"). setup() -> catch ets:delete(eventhub_geo_cache), catch ets:delete(eventhub_geo_rl), catch ets:delete(eventhub_geo_upstream), logic_geo:ensure(), application:unset_env(eventhub, geo_http_get), os:putenv("OPENCAGE_API_KEY", "test-key"), os:putenv("OPENCAGE_URL", "http://opencage.test/geocode/v1/json"), os:putenv("OPENCAGE_THROTTLE_RPS", "0"), ok. cleanup(_) -> application:unset_env(eventhub, geo_http_get), os:unsetenv("OPENCAGE_API_KEY"), os:unsetenv("OPENCAGE_URL"), os:unsetenv("OPENCAGE_THROTTLE_RPS"), catch ets:delete(eventhub_geo_cache), catch ets:delete(eventhub_geo_rl), catch ets:delete(eventhub_geo_upstream), ok. logic_geo_test_() -> {foreach, fun setup/0, fun cleanup/1, [ {"Suggest too short", fun test_suggest_short/0}, {"Suggest parses opencage results", fun test_suggest_ok/0}, {"Geocode empty results is not_found", fun test_geocode_not_found/0}, {"Unavailable without opencage key", fun test_unavailable/0}, {"Upstream quota (402) is unavailable", fun test_quota_exceeded/0}, {"Reverse fallback address", fun test_reverse_empty/0}, {"Format address from properties", fun test_format_address/0} ]}. sample_opencage() -> <<"{ \"status\": {\"code\": 200, \"message\": \"OK\"}, \"results\": [{ \"formatted\": \"Red Square, Moscow, Russia\", \"geometry\": {\"lat\": 55.75, \"lng\": 37.62}, \"components\": {\"city\": \"Moscow\", \"country\": \"Russia\"} }] }">>. test_suggest_short() -> ?assertEqual({error, invalid_query}, logic_geo:suggest(<<"ab">>, <<"ru">>, <<"ip">>)). test_suggest_ok() -> application:set_env(eventhub, geo_http_get, fun(_) -> {ok, sample_opencage()} end), {ok, Hits} = logic_geo:suggest(<<"красная площадь">>, <<"ru">>, <<"ip1">>), ?assertMatch([#{<<"lat">> := 55.75, <<"lon">> := 37.62}], Hits), [#{<<"address">> := Addr}] = Hits, ?assertEqual(<<"Red Square, Moscow, Russia">>, Addr). test_geocode_not_found() -> application:set_env(eventhub, geo_http_get, fun(_) -> {ok, <<"{\"status\":{\"code\":200},\"results\":[]}">>} end), ?assertEqual({error, not_found}, logic_geo:geocode(<<"nowherexyz">>, <<"ru">>, <<"u1">>)). test_unavailable() -> os:unsetenv("OPENCAGE_API_KEY"), application:unset_env(eventhub, geo_http_get), ?assertEqual({error, unavailable}, logic_geo:suggest(<<"москва центр">>, <<"ru">>, <<"ip2">>)). test_quota_exceeded() -> application:set_env(eventhub, geo_http_get, fun(_) -> {error, {http_status, 402}} end), ?assertEqual({error, unavailable}, logic_geo:suggest(<<"москва центр">>, <<"ru">>, <<"ip3">>)). test_reverse_empty() -> application:set_env(eventhub, geo_http_get, fun(_) -> {ok, <<"{\"status\":{\"code\":200},\"results\":[]}">>} end), {ok, Hit} = logic_geo:reverse(55.75, 37.62, <<"ru">>, <<"u2">>), ?assertEqual(<<"opencage">>, maps:get(<<"source">>, Hit)), ?assertEqual(55.75, maps:get(<<"lat">>, Hit)). test_format_address() -> Addr = logic_geo:format_address(#{ <<"housenumber">> => <<"1">>, <<"street">> => <<"Tverskaya">>, <<"city">> => <<"Moscow">>, <<"country">> => <<"Russia">> }), ?assertEqual(<<"1 Tverskaya, Moscow, Russia">>, Addr).