Added documentation for ability to set conditions for recording impressions. Also, Had to do some work to get the tests passing

Merge remote branch 'upstream/master'

Conflicts:
  test_app/Gemfile.lock
This commit is contained in:
Cory Schires 2011-11-27 13:39:29 -06:00
commit e2ee248fba
15 changed files with 521 additions and 61 deletions

2
.gitignore vendored
View File

@ -1,4 +1,4 @@
Gemfile.lock Gemfile.lock
/test_app/db/migrate/20*
/test_app/db/schema.rb /test_app/db/schema.rb
/pkg /pkg
*~

View File

@ -120,6 +120,25 @@ If you'd like to include only unique impressions in your count:
is_impressionable :counter_cache => { :column_name => :my_column, :unique => true } is_impressionable :counter_cache => { :column_name => :my_column, :unique => true }
What if I only want to record unique impressions?
-------------------------------------------------
Maybe you only care about unique impressions and would like to eliminate unnecessary database calls. You can specify conditions for recording impressions in your controller:
# only record impression if the request has a unique combination of type, id, and session
impressionist :unique => [:impressionable_type, :impressionable_id, :session_hash]
# only record impression if the request has a unique combination of controller, action, and session
impressionist :unique => [:controller_name, :action_name, :session_hash]
# only record impression if session is unique
impressionist :unique => [:session_hash]
Or you can use the `impressionist` method directly:
impressionist(impressionable, "some message", :unique => [:session_hash])
Development Roadmap Development Roadmap
------------------- -------------------
* Automatic impression logging in views. For example, log initial view, and any partials called from initial view * Automatic impression logging in views. For example, log initial view, and any partials called from initial view

View File

@ -3,27 +3,23 @@ require 'digest/sha2'
module ImpressionistController module ImpressionistController
module ClassMethods module ClassMethods
def impressionist(opts={}) def impressionist(opts={})
before_filter { |c| c.impressionist_subapp_filter opts[:actions] } before_filter { |c| c.impressionist_subapp_filter(opts[:actions], opts[:unique])}
end end
end end
module InstanceMethods module InstanceMethods
def self.included(base) def self.included(base)
base.before_filter :impressionist_app_filter base.before_filter :impressionist_app_filter
end end
def impressionist(obj,message=nil) def impressionist(obj,message=nil,opts={})
unless bypass unless bypass
if obj.respond_to?("impressionable?") if obj.respond_to?("impressionable?")
obj.impressions.create(:message=> message, if unique_instance?(obj, opts[:unique])
:request_hash=> @impressionist_hash, obj.impressions.create(associative_create_statement({:message => message}))
:session_hash=> request.session_options[:id], end
:ip_address=> request.remote_ip,
:user_id=> user_id,
:controller_name=>controller_name,
:action_name=> action_name,
:referrer=>request.referer)
else else
# we could create an impression anyway. for classes, too. why not?
raise "#{obj.class.to_s} is not impressionable!" raise "#{obj.class.to_s} is not impressionable!"
end end
end end
@ -33,31 +29,73 @@ module ImpressionistController
@impressionist_hash = Digest::SHA2.hexdigest(Time.now.to_f.to_s+rand(10000).to_s) @impressionist_hash = Digest::SHA2.hexdigest(Time.now.to_f.to_s+rand(10000).to_s)
end end
def impressionist_subapp_filter(actions=nil) def impressionist_subapp_filter(actions=nil,unique_opts=nil)
unless bypass unless bypass
actions.collect!{|a|a.to_s} unless actions.blank? actions.collect!{|a|a.to_s} unless actions.blank?
if actions.blank? or actions.include?(action_name) if (actions.blank? || actions.include?(action_name)) && unique?(unique_opts)
Impression.create(:controller_name=> controller_name, Impression.create(direct_create_statement)
:action_name=> action_name,
:user_id=> user_id,
:request_hash=> @impressionist_hash,
:session_hash=> request.session_options[:id],
:ip_address=> request.remote_ip,
:impressionable_type=> controller_name.singularize.camelize,
:impressionable_id=> params[:id],
:referrer=>request.referer)
end end
end end
end end
private private
def bypass def bypass
Impressionist::Bots::WILD_CARDS.each do |wild_card| Impressionist::Bots::WILD_CARDS.each do |wild_card|
return true if request.user_agent and request.user_agent.downcase.include? wild_card return true if request.user_agent and request.user_agent.downcase.include? wild_card
end end
Impressionist::Bots::LIST.include? request.user_agent Impressionist::Bots::LIST.include? request.user_agent
end end
def unique_instance?(impressionable, unique_opts)
return unique_opts.blank? || impressionable.impressions.where(unique_query(unique_opts)).size == 0
end
def unique?(unique_opts)
return unique_opts.blank? || Impression.where(unique_query(unique_opts)).size == 0
end
# creates the query to check for uniqueness
def unique_query(unique_opts)
full_statement = direct_create_statement
# reduce the full statement to the params we need for the specified unique options
unique_opts.reduce({}) do |query, param|
query[param] = full_statement[param]
query
end
end
# creates a statment hash that contains default values for creating an impression via an AR relation.
def associative_create_statement(query_params={})
query_params.reverse_merge!(
:controller_name => controller_name,
:action_name => action_name,
:user_id => user_id,
:request_hash => @impressionist_hash,
:session_hash => session_hash,
:ip_address => request.remote_ip,
:referrer => request.referer
)
end
# creates a statment hash that contains default values for creating an impression.
def direct_create_statement(query_params={})
query_params.reverse_merge!(
:impressionable_type => controller_name.singularize.camelize,
:impressionable_id=> params[:id]
)
associative_create_statement(query_params)
end
def session_hash
# # careful: request.session_options[:id] encoding in rspec test was ASCII-8BIT
# # that broke the database query for uniqueness. not sure if this is a testing only issue.
# str = request.session_options[:id]
# logger.debug "Encoding: #{str.encoding.inspect}"
# # request.session_options[:id].encode("ISO-8859-1")
request.session_options[:id]
end
#use both @current_user and current_user helper #use both @current_user and current_user helper
def user_id def user_id
user_id = @current_user ? @current_user.id : nil rescue nil user_id = @current_user ? @current_user.id : nil rescue nil

