vrfs-774: geocoding tests

This commit is contained in:
Jonathan Kolyer 2013-11-03 01:43:09 -05:00
parent 6513293969
commit d045ae4b53
5 changed files with 96 additions and 44 deletions

View File

@ -1,9 +1,14 @@
require 'csv'
module JamRuby
class MaxMindGeo < ActiveRecord::Base
self.table_name = 'max_mind_geo'
def self.ip_lookup(ip_addy)
self.where(["ip_start <= ? AND ip_end >= ?",
ip_addy, ip_addy])
.limit(1)
.first
end
def self.import_from_max_mind(file)
# File Geo-139
@ -36,15 +41,6 @@ module JamRuby
end
User.find_each { |usr| usr.update_lat_lng }
end
# Make an IP address fit in a signed int. Just divide it by 2, as the least significant part
# just can't possibly matter. We can verify this if needed. My guess is the entire bottom octet is
# actually irrelevant
def self.ip_address_to_int(ip)
ip.split('.').inject(0) {|total,value| (total << 8 ) + value.to_i} / 2
end
end
end

View File

@ -11,7 +11,7 @@ module JamRuby
include Geokit::ActsAsMappable::Glue unless defined?(acts_as_mappable)
acts_as_mappable
after_update :check_lat_lng
after_save :check_lat_lng
attr_accessible :first_name, :last_name, :email, :city, :password, :password_confirmation, :state, :country, :birth_date, :subscribe_email, :terms_of_service, :original_fpfile, :cropped_fpfile, :cropped_s3_path, :photo_url, :crop_selection, :lat, :lng
@ -969,24 +969,29 @@ module JamRuby
end
def check_lat_lng
update_lat_lng if city_changed? || state_changed? || country_changed?
update_lat_lng if (city_changed? || state_changed? || country_changed?) && !lat_changed?
end
def update_lat_lng(ip_addy=nil)
def update_lat_lng(ip_addy=nil, force=false)
yn = false
if provides_location? # ip_addy argument ignored in this case
query = {:city => self.city}
query[:region] = self.state unless self.state.blank?
query[:country] = self.country unless self.country.blank?
if geo = MaxMindGeo.where(query).limit(1).first
self.update_attributes({:lat => geo.lat, :lng => geo.lng})
yn = true
if force || lat.nil? || lng.nil?
query = { :city => self.city }
query[:region] = self.state unless self.state.blank?
query[:country] = self.country unless self.country.blank?
if geo = MaxMindGeo.where(query).limit(1).first
self.update_attributes({ :lat => geo.lat, :lng => geo.lng })
yn = true
end
end
elsif ip_addy
if geo = MaxMindGeo.where(['ip_start >= ? AND ip_end <= ?',ip_addy,ip_addy]).limit(1).first
self.update_attributes({:lat => geo.lat, :lng => geo.lng})
if geo = MaxMindGeo.ip_lookup(ip_addy)
self.update_attributes({ :lat => geo.lat, :lng => geo.lng })
yn = true
end
end
else
self.update_attributes({ :lat => nil, :lng => nil })
yn = true
end
yn
end

View File

@ -130,12 +130,12 @@ FactoryGirl.define do
factory :geocoder, :class => JamRuby::MaxMindGeo do
country 'US'
region 'NC'
city 'Apex'
ip_start '1.0.0.0'
ip_end '1.1.1.1.'
lat 35.73265
lng -78.85029
sequence(:region) { |n| ['NC', 'CA'][(n-1).modulo(2)] }
sequence(:city) { |n| ['Apex', 'San Francisco'][(n-1).modulo(2)] }
sequence(:ip_start) { |n| ['1.1.0.0', '1.1.255.255'][(n-1).modulo(2)] }
sequence(:ip_end) { |n| ['1.2.0.0', '1.2.255.255'][(n-1).modulo(2)] }
sequence(:lat) { |n| [35.73265, 37.7742075][(n-1).modulo(2)] }
sequence(:lng) { |n| [-78.85029, -122.4155311][(n-1).modulo(2)] }
end
end

View File

