73d43e5fdc
logic_geo проксирует OpenCage (suggest/geocode/reverse): env OPENCAGE_API_KEY, OPENCAGE_URL, OPENCAGE_TIMEOUT_MS, OPENCAGE_COUNTRYCODE, OPENCAGE_THROTTLE_RPS (1 rps под free-тариф, 0 - выключить). HTTP 402/403/429 апстрима -> 503 geo_unavailable; source=opencage. Сервис photon и volume photon-data удалены из swarm compose; eunit-фикстуры под формат OpenCage. Refs EventHub/EventHubBack#77
92 lines
3.3 KiB
Erlang
92 lines
3.3 KiB
Erlang
-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).
|