View File

@ -3,7 +3,7 @@ source 'http://rubygems.org'
gem 'rails', '3.1' gem 'rails', '3.1'
gem 'sqlite3-ruby', :require => 'sqlite3' gem 'sqlite3-ruby', :require => 'sqlite3'
gem 'impressionist', :path=>"#{File.dirname(__FILE__)}/../" gem 'impressionist', :path=>"#{File.dirname(__FILE__)}/../"
gem "pg" #gem "pg"
group :development do group :development do
gem 'ZenTest' gem 'ZenTest'

View File

@ -1,5 +1,5 @@
PATH PATH
remote: /Users/coryschires/Desktop/work/applications/impressionist remote: /Users/coryschires/Desktop/impressionist
specs: specs:
impressionist (0.4.0) impressionist (0.4.0)
@ -45,7 +45,7 @@ GEM
autotest-standalone (4.5.8) autotest-standalone (4.5.8)
bcrypt-ruby (3.0.1) bcrypt-ruby (3.0.1)
builder (3.0.0) builder (3.0.0)
capybara (1.1.1) capybara (1.1.2)
mime-types (>= 1.16) mime-types (>= 1.16)
nokogiri (>= 1.3.3) nokogiri (>= 1.3.3)
rack (>= 1.0.0) rack (>= 1.0.0)
@ -54,23 +54,23 @@ GEM
xpath (~> 0.1.4) xpath (~> 0.1.4)
childprocess (0.2.2) childprocess (0.2.2)
ffi (~> 1.0.6) ffi (~> 1.0.6)
cucumber (1.1.0) cucumber (1.1.3)
builder (>= 2.1.2) builder (>= 2.1.2)
diff-lcs (>= 1.1.2) diff-lcs (>= 1.1.2)
gherkin (~> 2.5.0) gherkin (~> 2.6.7)
json (>= 1.4.6) json (>= 1.4.6)
term-ansicolor (>= 1.0.6) term-ansicolor (>= 1.0.6)
cucumber-rails (1.1.1) cucumber-rails (1.2.0)
capybara (>= 1.1.1) capybara (>= 1.1.1)
cucumber (>= 1.1.0) cucumber (>= 1.1.1)
nokogiri (>= 1.5.0) nokogiri (>= 1.5.0)
daemons (1.0.10) daemons (1.0.10)
database_cleaner (0.6.7) database_cleaner (0.7.0)
diff-lcs (1.1.3) diff-lcs (1.1.3)
erubis (2.7.0) erubis (2.7.0)
ffi (1.0.9) ffi (1.0.11)
gem_plugin (0.2.3) gem_plugin (0.2.3)
gherkin (2.5.4) gherkin (2.6.8)
json (>= 1.4.6) json (>= 1.4.6)
hike (1.2.1) hike (1.2.1)
i18n (0.6.0) i18n (0.6.0)
@ -88,8 +88,7 @@ GEM
gem_plugin (~> 0.2.3) gem_plugin (~> 0.2.3)
multi_json (1.0.3) multi_json (1.0.3)
nokogiri (1.5.0) nokogiri (1.5.0)
pg (0.11.0) polyglot (0.3.3)
polyglot (0.3.2)
rack (1.3.5) rack (1.3.5)
rack-cache (1.0.3) rack-cache (1.0.3)
rack (>= 0.4) rack (>= 0.4)
@ -130,28 +129,28 @@ GEM
activesupport (~> 3.0) activesupport (~> 3.0)
railties (~> 3.0) railties (~> 3.0)
rspec (~> 2.7.0) rspec (~> 2.7.0)
rubyzip (0.9.4) rubyzip (0.9.5)
selenium-webdriver (2.10.0) selenium-webdriver (2.13.0)
childprocess (>= 0.2.1) childprocess (>= 0.2.1)
ffi (= 1.0.9) ffi (~> 1.0.9)
json_pure json_pure
rubyzip rubyzip
spork (0.8.5) spork (0.8.5)
sprockets (2.0.3) sprockets (2.0.3)
hike (~> 1.2) hike (~> 1.2)
rack (~> 1.0) rack (~> 1.0)
tilt (!= 1.3.0, ~> 1.1) tilt (~> 1.1, != 1.3.0)
sqlite3 (1.3.4) sqlite3 (1.3.4)
sqlite3-ruby (1.3.3) sqlite3-ruby (1.3.3)
sqlite3 (>= 1.3.3) sqlite3 (>= 1.3.3)
systemu (2.4.0) systemu (2.4.1)
term-ansicolor (1.0.7) term-ansicolor (1.0.7)
thor (0.14.6) thor (0.14.6)
tilt (1.3.3) tilt (1.3.3)
treetop (1.4.10) treetop (1.4.10)
polyglot polyglot
polyglot (>= 0.3.1) polyglot (>= 0.3.1)
tzinfo (0.3.30) tzinfo (0.3.31)
xpath (0.1.4) xpath (0.1.4)
nokogiri (~> 1.3) nokogiri (~> 1.3)
@ -169,7 +168,6 @@ DEPENDENCIES
impressionist! impressionist!
launchy launchy
mongrel (= 1.2.0.pre2) mongrel (= 1.2.0.pre2)
pg
rails (= 3.1) rails (= 3.1)
rspec rspec
rspec-rails rspec-rails