@ -9,10 +9,6 @@ describe MaxMindGeo do
in_directory_with_file(GEO_CSV)
before do
# content_for_file('0.116.0.0,0.119.255.255,"AT","","","",47.3333,13.3333,,
# 1.0.0.0,1.0.0.255,"AU","","","",-27.0000,133.0000,,
# 1.0.1.0,1.0.1.255,"CN","07","Fuzhou","",26.0614,119.3061,,'.encode(Encoding::ISO_8859_1))
content_for_file('startIpNum,endIpNum,country,region,city,postalCode,latitude,longitude,dmaCode,areaCode
0.116.0.0,0.119.255.255,"AT","","","",47.3333,13.3333,123,123
1.0.0.0,1.0.0.255,"AU","","","",-27.0000,133.0000,,
@ -23,20 +19,20 @@ describe MaxMindGeo do
it { MaxMindGeo.count.should == 3 }
# let(:first) { MaxMindGeo.find_by_ip_start('0.116.0.0') }
# let(:second) { MaxMindGeo.find_by_ip_start('1.0.0.0') }
# let(:third) { MaxMindGeo.find_by_ip_start('1.0.1.0') }
let(:first) { MaxMindGeo.find_by_ip_start('0.116.0.0') }
let(:second) { MaxMindGeo.find_by_ip_start('1.0.0.0') }
let(:third) { MaxMindGeo.find_by_ip_start('1.0.1.0') }
# it { first.country.should == 'AT' }
# it { first.ip_start.should == '0.116.0.0' }
# it { first.ip_end.should == '0.119.255.255' }
it { first.country.should == 'AT' }
it { first.ip_start.should == '0.116.0.0' }
it { first.ip_end.should == '0.119.255.255' }
# it { second.country.should == 'AU' }
# it { second.ip_start.should == '1.0.0.0' }
# it { second.ip_end.should == '1.0.0.255' }
it { second.country.should == 'AU' }
it { second.ip_start.should == '1.0.0.0' }
it { second.ip_end.should == '1.0.0.255' }
# it { third.country.should == 'CN' }
# it { third.ip_start.should == '1.0.1.0' }
# it { third.ip_end.should == '1.0.1.255' }
it { third.country.should == 'CN' }
it { third.ip_start.should == '1.0.1.0' }
it { third.ip_end.should == '1.0.1.255' }
end

View File

@ -0,0 +1,55 @@
require 'spec_helper'
describe User do
=begin
X If user provides profile location data, that will be used for lat/lng lookup
X If the user changes their profile location, we update their lat/lng address
X If no profile location is provided, then we populate lat/lng from their IP address
X If no profile location is provided, and the user creates/joins a music session, then we update their lat/lng from the IP address
=end
before do
@geocode1 = FactoryGirl.create(:geocoder)
@geocode2 = FactoryGirl.create(:geocoder)
@user = User.new(first_name: "Example", last_name: "User", email: "user@example.com",
password: "foobar", password_confirmation: "foobar",
city: "Apex", state: "NC", country: "US",
terms_of_service: true, musician: true)
@user.save!
end
describe "with profile location data" do
it "should have lat/lng values" do
@user.lat.should == @geocode1.lat
@user.lng.should == @geocode1.lng
end
it "should have updated lat/lng values" do
@user.update_attributes({ :city => @geocode2.city,
:state => @geocode2.region,
:country => @geocode2.country,
})
@user.lat.should == @geocode2.lat
@user.lng.should == @geocode2.lng
end
end
describe "without profile location data" do
it "should have lat/lng values from ip_address" do
@user.update_attributes({ :city => nil,
:state => nil,
:country => nil,
})
@user.lat.should == nil
@user.lng.should == nil
geo = JamRuby::MaxMindGeo.ip_lookup('1.1.0.0')
geo.should_not be_nil
geo = JamRuby::MaxMindGeo.ip_lookup('1.1.0.255')
geo.should_not be_nil
@user.update_lat_lng('1.1.0.255')
@user.lat.should == @geocode1.lat
@user.lng.should == @geocode1.lng
end
end
end