diff --git a/README.md b/README.md index 3356f44d2c025682dd7386350b25840e0baecabb..67fb58f7b952c7fe6d14cdd114aff8921731c114 100644 --- a/README.md +++ b/README.md @@ -753,7 +753,31 @@ This uses the PostcodeAnywhere UK Geocode service, this will geocode any string ### IP Address Services -#### FreeGeoIP (`:freegeoip`) +#### Ipstack (`:ipstack`) + +* **API key**: required - see https://ipstack.com/product +* **Quota**: 10,000 requests per month (with free API Key, 50,000/day and up for paid plans) +* **Region**: world +* **SSL support**: yes ( only with paid plan ) +* **Languages**: English, German, Spanish, French, Japanese, Portugues (Brazil), Russian, Chinese +* **Documentation**: https://ipstack.com/documentation +* **Terms of Service**: ? +* **Limitations**: ? +* **Notes**: To use Ipstack set `Geocoder.configure(:ip_lookup => :ipstack, :api_key => "your_ipstack_api_key")`. Support for the ipstack JSONP, batch lookup, and requester lookup features has not been implemented yet. This lookup does support the params shown below: +* ```ruby + # Search Options Examples + + Geocoder.search('0.0.0.0', { + params: { + hostname: '1', + security: '1', + fields: 'country_code,location.capital,...', # see ipstack documentation + language: 'en' + } + }) + ``` + +#### FreeGeoIP (`:freegeoip`) - DEPRECATED ( [ more information](https://github.com/alexreisner/geocoder/wiki/Freegeoip-Discontinuation) ) * **API key**: none * **Quota**: 15,000 requests per hour. After reaching the hourly quota, all of your requests will result in HTTP 403 (Forbidden) until it clears up on the next roll over. diff --git a/geocoder.gemspec b/geocoder.gemspec index 8bb7462e6e41014a32df81429e767f08200da4ef..7488885ca218f0c8fa2593e9effce6e37d4b4bb4 100644 --- a/geocoder.gemspec +++ b/geocoder.gemspec @@ -19,6 +19,17 @@ Gem::Specification.new do |s| s.executables = ["geocode"] s.license = 'MIT' + s.post_install_message = %q{ + +IMPORTANT: Geocoder has recently switched its default ip lookup. If you have specified :freegeoip +in your configuration, you must choose a different ip lookup by July 1, 2018, which is when +the Freegeoip API will be discontinued. + +For more information visit: +https://github.com/alexreisner/geocoder/wiki/Freegeoip-Discontinuation + +} + s.metadata = { 'source_code_uri' => 'https://github.com/alexreisner/geocoder', 'changelog_uri' => 'https://github.com/alexreisner/geocoder/blob/master/CHANGELOG.md' diff --git a/lib/generators/geocoder/config/templates/initializer.rb b/lib/generators/geocoder/config/templates/initializer.rb index 41d682f2f24ac39815deaeffcd569576a5f51fed..88c64890cdfb956d497cae86e6b1f475f6c06827 100644 --- a/lib/generators/geocoder/config/templates/initializer.rb +++ b/lib/generators/geocoder/config/templates/initializer.rb @@ -2,7 +2,7 @@ Geocoder.configure( # Geocoding options # timeout: 3, # geocoding service timeout (secs) # lookup: :google, # name of geocoding service (symbol) - # ip_lookup: :freegeoip, # name of IP address geocoding service (symbol) + # ip_lookup: :ipinfo_io, # name of IP address geocoding service (symbol) # language: :en, # ISO-639 language code # use_https: false, # use HTTPS for lookup requests? (if supported) # http_proxy: nil, # HTTP proxy server (user:pass@host:port) diff --git a/lib/geocoder/lookup.rb b/lib/geocoder/lookup.rb index b756f768f40e9fe94d6b80fa56505bf688a72c41..d439c7d231ef20d5c2044b6171c8c6a4ed5cef7f 100644 --- a/lib/geocoder/lookup.rb +++ b/lib/geocoder/lookup.rb @@ -72,7 +72,8 @@ module Geocoder :ipinfo_io, :ipapi_com, :ipdata_co, - :db_ip_com + :db_ip_com, + :ipstack, ] end diff --git a/lib/geocoder/lookups/ipstack.rb b/lib/geocoder/lookups/ipstack.rb new file mode 100644 index 0000000000000000000000000000000000000000..2d8d3c328c0cff237269495bc4dd0ef3d578d232 --- /dev/null +++ b/lib/geocoder/lookups/ipstack.rb @@ -0,0 +1,64 @@ +require 'geocoder/lookups/base' +require 'geocoder/results/ipstack' + +module Geocoder::Lookup + class Ipstack < Base + + ERROR_CODES = { + 404 => Geocoder::InvalidRequest, + 101 => Geocoder::InvalidApiKey, + 102 => Geocoder::Error, + 103 => Geocoder::InvalidRequest, + 104 => Geocoder::OverQueryLimitError, + 105 => Geocoder::RequestDenied, + 301 => Geocoder::InvalidRequest, + 302 => Geocoder::InvalidRequest, + 303 => Geocoder::RequestDenied, + } + ERROR_CODES.default = Geocoder::Error + + def name + "Ipstack" + end + + def query_url(query) + extra_params = url_query_string(query) + url = "#{protocol}://#{host}/#{query.sanitized_text}?access_key=#{api_key}" + url << "&#{extra_params}" unless extra_params.empty? + url + end + + private + + def results(query) + # don't look up a loopback address, just return the stored result + return [reserved_result(query.text)] if query.loopback_ip_address? + + return [] unless doc = fetch_data(query) + + if error = doc['error'] + code = error['code'] + msg = error['info'] + raise_error(ERROR_CODES[code], msg ) || Geocoder.log(:warn, "Ipstack Geocoding API error: #{msg}") + return [] + end + [doc] + end + + def reserved_result(ip) + { + "ip" => ip, + "country_name" => "Reserved", + "country_code" => "RD" + } + end + + def host + configuration[:host] || "api.ipstack.com" + end + + def api_key + configuration.api_key + end + end +end diff --git a/lib/geocoder/results/ipstack.rb b/lib/geocoder/results/ipstack.rb new file mode 100644 index 0000000000000000000000000000000000000000..af1099fb8cfcc47fe1e47adebff111af8f0f7e34 --- /dev/null +++ b/lib/geocoder/results/ipstack.rb @@ -0,0 +1,60 @@ +require 'geocoder/results/base' + +module Geocoder::Result + class Ipstack < Base + + def address(format = :full) + s = region_code.empty? ? "" : ", #{region_code}" + "#{city}#{s} #{zip}, #{country_name}".sub(/^[ ,]*/, "") + end + + def state + @data['region_name'] + end + + def state_code + @data['region_code'] + end + + def country + @data['country_name'] + end + + def postal_code + @data['zip'] || @data['zipcode'] || @data['zip_code'] + end + + def self.response_attributes + [ + ['ip', ''], + ['hostname', ''], + ['continent_code', ''], + ['continent_name', ''], + ['country_code', ''], + ['country_name', ''], + ['region_code', ''], + ['region_name', ''], + ['city', ''], + ['zip', ''], + ['latitude', 0], + ['longitude', 0], + ['location', {}], + ['time_zone', {}], + ['currency', {}], + ['connection', {}], + ['security', {}], + ] + end + + response_attributes.each do |attr, default| + define_method attr do + @data[attr] || default + end + end + + def metro_code + Geocoder.log(:warn, "Ipstack does not implement `metro_code` in api results. Please discontinue use.") + 0 # no longer implemented by ipstack + end + end +end diff --git a/test/fixtures/freegeoip_74_200_247_59 b/test/fixtures/freegeoip_74_200_247_59 index e187b40bdea9734e7d9147f37867dd627f557960..defc4ace5a4d41cfad998228576c6ce00eeec117 100644 --- a/test/fixtures/freegeoip_74_200_247_59 +++ b/test/fixtures/freegeoip_74_200_247_59 @@ -4,9 +4,9 @@ "region_name": "Texas", "metro_code": "623", "zipcode": "75093", - "longitude": "-96.8134", + "longitude": -96.8134, "country_name": "United States", "country_code": "US", "ip": "74.200.247.59", - "latitude": "33.0347" + "latitude": 33.0347 } diff --git a/test/fixtures/ipstack_134_201_250_155 b/test/fixtures/ipstack_134_201_250_155 new file mode 100644 index 0000000000000000000000000000000000000000..cff0568d2616887b9e19711c6f497f74c1c88349 --- /dev/null +++ b/test/fixtures/ipstack_134_201_250_155 @@ -0,0 +1,49 @@ +{ + "ip": "134.201.250.155", + "hostname": "134.201.250.155", + "type": "ipv4", + "continent_code": "NA", + "continent_name": "North America", + "country_code": "US", + "country_name": "United States", + "region_code": "CA", + "region_name": "California", + "city": "Los Angeles", + "zip": "90013", + "latitude": 34.0453, + "longitude": -118.2413, + "location": { + "geoname_id": 5368361, + "capital": "Washington D.C.", + "languages": [ + { + "code": "en", + "name": "English", + "native": "English" + } + ], + "country_flag": "https://assets.ipstack.com/images/assets/flags_svg/us.svg", + "country_flag_emoji": "🇺🇸", + "country_flag_emoji_unicode": "U+1F1FA U+1F1F8", + "calling_code": "1", + "is_eu": false + }, + "time_zone": { + "id": "America/Los_Angeles", + "current_time": "2018-03-29T07:35:08-07:00", + "gmt_offset": -25200, + "code": "PDT", + "is_daylight_saving": true + }, + "currency": { + "code": "USD", + "name": "US Dollar", + "plural": "US dollars", + "symbol": "$", + "symbol_native": "$" + }, + "connection": { + "asn": 25876, + "isp": "Los Angeles Department of Water & Power" + } +} diff --git a/test/fixtures/ipstack_access_restricted b/test/fixtures/ipstack_access_restricted new file mode 100644 index 0000000000000000000000000000000000000000..652e1cb9cc71e7e4c5532d7977bd80028c945101 --- /dev/null +++ b/test/fixtures/ipstack_access_restricted @@ -0,0 +1,8 @@ +{ + "success": false, + "error": { + "code": 105, + "type": "function_access_restricted", + "info": "The current subscription plan does not support this API endpoint." + } +} \ No newline at end of file diff --git a/test/fixtures/ipstack_batch_not_supported b/test/fixtures/ipstack_batch_not_supported new file mode 100644 index 0000000000000000000000000000000000000000..b60a245f39265888925cd705901541441a68113c --- /dev/null +++ b/test/fixtures/ipstack_batch_not_supported @@ -0,0 +1,8 @@ +{ + "success": false, + "error": { + "code": 303, + "type": "batch_not_supported_on_plan", + "info": "The Bulk Lookup Endpoint is not supported on the current subscription plan" + } +} \ No newline at end of file diff --git a/test/fixtures/ipstack_inactive_user b/test/fixtures/ipstack_inactive_user new file mode 100644 index 0000000000000000000000000000000000000000..1ead8fa9e34108b0136fcb89e143e91768219b06 --- /dev/null +++ b/test/fixtures/ipstack_inactive_user @@ -0,0 +1,8 @@ +{ + "success": false, + "error": { + "code": 102, + "type": "inactive_user", + "info": "The current user account is not active. User will be prompted to get in touch with Customer Support." + } +} \ No newline at end of file diff --git a/test/fixtures/ipstack_invalid_access_key b/test/fixtures/ipstack_invalid_access_key new file mode 100644 index 0000000000000000000000000000000000000000..f119c8521205fde48a1368554eaa4745f7902115 --- /dev/null +++ b/test/fixtures/ipstack_invalid_access_key @@ -0,0 +1,8 @@ +{ + "success": false, + "error": { + "code": 101, + "type": "invalid_access_key", + "info": "No API Key was specified or an invalid API Key was specified." + } +} \ No newline at end of file diff --git a/test/fixtures/ipstack_invalid_api_function b/test/fixtures/ipstack_invalid_api_function new file mode 100644 index 0000000000000000000000000000000000000000..e58000501006ee321716f20a2cb96fc85ac251e6 --- /dev/null +++ b/test/fixtures/ipstack_invalid_api_function @@ -0,0 +1,8 @@ +{ + "success": false, + "error": { + "code": 103, + "type": "invalid_api_function", + "info": "The requested API endpoint does not exist." + } +} \ No newline at end of file diff --git a/test/fixtures/ipstack_invalid_fields b/test/fixtures/ipstack_invalid_fields new file mode 100644 index 0000000000000000000000000000000000000000..105f54119b44fe8109f3e06b5ac05077de696056 --- /dev/null +++ b/test/fixtures/ipstack_invalid_fields @@ -0,0 +1,8 @@ +{ + "success": false, + "error": { + "code": 301, + "type": "invalid_fields", + "info": "One or more invalid fields were specified using the fields parameter." + } +} \ No newline at end of file diff --git a/test/fixtures/ipstack_missing_access_key b/test/fixtures/ipstack_missing_access_key new file mode 100644 index 0000000000000000000000000000000000000000..358e5c8e0c4c6cf63ba5d35b393f3e8c95a3402b --- /dev/null +++ b/test/fixtures/ipstack_missing_access_key @@ -0,0 +1,8 @@ +{ + "success": false, + "error": { + "code": 101, + "type": "missing_access_key", + "info": "No API Key was specified." + } +} \ No newline at end of file diff --git a/test/fixtures/ipstack_no_results b/test/fixtures/ipstack_no_results new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/fixtures/ipstack_not_found b/test/fixtures/ipstack_not_found new file mode 100644 index 0000000000000000000000000000000000000000..f644fa30af0867af86df35cbb909e7543b233de3 --- /dev/null +++ b/test/fixtures/ipstack_not_found @@ -0,0 +1,8 @@ +{ + "success": false, + "error": { + "code": 404, + "type": "404_not_found", + "info": "The requested resource does not exist." + } +} \ No newline at end of file diff --git a/test/fixtures/ipstack_protocol_access_restricted b/test/fixtures/ipstack_protocol_access_restricted new file mode 100644 index 0000000000000000000000000000000000000000..7c915afaf5ef5f3386bac04d488a1fd919a65b41 --- /dev/null +++ b/test/fixtures/ipstack_protocol_access_restricted @@ -0,0 +1,8 @@ +{ + "success": false, + "error": { + "code": 105, + "type": "https_access_restricted", + "info": "The user's current subscription plan does not support HTTPS Encryption." + } +} \ No newline at end of file diff --git a/test/fixtures/ipstack_too_many_ips b/test/fixtures/ipstack_too_many_ips new file mode 100644 index 0000000000000000000000000000000000000000..b85c5e5d1cc355f47e7ca41d90ed8e3d440ac022 --- /dev/null +++ b/test/fixtures/ipstack_too_many_ips @@ -0,0 +1,8 @@ +{ + "success": false, + "error": { + "code": 302, + "type": "too_many_ips", + "info": "Too many IPs have been specified for the Bulk Lookup Endpoint. (max. 50)" + } +} \ No newline at end of file diff --git a/test/fixtures/ipstack_usage_limit b/test/fixtures/ipstack_usage_limit new file mode 100644 index 0000000000000000000000000000000000000000..d3753f02a0acf2a6cc4c3e5142faff66b3cff1ee --- /dev/null +++ b/test/fixtures/ipstack_usage_limit @@ -0,0 +1,8 @@ +{ + "success": false, + "error": { + "code": 104, + "type": "usage_limit_reached", + "info": "The maximum allowed amount of monthly API requests has been reached." + } +} \ No newline at end of file diff --git a/test/test_helper.rb b/test/test_helper.rb index 4857dfed71f30051ee1e0abd24a840b8257576bb..5698e49ef6841651f924dde2dcc11e2b7bba14ef 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -217,6 +217,14 @@ module Geocoder end end + require 'geocoder/lookups/ipstack' + class Ipstack + private + def default_fixture_filename + "ipstack_134_201_250_155" + end + end + require 'geocoder/lookups/geoip2' class Geoip2 private diff --git a/test/unit/lookup_test.rb b/test/unit/lookup_test.rb index 7f21877f77b4359c3fe6b8c37a70ac5e123214c9..2afa95474ed44afe0aec22653f5742afc444b4be 100644 --- a/test/unit/lookup_test.rb +++ b/test/unit/lookup_test.rb @@ -24,7 +24,7 @@ class LookupTest < GeocoderTestCase def test_query_url_contains_values_in_params_hash Geocoder::Lookup.all_services_except_test.each do |l| - next if [:freegeoip, :maxmind_local, :telize, :pointpin, :geoip2, :maxmind_geoip2, :mapbox, :ipdata_co, :ipinfo_io, :ipapi_com].include? l # does not use query string + next if [:freegeoip, :maxmind_local, :telize, :pointpin, :geoip2, :maxmind_geoip2, :mapbox, :ipdata_co, :ipinfo_io, :ipapi_com, :ipstack].include? l # does not use query string set_api_key!(l) url = Geocoder::Lookup.get(l).query_url(Geocoder::Query.new( "test", :params => {:one_in_the_hand => "two in the bush"} diff --git a/test/unit/lookups/ipstack_test.rb b/test/unit/lookups/ipstack_test.rb new file mode 100644 index 0000000000000000000000000000000000000000..fd2a17682273c7c6e04353caf55c7e7463aed2bf --- /dev/null +++ b/test/unit/lookups/ipstack_test.rb @@ -0,0 +1,285 @@ +# encoding: utf-8 +require 'test_helper' + +class SpyLogger + def initialize + @log = [] + end + + def logged?(msg) + @log.include?(msg) + end + + def add(level, msg) + @log << msg + end +end + +class IpstackTest < GeocoderTestCase + + def setup + @logger = SpyLogger.new + Geocoder::Configuration.instance.data.clear + Geocoder::Configuration.set_defaults + Geocoder.configure( + :api_key => '123', + :ip_lookup => :ipstack, + :always_raise => :all, + :logger => @logger + ) + end + + def test_result_on_ip_address_search + result = Geocoder.search("134.201.250.155").first + assert result.is_a?(Geocoder::Result::Ipstack) + end + + def test_result_components + result = Geocoder.search("134.201.250.155").first + assert_equal "Los Angeles, CA 90013, United States", result.address + end + + def test_all_top_level_api_fields + result = Geocoder.search("134.201.250.155").first + assert_equal "134.201.250.155", result.ip + assert_equal "134.201.250.155", result.hostname + assert_equal "NA", result.continent_code + assert_equal "North America", result.continent_name + assert_equal "US", result.country_code + assert_equal "United States", result.country_name + assert_equal "CA", result.region_code + assert_equal "California", result.region_name + assert_equal "Los Angeles", result.city + assert_equal "90013", result.zip + assert_equal 34.0453, result.latitude + assert_equal (-118.2413), result.longitude + end + + def test_nested_api_fields + result = Geocoder.search("134.201.250.155").first + + assert result.location.is_a?(Hash) + assert_equal 5368361, result.location['geoname_id'] + + assert result.time_zone.is_a?(Hash) + assert_equal "America/Los_Angeles", result.time_zone['id'] + + assert result.currency.is_a?(Hash) + assert_equal "USD", result.currency['code'] + + assert result.connection.is_a?(Hash) + assert_equal 25876, result.connection['asn'] + + assert result.security.is_a?(Hash) + end + + def test_required_base_fields + result = Geocoder.search("134.201.250.155").first + assert_equal "California", result.state + assert_equal "CA", result.state_code + assert_equal "United States", result.country + assert_equal "90013", result.postal_code + assert_equal [34.0453, -118.2413], result.coordinates + end + + def test_logs_deprecation_of_metro_code_field + result = Geocoder.search("134.201.250.155").first + result.metro_code + + assert @logger.logged?("Ipstack does not implement `metro_code` in api results. Please discontinue use.") + end + + def test_localhost_loopback + result = Geocoder.search("127.0.0.1").first + assert_equal "127.0.0.1", result.ip + assert_equal "RD", result.country_code + assert_equal "Reserved", result.country_name + end + + def test_localhost_loopback_defaults + result = Geocoder.search("127.0.0.1").first + assert_equal "127.0.0.1", result.ip + assert_equal "", result.hostname + assert_equal "", result.continent_code + assert_equal "", result.continent_name + assert_equal "RD", result.country_code + assert_equal "Reserved", result.country_name + assert_equal "", result.region_code + assert_equal "", result.region_name + assert_equal "", result.city + assert_equal "", result.zip + assert_equal 0, result.latitude + assert_equal 0, result.longitude + assert_equal({}, result.location) + assert_equal({}, result.time_zone) + assert_equal({}, result.currency) + assert_equal({}, result.connection) + end + + def test_api_request_adds_access_key + lookup = Geocoder::Lookup.get(:ipstack) + assert_match 'http://api.ipstack.com/74.200.247.59?access_key=123', lookup.query_url(Geocoder::Query.new("74.200.247.59")) + end + + def test_api_request_adds_security_when_specified + lookup = Geocoder::Lookup.get(:ipstack) + + query_url = lookup.query_url(Geocoder::Query.new("74.200.247.59", params: { security: '1' })) + + assert_match(/&security=1/, query_url) + end + + def test_api_request_adds_hostname_when_specified + lookup = Geocoder::Lookup.get(:ipstack) + + query_url = lookup.query_url(Geocoder::Query.new("74.200.247.59", params: { hostname: '1' })) + + assert_match(/&hostname=1/, query_url) + end + + def test_api_request_adds_language_when_specified + lookup = Geocoder::Lookup.get(:ipstack) + + query_url = lookup.query_url(Geocoder::Query.new("74.200.247.59", params: { language: 'es' })) + + assert_match(/&language=es/, query_url) + end + + def test_api_request_adds_fields_when_specified + lookup = Geocoder::Lookup.get(:ipstack) + + query_url = lookup.query_url(Geocoder::Query.new("74.200.247.59", params: { fields: 'foo,bar' })) + + assert_match(/&fields=foo%2Cbar/, query_url) + end + + def test_logs_warning_when_errors_are_set_not_to_raise + Geocoder::Configuration.instance.data.clear + Geocoder::Configuration.set_defaults + Geocoder.configure(api_key: '123', ip_lookup: :ipstack, logger: @logger) + + lookup = Geocoder::Lookup.get(:ipstack) + + lookup.send(:results, Geocoder::Query.new("not_found")) + + assert @logger.logged?("Ipstack Geocoding API error: The requested resource does not exist.") + end + + def test_uses_lookup_specific_configuration + Geocoder::Configuration.instance.data.clear + Geocoder::Configuration.set_defaults + Geocoder.configure(api_key: '123', ip_lookup: :ipstack, logger: @logger, ipstack: { api_key: '345'}) + + lookup = Geocoder::Lookup.get(:ipstack) + assert_match 'http://api.ipstack.com/74.200.247.59?access_key=345', lookup.query_url(Geocoder::Query.new("74.200.247.59")) + end + + def test_not_authorized lookup = Geocoder::Lookup.get(:ipstack) + + error = assert_raise Geocoder::InvalidRequest do + lookup.send(:results, Geocoder::Query.new("not_found")) + end + + assert_equal error.message, "The requested resource does not exist." + end + + def test_missing_access_key + lookup = Geocoder::Lookup.get(:ipstack) + + error = assert_raise Geocoder::InvalidApiKey do + lookup.send(:results, Geocoder::Query.new("missing_access_key")) + end + + assert_equal error.message, "No API Key was specified." + end + + def test_invalid_access_key + lookup = Geocoder::Lookup.get(:ipstack) + + error = assert_raise Geocoder::InvalidApiKey do + lookup.send(:results, Geocoder::Query.new("invalid_access_key")) + end + + assert_equal error.message, "No API Key was specified or an invalid API Key was specified." + end + + def test_inactive_user + lookup = Geocoder::Lookup.get(:ipstack) + + error = assert_raise Geocoder::Error do + lookup.send(:results, Geocoder::Query.new("inactive_user")) + end + + assert_equal error.message, "The current user account is not active. User will be prompted to get in touch with Customer Support." + end + + def test_invalid_api_function + lookup = Geocoder::Lookup.get(:ipstack) + + error = assert_raise Geocoder::InvalidRequest do + lookup.send(:results, Geocoder::Query.new("invalid_api_function")) + end + + assert_equal error.message, "The requested API endpoint does not exist." + end + + def test_usage_limit + lookup = Geocoder::Lookup.get(:ipstack) + + error = assert_raise Geocoder::OverQueryLimitError do + lookup.send(:results, Geocoder::Query.new("usage_limit")) + end + + assert_equal error.message, "The maximum allowed amount of monthly API requests has been reached." + end + + def test_access_restricted + lookup = Geocoder::Lookup.get(:ipstack) + + error = assert_raise Geocoder::RequestDenied do + lookup.send(:results, Geocoder::Query.new("access_restricted")) + end + + assert_equal error.message, "The current subscription plan does not support this API endpoint." + end + + def test_protocol_access_restricted + lookup = Geocoder::Lookup.get(:ipstack) + + error = assert_raise Geocoder::RequestDenied do + lookup.send(:results, Geocoder::Query.new("protocol_access_restricted")) + end + + assert_equal error.message, "The user's current subscription plan does not support HTTPS Encryption." + end + + def test_invalid_fields + lookup = Geocoder::Lookup.get(:ipstack) + + error = assert_raise Geocoder::InvalidRequest do + lookup.send(:results, Geocoder::Query.new("invalid_fields")) + end + + assert_equal error.message, "One or more invalid fields were specified using the fields parameter." + end + + def test_too_many_ips + lookup = Geocoder::Lookup.get(:ipstack) + + error = assert_raise Geocoder::InvalidRequest do + lookup.send(:results, Geocoder::Query.new("too_many_ips")) + end + + assert_equal error.message, "Too many IPs have been specified for the Bulk Lookup Endpoint. (max. 50)" + end + + def test_batch_not_supported + lookup = Geocoder::Lookup.get(:ipstack) + + error = assert_raise Geocoder::RequestDenied do + lookup.send(:results, Geocoder::Query.new("batch_not_supported")) + end + + assert_equal error.message, "The Bulk Lookup Endpoint is not supported on the current subscription plan" + end +end