View File

@ -0,0 +1,6 @@
# This controller imports the impressionist module to make the modules methods available for testing
class DummyController < ActionController::Base
impressionist
end

View File

@ -1,5 +1,6 @@
class WidgetsController < ApplicationController class WidgetsController < ApplicationController
impressionist :actions=>[:show,:index] impressionist :actions=>[:show,:index], :unique => [:controller_name,:action_name,:impressionable_id]
def show def show
end end
@ -8,4 +9,5 @@ class WidgetsController < ApplicationController
def new def new
end end
end end

View File

@ -0,0 +1,7 @@
# We don't really care about this model. It's just being used to test the uniqueness controller
# specs. Nevertheless, we need a model because the counter caching functionality expects it.
#
class Dummy < ActiveRecord::Base
self.abstract_class = true # doesn't need to be backed by an actual table
is_impressionable
end

View File

@ -6,28 +6,19 @@ development:
pool: 5 pool: 5
timeout: 5000 timeout: 5000
# Warning: The database defined as "test" will be erased and test: &test
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
#test: &test
# adapter: sqlite3
# database: db/test.sqlite3
# pool: 5
# timeout: 5000
test:
adapter: sqlite3 adapter: sqlite3
database: db/test.sqlite3 database: db/test.sqlite3
pool: 5 pool: 5
timeout: 5000 timeout: 5000
pg_test: #pg_test:
adapter: postgresql # adapter: postgresql
database: impressionist_test # database: impressionist_test
username: johnmcaliley # username: johnmcaliley
password: # password:
host: localhost # host: localhost
encoding: UTF8 # encoding: UTF8
production: production:
adapter: sqlite3 adapter: sqlite3

