towerops/test/towerops/geoip_test.exs
2026-02-03 11:16:43 -06:00

215 lines
5.7 KiB
Elixir

defmodule Towerops.GeoIPTest do
use Towerops.DataCase, async: true
alias Towerops.GeoIP
alias Towerops.GeoIP.Block
alias Towerops.GeoIP.Location
describe "lookup/1" do
test "returns country code for valid IP with location data" do
# Insert test location
location = insert_location(%{geoname_id: 5_375_480, country_code: "US"})
# Insert test block for IP 8.8.8.8 (134744072)
insert_block(%{
geoname_id: location.geoname_id,
start_ip_int: 134_744_072,
end_ip_int: 134_744_072
})
assert GeoIP.lookup("8.8.8.8") == "US"
end
test "returns nil for valid IP with no location data" do
assert GeoIP.lookup("192.168.1.1") == nil
end
test "returns nil for invalid IP address" do
assert GeoIP.lookup("invalid") == nil
end
test "returns nil for empty string" do
assert GeoIP.lookup("") == nil
end
test "returns nil for IP with too many octets" do
assert GeoIP.lookup("1.2.3.4.5") == nil
end
test "returns nil for IP with invalid octets" do
assert GeoIP.lookup("999.999.999.999") == nil
end
end
describe "lookup_full/1" do
test "returns full location data for valid IP" do
# Insert test location with full data
location =
insert_location(%{
geoname_id: 5_375_480,
country_code: "US",
country_name: "United States",
city_name: "Mountain View",
subdivision_1_name: "California",
subdivision_2_name: nil,
latitude: 37.386,
longitude: -122.0838
})
# Insert test block for IP 8.8.8.8
insert_block(%{
geoname_id: location.geoname_id,
start_ip_int: 134_744_072,
end_ip_int: 134_744_072
})
result = GeoIP.lookup_full("8.8.8.8")
assert result.country_code == "US"
assert result.country_name == "United States"
assert result.city_name == "Mountain View"
assert result.subdivision_1_name == "California"
assert result.subdivision_2_name == nil
assert result.latitude == 37.386
assert result.longitude == -122.0838
end
test "returns location data with minimal fields" do
location = insert_location(%{geoname_id: 1234, country_code: "CA"})
insert_block(%{
geoname_id: location.geoname_id,
start_ip_int: 100,
end_ip_int: 200
})
result = GeoIP.lookup_full("0.0.0.100")
assert result.country_code == "CA"
assert result.country_name == nil
assert result.city_name == nil
end
test "returns nil for IP not in any block" do
# Create location and block, but query different IP
location = insert_location(%{geoname_id: 5678, country_code: "US"})
insert_block(%{
geoname_id: location.geoname_id,
start_ip_int: 1000,
end_ip_int: 2000
})
assert GeoIP.lookup_full("192.168.1.1") == nil
end
test "returns nil for invalid IP string" do
assert GeoIP.lookup_full("not-an-ip") == nil
end
test "returns nil for empty string" do
assert GeoIP.lookup_full("") == nil
end
test "handles IP at start of range" do
location = insert_location(%{geoname_id: 9999, country_code: "FR"})
insert_block(%{
geoname_id: location.geoname_id,
start_ip_int: 167_772_160,
end_ip_int: 167_772_170
})
# 10.0.0.0 = 167772160
result = GeoIP.lookup_full("10.0.0.0")
assert result.country_code == "FR"
end
test "handles IP at end of range" do
location = insert_location(%{geoname_id: 8888, country_code: "DE"})
insert_block(%{
geoname_id: location.geoname_id,
start_ip_int: 167_772_160,
end_ip_int: 167_772_170
})
# 10.0.0.10 = 167772170
result = GeoIP.lookup_full("10.0.0.10")
assert result.country_code == "DE"
end
test "handles IP in middle of range" do
location = insert_location(%{geoname_id: 7777, country_code: "GB"})
insert_block(%{
geoname_id: location.geoname_id,
start_ip_int: 167_772_160,
end_ip_int: 167_772_170
})
# 10.0.0.5 = 167772165
result = GeoIP.lookup_full("10.0.0.5")
assert result.country_code == "GB"
end
test "returns first matching block when multiple blocks overlap" do
location1 = insert_location(%{geoname_id: 1111, country_code: "US"})
location2 = insert_location(%{geoname_id: 2222, country_code: "CA"})
insert_block(%{
network: "0.0.0.100/24",
geoname_id: location1.geoname_id,
start_ip_int: 100,
end_ip_int: 200
})
insert_block(%{
network: "0.0.0.50/24",
geoname_id: location2.geoname_id,
start_ip_int: 50,
end_ip_int: 150
})
# Query returns first match due to limit: 1
result = GeoIP.lookup_full("0.0.0.150")
assert result.country_code in ["US", "CA"]
end
end
# Helper functions to insert test data
defp insert_location(attrs) do
default_attrs = %{
geoname_id: System.unique_integer([:positive]),
country_code: "US",
country_name: nil,
city_name: nil,
subdivision_1_name: nil,
subdivision_2_name: nil,
latitude: nil,
longitude: nil
}
attrs = Map.merge(default_attrs, Map.new(attrs))
%Location{}
|> Location.changeset(attrs)
|> Repo.insert!()
end
defp insert_block(attrs) do
default_attrs = %{
network: "0.0.0.0/32",
start_ip_int: 0,
end_ip_int: 0,
geoname_id: nil,
registered_country_geoname_id: nil
}
attrs = Map.merge(default_attrs, Map.new(attrs))
%Block{}
|> Block.changeset(attrs)
|> Repo.insert!()
end
end