View File

@ -0,0 +1,15 @@
class CreateWidgets < ActiveRecord::Migration
def self.up
create_table :widgets do |t|
t.string :name
t.integer :impressions_count
t.timestamps
end
end
def self.down
drop_table :widgets
end
end

View File

@ -0,0 +1,37 @@
class CreateImpressionsTable < ActiveRecord::Migration
def self.up
create_table :impressions, :force => true do |t|
t.string :impressionable_type
t.integer :impressionable_id
t.integer :user_id
t.string :controller_name
t.string :action_name
t.string :view_name
t.string :request_hash
t.string :session_hash
t.string :ip_address
t.string :message
t.string :referrer
t.timestamps
end
add_index :impressions, [:impressionable_type, :impressionable_id, :request_hash], :name => "poly_request_index", :unique => false
add_index :impressions, [:impressionable_type, :impressionable_id, :ip_address], :name => "poly_ip_index", :unique => false
add_index :impressions, [:impressionable_type, :impressionable_id, :session_hash], :name => "poly_session_index", :unique => false
add_index :impressions, [:controller_name,:action_name,:request_hash], :name => "controlleraction_request_index", :unique => false
add_index :impressions, [:controller_name,:action_name,:ip_address], :name => "controlleraction_ip_index", :unique => false
add_index :impressions, [:controller_name,:action_name,:session_hash], :name => "controlleraction_session_index", :unique => false
add_index :impressions, :user_id
end
def self.down
remove_index :impressions, :name => :poly_request_index
remove_index :impressions, :name => :poly_ip_index
remove_index :impressions, :name => :poly_session_index
remove_index :impressions, :name => :controlleraction_request_index
remove_index :impressions, :name => :controlleraction_ip_index
remove_index :impressions, :name => :controlleraction_session_index
remove_index :impressions, :user_id
drop_table :impressions
end
end

View File

@ -95,4 +95,31 @@ describe WidgetsController do
get "show", :id=> 1 get "show", :id=> 1
Impression.all.size.should eq 11 Impression.all.size.should eq 11
end end
describe "impressionist unique options" do
it "should log unique impressions at the per action level" do
get "show", :id=> 1
Impression.all.size.should eq 12
get "show", :id=> 2
Impression.all.size.should eq 13
get "show", :id => 2
Impression.all.size.should eq 13
get "index"
Impression.all.size.should eq 14
end
it "should log unique impressions only once per id" do
get "show", :id=> 1
Impression.all.size.should eq 12
get "show", :id=> 2
Impression.all.size.should eq 13
get "show", :id => 2
Impression.all.size.should eq 13
get "index"
Impression.all.size.should eq 14
end
end
end end

View File

@ -0,0 +1,312 @@
require "spec_helper.rb"
# we use the posts controller as it uses the impressionsist module. any such controller would do.
describe DummyController do
before do
@impression_count = Impression.all.size
end
describe "impressionist filter uniqueness" do
it "should ignore uniqueness if not requested" do
controller.impressionist_subapp_filter(nil, nil)
controller.impressionist_subapp_filter(nil, nil)
Impression.should have(@impression_count + 2).records
end
it "should recognize unique session" do
# the following line was necessary as session hash returned a binary string (ASCII-8BIT encoded)
controller.stub!(:session_hash).and_return(request.session_options[:id].encode("ISO-8859-1"))
controller.impressionist_subapp_filter(nil, [:session_hash])
controller.impressionist_subapp_filter(nil, [:session_hash])
Impression.should have(@impression_count + 1).records
end
it "should recognize unique ip" do
controller.request.stub!(:remote_ip).and_return("1.2.3.4")
controller.impressionist_subapp_filter(nil, [:ip_address])
controller.impressionist_subapp_filter(nil, [:ip_address])
Impression.should have(@impression_count + 1).records
end
it "should recognize unique request" do
controller.impressionist_subapp_filter(nil, [:request_hash])
controller.impressionist_subapp_filter(nil, [:request_hash])
Impression.should have(@impression_count + 1).records
end
it "should recognize unique action" do
controller.stub!(:action_name).and_return("test_action")
controller.impressionist_subapp_filter(nil, [:action_name])
controller.impressionist_subapp_filter(nil, [:action_name])
Impression.should have(@impression_count + 1).records
end
it "should recognize unique controller" do
controller.stub!(:controller_name).and_return("post")
controller.impressionist_subapp_filter(nil, [:controller_name])
controller.impressionist_subapp_filter(nil, [:controller_name])
Impression.should have(@impression_count + 1).records
end
it "should recognize unique user" do
controller.stub!(:user_id).and_return(42)
controller.impressionist_subapp_filter(nil, [:user_id])
controller.impressionist_subapp_filter(nil, [:user_id])
Impression.should have(@impression_count + 1).records
end
it "should recognize unique referer" do
controller.request.stub!(:referer).and_return("http://foo/bar")
controller.impressionist_subapp_filter(nil, [:referrer])
controller.impressionist_subapp_filter(nil, [:referrer])
Impression.should have(@impression_count + 1).records
end
it "should recognize unique id" do
controller.stub!(:params).and_return({:id => "666"}) # for correct impressionable id in filter
controller.impressionist_subapp_filter(nil, [:impressionable_id])
controller.impressionist_subapp_filter(nil, [:impressionable_id])
Impression.should have(@impression_count + 1).records
end
# extra redundant test for important controller and action combination.
it "should recognize different controller and action" do
controller.stub!(:controller_name).and_return("post")
controller.stub!(:action_name).and_return("test_action")
controller.impressionist_subapp_filter(nil, [:controller_name, :action_name])
controller.impressionist_subapp_filter(nil, [:controller_name, :action_name])
Impression.should have(@impression_count + 1).records
controller.stub!(:action_name).and_return("another_action")
controller.impressionist_subapp_filter(nil, [:controller_name, :action_name])
controller.impressionist_subapp_filter(nil, [:controller_name, :action_name])
Impression.should have(@impression_count + 2).records
controller.stub!(:controller_name).and_return("article")
controller.impressionist_subapp_filter(nil, [:controller_name, :action_name])
controller.impressionist_subapp_filter(nil, [:controller_name, :action_name])
Impression.should have(@impression_count + 3).records
end
it "should recognize different action" do
controller.stub!(:action_name).and_return("test_action")
controller.impressionist_subapp_filter(nil, [:action_name])
controller.impressionist_subapp_filter(nil, [:action_name])
Impression.should have(@impression_count + 1).records
controller.stub!(:action_name).and_return("another_action")
controller.impressionist_subapp_filter(nil, [:action_name])
controller.impressionist_subapp_filter(nil, [:action_name])
Impression.should have(@impression_count + 2).records
end
it "should recognize different controller" do
controller.stub!(:controller_name).and_return("post")
controller.impressionist_subapp_filter(nil, [:controller_name])
controller.impressionist_subapp_filter(nil, [:controller_name])
Impression.should have(@impression_count + 1).records
controller.stub!(:controller_name).and_return("article")
controller.impressionist_subapp_filter(nil, [:controller_name])
controller.impressionist_subapp_filter(nil, [:controller_name])
Impression.should have(@impression_count + 2).records
end
it "should recognize different session" do
controller.stub!(:session_hash).and_return("foo")
controller.impressionist_subapp_filter(nil, [:session_hash])
controller.impressionist_subapp_filter(nil, [:session_hash])
Impression.should have(@impression_count + 1).records
controller.stub!(:session_hash).and_return("bar")
controller.impressionist_subapp_filter(nil, [:session_hash])
controller.impressionist_subapp_filter(nil, [:session_hash])
Impression.should have(@impression_count + 2).records
end
it "should recognize different ip" do
controller.request.stub!(:remote_ip).and_return("1.2.3.4")
controller.impressionist_subapp_filter(nil, [:ip_address])
controller.impressionist_subapp_filter(nil, [:ip_address])
Impression.should have(@impression_count + 1).records
controller.request.stub!(:remote_ip).and_return("5.6.7.8")
controller.impressionist_subapp_filter(nil, [:ip_address])
controller.impressionist_subapp_filter(nil, [:ip_address])
Impression.should have(@impression_count + 2).records
end
it "should recognize different referer" do
controller.request.stub!(:referer).and_return("http://foo/bar")
controller.impressionist_subapp_filter(nil, [:referrer])
controller.impressionist_subapp_filter(nil, [:referrer])
Impression.should have(@impression_count + 1).records
controller.request.stub!(:referer).and_return("http://bar/fo")
controller.impressionist_subapp_filter(nil, [:referrer])
controller.impressionist_subapp_filter(nil, [:referrer])
Impression.should have(@impression_count + 2).records
end
it "should recognize different id" do
controller.stub!(:params).and_return({:id => "666"}) # for correct impressionable id in filter
controller.impressionist_subapp_filter(nil, [:impressionable_type, :impressionable_id])
controller.impressionist_subapp_filter(nil, [:impressionable_type, :impressionable_id])
controller.stub!(:params).and_return({:id => "42"}) # for correct impressionable id in filter
controller.impressionist_subapp_filter(nil, [:impressionable_type, :impressionable_id])
controller.impressionist_subapp_filter(nil, [:impressionable_type, :impressionable_id])
Impression.should have(@impression_count + 2).records
end
it "should recognize combined uniqueness" do
controller.stub!(:action_name).and_return("test_action")
controller.impressionist_subapp_filter(nil, [:ip_address, :request_hash, :action_name])
controller.impressionist_subapp_filter(nil, [:request_hash, :ip_address, :action_name])
controller.impressionist_subapp_filter(nil, [:request_hash, :action_name])
controller.impressionist_subapp_filter(nil, [:ip_address, :action_name])
controller.impressionist_subapp_filter(nil, [:ip_address, :request_hash])
controller.impressionist_subapp_filter(nil, [:action_name])
controller.impressionist_subapp_filter(nil, [:ip_address])
controller.impressionist_subapp_filter(nil, [:request_hash])
Impression.should have(@impression_count + 1).records
end
it "should recognize combined non-uniqueness" do
controller.stub!(:action_name).and_return(nil)
controller.impressionist_subapp_filter(nil, [:ip_address, :action_name])
controller.stub!(:action_name).and_return("test_action")
controller.impressionist_subapp_filter(nil, [:ip_address, :action_name])
controller.stub!(:action_name).and_return("another_action")
controller.impressionist_subapp_filter(nil, [:ip_address, :action_name])
Impression.should have(@impression_count + 3).records
end
end
describe "impressionist method uniqueness for impressionables" do
# in this test we reuse the post model. might break if model changes.
it "should ignore uniqueness if not requested" do
impressionable = Post.create
controller.impressionist impressionable
controller.impressionist impressionable
Impression.should have(@impression_count + 2).records
end
it "should recognize unique session" do
# the following line was necessary as session hash returned a binary string (ASCII-8BIT encoded)
controller.stub!(:session_hash).and_return(request.session_options[:id].encode("ISO-8859-1"))
impressionable = Post.create
controller.impressionist(impressionable, nil, :unique => [:session_hash])
controller.impressionist(impressionable, nil, :unique => [:session_hash])
Impression.should have(@impression_count + 1).records
end
it "should recognize unique ip" do
controller.request.stub!(:remote_ip).and_return("1.2.3.4")
impressionable = Post.create
controller.impressionist(impressionable, nil, :unique => [:ip_address])
controller.impressionist(impressionable, nil, :unique => [:ip_address])
Impression.should have(@impression_count + 1).records
end
it "should recognize unique request" do
impressionable = Post.create
controller.impressionist(impressionable, nil, :unique => [:request_hash])
controller.impressionist(impressionable, nil, :unique => [:request_hash])
Impression.should have(@impression_count + 1).records
end
it "should recognize unique user" do
controller.stub!(:user_id).and_return(666)
impressionable = Post.create
controller.impressionist(impressionable, nil, :unique => [:user_id])
controller.impressionist(impressionable, nil, :unique => [:user_id])
Impression.should have(@impression_count + 1).records
end
it "should recognize unique referer" do
controller.request.stub!(:referer).and_return("http://foo/bar")
impressionable = Post.create
controller.impressionist(impressionable, nil, :unique => [:referrer])
controller.impressionist(impressionable, nil, :unique => [:referrer])
Impression.should have(@impression_count + 1).records
end
it "should recognize different session" do
impressionable = Post.create
controller.stub!(:session_hash).and_return("foo")
controller.impressionist(impressionable, nil, :unique => [:session_hash])
controller.impressionist(impressionable, nil, :unique => [:session_hash])
Impression.should have(@impression_count + 1).records
controller.stub!(:session_hash).and_return("bar")
controller.impressionist(impressionable, nil, :unique => [:session_hash])
controller.impressionist(impressionable, nil, :unique => [:session_hash])
Impression.should have(@impression_count + 2).records
end
it "should recognize different ip" do
controller.request.stub!(:remote_ip).and_return("1.2.3.4")
impressionable = Post.create
controller.impressionist(impressionable, nil, :unique => [:ip_address])
controller.impressionist(impressionable, nil, :unique => [:ip_address])
Impression.should have(@impression_count + 1).records
controller.request.stub!(:remote_ip).and_return("5.6.7.8")
controller.impressionist(impressionable, nil, :unique => [:ip_address])
controller.impressionist(impressionable, nil, :unique => [:ip_address])
Impression.should have(@impression_count + 2).records
end
it "should recognize different user" do
impressionable = Post.create
controller.stub!(:user_id).and_return(666)
controller.impressionist(impressionable, nil, :unique => [:user_id])
controller.impressionist(impressionable, nil, :unique => [:user_id])
Impression.should have(@impression_count + 1).records
controller.stub!(:user_id).and_return(42)
controller.impressionist(impressionable, nil, :unique => [:user_id])
controller.impressionist(impressionable, nil, :unique => [:user_id])
Impression.should have(@impression_count + 2).records
end
it "should recognize combined uniqueness" do
impressionable = Post.create
controller.stub!(:session_hash).and_return("foo")
controller.impressionist(impressionable, nil, :unique => [:ip_address, :request_hash, :session_hash])
controller.impressionist(impressionable, nil, :unique => [:request_hash, :ip_address, :session_hash])
controller.impressionist(impressionable, nil, :unique => [:request_hash, :session_hash])
controller.impressionist(impressionable, nil, :unique => [:ip_address, :session_hash])
controller.impressionist(impressionable, nil, :unique => [:ip_address, :request_hash])
controller.impressionist(impressionable, nil, :unique => [:session_hash])
controller.impressionist(impressionable, nil, :unique => [:ip_address])
controller.impressionist(impressionable, nil, :unique => [:request_hash])
Impression.should have(@impression_count + 1).records
end
it "should recognize combined non-uniqueness" do
impressionable = Post.create
controller.stub!(:session_hash).and_return(nil)
controller.impressionist(impressionable, nil, :unique => [:ip_address, :session_hash])
controller.stub!(:session_hash).and_return("foo")
controller.impressionist(impressionable, nil, :unique => [:ip_address, :session_hash])
controller.stub!(:session_hash).and_return("bar")
controller.impressionist(impressionable, nil, :unique => [:ip_address, :session_hash])
Impression.should have(@impression_count + 3).records
end
end
describe "impressionist filter and method uniqueness" do
it "should recognize uniqueness" do
impressionable = Post.create
controller.stub!(:controller_name).and_return("posts") # for correct impressionable type in filter
controller.stub!(:params).and_return({:id => impressionable.id.to_s}) # for correct impressionable id in filter
controller.stub!(:session_hash).and_return("foo")
controller.request.stub!(:remote_ip).and_return("1.2.3.4")
# order of the following methods is important for the test!
controller.impressionist_subapp_filter(nil, [:ip_address, :request_hash, :session_hash])
controller.impressionist(impressionable, nil, :unique => [:ip_address, :request_hash, :session_hash])
Impression.should have(@impression_count + 1).records
end
end
end

View File

@ -1,6 +1,8 @@
require 'spec_helper' require 'spec_helper'
require 'systemu' require 'systemu'
# FIXME this test might break the others if run before them
#
describe Impressionist do describe Impressionist do
fixtures :articles,:impressions,:posts fixtures :articles,:impressions,:posts
it "should delete existing migration and generate the migration file" do it "should delete existing migration and generate the migration file" do

View File

@ -24,4 +24,10 @@ RSpec.configure do |config|
# examples within a transaction, remove the following line or assign false # examples within a transaction, remove the following line or assign false
# instead of true. # instead of true.
config.use_transactional_fixtures = true config.use_transactional_fixtures = true
# make the rails logger usable in the tests as logger.xxx "..."
def logger
Rails.logger
end
end end