impressionist 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. data/.gitignore +11 -0
  2. data/.rspec +1 -0
  3. data/.travis.yml +11 -0
  4. data/CHANGELOG.rdoc +1 -1
  5. data/Gemfile +8 -19
  6. data/README.md +65 -34
  7. data/Rakefile +10 -82
  8. data/app/controllers/impressionist_controller.rb +11 -11
  9. data/app/models/impression.rb +2 -15
  10. data/app/models/impressionist/bots.rb +3 -3
  11. data/app/models/impressionist/impressionable.rb +29 -41
  12. data/impressionist.gemspec +22 -65
  13. data/lib/generators/active_record/impressionist_generator.rb +21 -0
  14. data/lib/generators/{impressionist → active_record}/templates/create_impressions_table.rb +1 -9
  15. data/lib/generators/impressionist_generator.rb +12 -0
  16. data/lib/generators/mongo_mapper/impressionist_generator.rb +8 -0
  17. data/lib/generators/templates/impression.rb +5 -0
  18. data/lib/impressionist.rb +10 -3
  19. data/lib/impressionist/bots.rb +1 -1
  20. data/lib/impressionist/engine.rb +11 -3
  21. data/lib/impressionist/models/active_record/impression.rb +18 -0
  22. data/lib/impressionist/models/active_record/impressionist/impressionable.rb +12 -0
  23. data/lib/impressionist/models/mongo_mapper/impression.rb +17 -0
  24. data/lib/impressionist/models/mongo_mapper/impressionist/impressionable.rb +12 -0
  25. data/lib/impressionist/version.rb +3 -0
  26. data/test_app/.gitignore +17 -0
  27. data/test_app/.rspec +1 -0
  28. data/test_app/Gemfile +58 -0
  29. data/test_app/README +256 -0
  30. data/test_app/README.rdoc +261 -0
  31. data/test_app/Rakefile +7 -0
  32. data/test_app/app/assets/images/rails.png +0 -0
  33. data/test_app/app/assets/javascripts/application.js +15 -0
  34. data/test_app/app/assets/stylesheets/application.css +13 -0
  35. data/test_app/app/controllers/application_controller.rb +8 -0
  36. data/test_app/app/controllers/articles_controller.rb +18 -0
  37. data/test_app/app/controllers/dummy_controller.rb +6 -0
  38. data/test_app/app/controllers/posts_controller.rb +23 -0
  39. data/test_app/app/controllers/widgets_controller.rb +13 -0
  40. data/test_app/app/helpers/application_helper.rb +2 -0
  41. data/{lib/impressionist/railties/tasks.rake → test_app/app/mailers/.gitkeep} +0 -0
  42. data/test_app/app/models/.gitkeep +0 -0
  43. data/test_app/app/models/article.rb +3 -0
  44. data/test_app/app/models/dummy.rb +7 -0
  45. data/test_app/app/models/post.rb +3 -0
  46. data/test_app/app/models/user.rb +3 -0
  47. data/test_app/app/models/widget.rb +3 -0
  48. data/test_app/app/views/articles/index.html.erb +1 -0
  49. data/test_app/app/views/articles/show.html.erb +1 -0
  50. data/test_app/app/views/layouts/application.html.erb +14 -0
  51. data/test_app/app/views/posts/edit.html.erb +0 -0
  52. data/test_app/app/views/posts/index.html.erb +0 -0
  53. data/test_app/app/views/posts/show.html.erb +0 -0
  54. data/test_app/app/views/widgets/index.html.erb +0 -0
  55. data/test_app/app/views/widgets/new.html.erb +0 -0
  56. data/test_app/app/views/widgets/show.html.erb +0 -0
  57. data/test_app/config.ru +4 -0
  58. data/test_app/config/application.rb +59 -0
  59. data/test_app/config/boot.rb +6 -0
  60. data/test_app/config/cucumber.yml +8 -0
  61. data/test_app/config/database.yml +30 -0
  62. data/test_app/config/environment.rb +5 -0
  63. data/test_app/config/environments/development.rb +37 -0
  64. data/test_app/config/environments/pg_test.rb +35 -0
  65. data/test_app/config/environments/production.rb +67 -0
  66. data/test_app/config/environments/test.rb +37 -0
  67. data/test_app/config/initializers/backtrace_silencers.rb +7 -0
  68. data/test_app/config/initializers/impression.rb +5 -0
  69. data/test_app/config/initializers/inflections.rb +15 -0
  70. data/test_app/config/initializers/mime_types.rb +5 -0
  71. data/test_app/config/initializers/secret_token.rb +7 -0
  72. data/test_app/config/initializers/session_store.rb +8 -0
  73. data/test_app/config/initializers/wrap_parameters.rb +14 -0
  74. data/test_app/config/locales/en.yml +5 -0
  75. data/test_app/config/routes.rb +3 -0
  76. data/test_app/db/migrate/20110201153144_create_articles.rb +13 -0
  77. data/test_app/db/migrate/20110210205028_create_posts.rb +13 -0
  78. data/test_app/db/migrate/20111127184039_create_widgets.rb +15 -0
  79. data/test_app/db/seeds.rb +7 -0
  80. data/test_app/lib/assets/.gitkeep +0 -0
  81. data/test_app/lib/tasks/.gitkeep +0 -0
  82. data/test_app/lib/tasks/cucumber.rake +53 -0
  83. data/test_app/log/.gitkeep +0 -0
  84. data/test_app/public/404.html +26 -0
  85. data/test_app/public/422.html +26 -0
  86. data/test_app/public/500.html +25 -0
  87. data/test_app/public/favicon.ico +0 -0
  88. data/test_app/public/images/rails.png +0 -0
  89. data/test_app/public/index.html +241 -0
  90. data/test_app/public/javascripts/application.js +2 -0
  91. data/test_app/public/javascripts/controls.js +965 -0
  92. data/test_app/public/javascripts/dragdrop.js +974 -0
  93. data/test_app/public/javascripts/effects.js +1123 -0
  94. data/test_app/public/javascripts/prototype.js +6001 -0
  95. data/test_app/public/javascripts/rails.js +175 -0
  96. data/test_app/public/robots.txt +5 -0
  97. data/test_app/public/stylesheets/.gitkeep +0 -0
  98. data/test_app/script/cucumber +10 -0
  99. data/test_app/script/rails +6 -0
  100. data/test_app/spec/controllers/controller_spec.rb +125 -0
  101. data/test_app/spec/controllers/impressionist_uniqueness_spec.rb +310 -0
  102. data/test_app/spec/fixtures/articles.yml +3 -0
  103. data/test_app/spec/fixtures/impressions.yml +43 -0
  104. data/test_app/spec/fixtures/posts.yml +3 -0
  105. data/test_app/spec/fixtures/widgets.yml +4 -0
  106. data/test_app/spec/intializers/initializers_spec.rb +18 -0
  107. data/test_app/spec/models/counter_caching_spec.rb +30 -0
  108. data/test_app/spec/models/model_spec.rb +94 -0
  109. data/test_app/spec/rails_generators/rails_generators_spec.rb +23 -0
  110. data/test_app/spec/spec_helper.rb +36 -0
  111. data/upgrade_migrations/version_0_3_0.rb +7 -7
  112. data/upgrade_migrations/version_0_4_0.rb +2 -2
  113. metadata +356 -99
  114. data/VERSION +0 -1
  115. data/config/routes.rb +0 -2
  116. data/lib/generators/impressionist/impressionist_generator.rb +0 -20
@@ -0,0 +1,175 @@
1
+ (function() {
2
+ // Technique from Juriy Zaytsev
3
+ // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
4
+ function isEventSupported(eventName) {
5
+ var el = document.createElement('div');
6
+ eventName = 'on' + eventName;
7
+ var isSupported = (eventName in el);
8
+ if (!isSupported) {
9
+ el.setAttribute(eventName, 'return;');
10
+ isSupported = typeof el[eventName] == 'function';
11
+ }
12
+ el = null;
13
+ return isSupported;
14
+ }
15
+
16
+ function isForm(element) {
17
+ return Object.isElement(element) && element.nodeName.toUpperCase() == 'FORM'
18
+ }
19
+
20
+ function isInput(element) {
21
+ if (Object.isElement(element)) {
22
+ var name = element.nodeName.toUpperCase()
23
+ return name == 'INPUT' || name == 'SELECT' || name == 'TEXTAREA'
24
+ }
25
+ else return false
26
+ }
27
+
28
+ var submitBubbles = isEventSupported('submit'),
29
+ changeBubbles = isEventSupported('change')
30
+
31
+ if (!submitBubbles || !changeBubbles) {
32
+ // augment the Event.Handler class to observe custom events when needed
33
+ Event.Handler.prototype.initialize = Event.Handler.prototype.initialize.wrap(
34
+ function(init, element, eventName, selector, callback) {
35
+ init(element, eventName, selector, callback)
36
+ // is the handler being attached to an element that doesn't support this event?
37
+ if ( (!submitBubbles && this.eventName == 'submit' && !isForm(this.element)) ||
38
+ (!changeBubbles && this.eventName == 'change' && !isInput(this.element)) ) {
39
+ // "submit" => "emulated:submit"
40
+ this.eventName = 'emulated:' + this.eventName
41
+ }
42
+ }
43
+ )
44
+ }
45
+
46
+ if (!submitBubbles) {
47
+ // discover forms on the page by observing focus events which always bubble
48
+ document.on('focusin', 'form', function(focusEvent, form) {
49
+ // special handler for the real "submit" event (one-time operation)
50
+ if (!form.retrieve('emulated:submit')) {
51
+ form.on('submit', function(submitEvent) {
52
+ var emulated = form.fire('emulated:submit', submitEvent, true)
53
+ // if custom event received preventDefault, cancel the real one too
54
+ if (emulated.returnValue === false) submitEvent.preventDefault()
55
+ })
56
+ form.store('emulated:submit', true)
57
+ }
58
+ })
59
+ }
60
+
61
+ if (!changeBubbles) {
62
+ // discover form inputs on the page
63
+ document.on('focusin', 'input, select, texarea', function(focusEvent, input) {
64
+ // special handler for real "change" events
65
+ if (!input.retrieve('emulated:change')) {
66
+ input.on('change', function(changeEvent) {
67
+ input.fire('emulated:change', changeEvent, true)
68
+ })
69
+ input.store('emulated:change', true)
70
+ }
71
+ })
72
+ }
73
+
74
+ function handleRemote(element) {
75
+ var method, url, params;
76
+
77
+ var event = element.fire("ajax:before");
78
+ if (event.stopped) return false;
79
+
80
+ if (element.tagName.toLowerCase() === 'form') {
81
+ method = element.readAttribute('method') || 'post';
82
+ url = element.readAttribute('action');
83
+ params = element.serialize();
84
+ } else {
85
+ method = element.readAttribute('data-method') || 'get';
86
+ url = element.readAttribute('href');
87
+ params = {};
88
+ }
89
+
90
+ new Ajax.Request(url, {
91
+ method: method,
92
+ parameters: params,
93
+ evalScripts: true,
94
+
95
+ onComplete: function(request) { element.fire("ajax:complete", request); },
96
+ onSuccess: function(request) { element.fire("ajax:success", request); },
97
+ onFailure: function(request) { element.fire("ajax:failure", request); }
98
+ });
99
+
100
+ element.fire("ajax:after");
101
+ }
102
+
103
+ function handleMethod(element) {
104
+ var method = element.readAttribute('data-method'),
105
+ url = element.readAttribute('href'),
106
+ csrf_param = $$('meta[name=csrf-param]')[0],
107
+ csrf_token = $$('meta[name=csrf-token]')[0];
108
+
109
+ var form = new Element('form', { method: "POST", action: url, style: "display: none;" });
110
+ element.parentNode.insert(form);
111
+
112
+ if (method !== 'post') {
113
+ var field = new Element('input', { type: 'hidden', name: '_method', value: method });
114
+ form.insert(field);
115
+ }
116
+
117
+ if (csrf_param) {
118
+ var param = csrf_param.readAttribute('content'),
119
+ token = csrf_token.readAttribute('content'),
120
+ field = new Element('input', { type: 'hidden', name: param, value: token });
121
+ form.insert(field);
122
+ }
123
+
124
+ form.submit();
125
+ }
126
+
127
+
128
+ document.on("click", "*[data-confirm]", function(event, element) {
129
+ var message = element.readAttribute('data-confirm');
130
+ if (!confirm(message)) event.stop();
131
+ });
132
+
133
+ document.on("click", "a[data-remote]", function(event, element) {
134
+ if (event.stopped) return;
135
+ handleRemote(element);
136
+ event.stop();
137
+ });
138
+
139
+ document.on("click", "a[data-method]", function(event, element) {
140
+ if (event.stopped) return;
141
+ handleMethod(element);
142
+ event.stop();
143
+ });
144
+
145
+ document.on("submit", function(event) {
146
+ var element = event.findElement(),
147
+ message = element.readAttribute('data-confirm');
148
+ if (message && !confirm(message)) {
149
+ event.stop();
150
+ return false;
151
+ }
152
+
153
+ var inputs = element.select("input[type=submit][data-disable-with]");
154
+ inputs.each(function(input) {
155
+ input.disabled = true;
156
+ input.writeAttribute('data-original-value', input.value);
157
+ input.value = input.readAttribute('data-disable-with');
158
+ });
159
+
160
+ var element = event.findElement("form[data-remote]");
161
+ if (element) {
162
+ handleRemote(element);
163
+ event.stop();
164
+ }
165
+ });
166
+
167
+ document.on("ajax:after", "form", function(event, element) {
168
+ var inputs = element.select("input[type=submit][disabled=true][data-disable-with]");
169
+ inputs.each(function(input) {
170
+ input.value = input.readAttribute('data-original-value');
171
+ input.removeAttribute('data-original-value');
172
+ input.disabled = false;
173
+ });
174
+ });
175
+ })();
@@ -0,0 +1,5 @@
1
+ # See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file
2
+ #
3
+ # To ban all spiders from the entire site uncomment the next two lines:
4
+ # User-Agent: *
5
+ # Disallow: /
File without changes
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ vendored_cucumber_bin = Dir["#{File.dirname(__FILE__)}/../vendor/{gems,plugins}/cucumber*/bin/cucumber"].first
4
+ if vendored_cucumber_bin
5
+ load File.expand_path(vendored_cucumber_bin)
6
+ else
7
+ require 'rubygems' unless ENV['NO_RUBYGEMS']
8
+ require 'cucumber'
9
+ load Cucumber::BINARY
10
+ end
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
5
+ require File.expand_path('../../config/boot', __FILE__)
6
+ require 'rails/commands'
@@ -0,0 +1,125 @@
1
+ require 'spec_helper'
2
+
3
+ describe ArticlesController do
4
+ fixtures :articles,:impressions,:posts,:widgets
5
+ render_views
6
+
7
+ it "should make the impressionable_hash available" do
8
+ get "index"
9
+ response.body.include?("false").should eq true
10
+ end
11
+
12
+ it "should log an impression with a message" do
13
+ get "index"
14
+ Impression.all.size.should eq 12
15
+ Article.first.impressions.last.message.should eq "this is a test article impression"
16
+ Article.first.impressions.last.controller_name.should eq "articles"
17
+ Article.first.impressions.last.action_name.should eq "index"
18
+ end
19
+
20
+ it "should log an impression without a message" do
21
+ get "show", :id=> 1
22
+ Impression.all.size.should eq 12
23
+ Article.first.impressions.last.message.should eq nil
24
+ Article.first.impressions.last.controller_name.should eq "articles"
25
+ Article.first.impressions.last.action_name.should eq "show"
26
+ end
27
+
28
+ it "should log the user_id if user is authenticated (@current_user before_filter method)" do
29
+ session[:user_id] = 123
30
+ get "show", :id=> 1
31
+ Article.first.impressions.last.user_id.should eq 123
32
+ end
33
+
34
+ it "should not log the user_id if user is authenticated" do
35
+ get "show", :id=> 1
36
+ Article.first.impressions.last.user_id.should eq nil
37
+ end
38
+
39
+ it "should log the request_hash, ip_address, referrer and session_hash" do
40
+ get "show", :id=> 1
41
+ Impression.last.request_hash.size.should eq 64
42
+ Impression.last.ip_address.should eq "0.0.0.0"
43
+ Impression.last.session_hash.size.should eq 32
44
+ Impression.last.referrer.should eq nil
45
+ end
46
+
47
+ it "should log the referrer when you click a link" do
48
+ visit article_url(Article.first)
49
+ click_link "Same Page"
50
+ Impression.last.referrer.should eq "http://test.host/articles/1"
51
+ end
52
+ end
53
+
54
+ describe PostsController do
55
+ it "should log impression at the action level" do
56
+ get "show", :id=> 1
57
+ Impression.all.size.should eq 12
58
+ Impression.last.controller_name.should eq "posts"
59
+ Impression.last.action_name.should eq "show"
60
+ Impression.last.impressionable_type.should eq "Post"
61
+ Impression.last.impressionable_id.should eq 1
62
+ end
63
+
64
+ it "should log the user_id if user is authenticated (current_user helper method)" do
65
+ session[:user_id] = 123
66
+ get "show", :id=> 1
67
+ Post.first.impressions.last.user_id.should eq 123
68
+ end
69
+ end
70
+
71
+ describe WidgetsController do
72
+
73
+ before(:each) do
74
+ @widget = Widget.find(1)
75
+ Widget.stub(:find).and_return(@widget)
76
+ end
77
+
78
+ it "should log impression at the per action level" do
79
+ get "show", :id=> 1
80
+ Impression.all.size.should eq 12
81
+ get "index"
82
+ Impression.all.size.should eq 13
83
+ get "new"
84
+ Impression.all.size.should eq 13
85
+ end
86
+
87
+ it "should not log impression when user-agent is in wildcard list" do
88
+ request.stub!(:user_agent).and_return('somebot')
89
+ get "show", :id=> 1
90
+ Impression.all.size.should eq 11
91
+ end
92
+
93
+ it "should not log impression when user-agent is in the bot list" do
94
+ request.stub!(:user_agent).and_return('Acoon Robot v1.50.001')
95
+ get "show", :id=> 1
96
+ Impression.all.size.should eq 11
97
+ end
98
+
99
+ describe "impressionist unique options" do
100
+
101
+ it "should log unique impressions at the per action level" do
102
+ get "show", :id=> 1
103
+ Impression.all.size.should eq 12
104
+ get "show", :id=> 2
105
+ Impression.all.size.should eq 13
106
+ get "show", :id => 2
107
+ Impression.all.size.should eq 13
108
+ get "index"
109
+ Impression.all.size.should eq 14
110
+ end
111
+
112
+ it "should log unique impressions only once per id" do
113
+ get "show", :id=> 1
114
+ Impression.all.size.should eq 12
115
+ get "show", :id=> 2
116
+ Impression.all.size.should eq 13
117
+ get "show", :id => 2
118
+ Impression.all.size.should eq 13
119
+ get "index"
120
+ Impression.all.size.should eq 14
121
+ end
122
+
123
+ end
124
+
125
+ end
@@ -0,0 +1,310 @@
1
+ require 'spec_helper'
2
+
3
+ # we use the posts controller as it uses the impressionsist module. any such controller would do.
4
+ describe DummyController do
5
+
6
+ before do
7
+ @impression_count = Impression.all.size
8
+ end
9
+
10
+ describe "impressionist filter uniqueness" do
11
+
12
+ it "should ignore uniqueness if not requested" do
13
+ controller.impressionist_subapp_filter(nil, nil)
14
+ controller.impressionist_subapp_filter(nil, nil)
15
+ Impression.should have(@impression_count + 2).records
16
+ end
17
+
18
+ it "should recognize unique session" do
19
+ controller.stub!(:session_hash).and_return(request.session_options[:id])
20
+ controller.impressionist_subapp_filter(nil, [:session_hash])
21
+ controller.impressionist_subapp_filter(nil, [:session_hash])
22
+ Impression.should have(@impression_count + 1).records
23
+ end
24
+
25
+ it "should recognize unique ip" do
26
+ controller.request.stub!(:remote_ip).and_return("1.2.3.4")
27
+ controller.impressionist_subapp_filter(nil, [:ip_address])
28
+ controller.impressionist_subapp_filter(nil, [:ip_address])
29
+ Impression.should have(@impression_count + 1).records
30
+ end
31
+
32
+ it "should recognize unique request" do
33
+ controller.impressionist_subapp_filter(nil, [:request_hash])
34
+ controller.impressionist_subapp_filter(nil, [:request_hash])
35
+ Impression.should have(@impression_count + 1).records
36
+ end
37
+
38
+ it "should recognize unique action" do
39
+ controller.stub!(:action_name).and_return("test_action")
40
+ controller.impressionist_subapp_filter(nil, [:action_name])
41
+ controller.impressionist_subapp_filter(nil, [:action_name])
42
+ Impression.should have(@impression_count + 1).records
43
+ end
44
+
45
+ it "should recognize unique controller" do
46
+ controller.stub!(:controller_name).and_return("post")
47
+ controller.impressionist_subapp_filter(nil, [:controller_name])
48
+ controller.impressionist_subapp_filter(nil, [:controller_name])
49
+ Impression.should have(@impression_count + 1).records
50
+ end
51
+
52
+ it "should recognize unique user" do
53
+ controller.stub!(:user_id).and_return(42)
54
+ controller.impressionist_subapp_filter(nil, [:user_id])
55
+ controller.impressionist_subapp_filter(nil, [:user_id])
56
+ Impression.should have(@impression_count + 1).records
57
+ end
58
+
59
+ it "should recognize unique referer" do
60
+ controller.request.stub!(:referer).and_return("http://foo/bar")
61
+ controller.impressionist_subapp_filter(nil, [:referrer])
62
+ controller.impressionist_subapp_filter(nil, [:referrer])
63
+ Impression.should have(@impression_count + 1).records
64
+ end
65
+
66
+ it "should recognize unique id" do
67
+ controller.stub!(:params).and_return({:id => "666"}) # for correct impressionable id in filter
68
+ controller.impressionist_subapp_filter(nil, [:impressionable_id])
69
+ controller.impressionist_subapp_filter(nil, [:impressionable_id])
70
+ Impression.should have(@impression_count + 1).records
71
+ end
72
+
73
+ # extra redundant test for important controller and action combination.
74
+ it "should recognize different controller and action" do
75
+ controller.stub!(:controller_name).and_return("post")
76
+ controller.stub!(:action_name).and_return("test_action")
77
+ controller.impressionist_subapp_filter(nil, [:controller_name, :action_name])
78
+ controller.impressionist_subapp_filter(nil, [:controller_name, :action_name])
79
+ Impression.should have(@impression_count + 1).records
80
+ controller.stub!(:action_name).and_return("another_action")
81
+ controller.impressionist_subapp_filter(nil, [:controller_name, :action_name])
82
+ controller.impressionist_subapp_filter(nil, [:controller_name, :action_name])
83
+ Impression.should have(@impression_count + 2).records
84
+ controller.stub!(:controller_name).and_return("article")
85
+ controller.impressionist_subapp_filter(nil, [:controller_name, :action_name])
86
+ controller.impressionist_subapp_filter(nil, [:controller_name, :action_name])
87
+ Impression.should have(@impression_count + 3).records
88
+ end
89
+
90
+ it "should recognize different action" do
91
+ controller.stub!(:action_name).and_return("test_action")
92
+ controller.impressionist_subapp_filter(nil, [:action_name])
93
+ controller.impressionist_subapp_filter(nil, [:action_name])
94
+ Impression.should have(@impression_count + 1).records
95
+ controller.stub!(:action_name).and_return("another_action")
96
+ controller.impressionist_subapp_filter(nil, [:action_name])
97
+ controller.impressionist_subapp_filter(nil, [:action_name])
98
+ Impression.should have(@impression_count + 2).records
99
+ end
100
+
101
+ it "should recognize different controller" do
102
+ controller.stub!(:controller_name).and_return("post")
103
+ controller.impressionist_subapp_filter(nil, [:controller_name])
104
+ controller.impressionist_subapp_filter(nil, [:controller_name])
105
+ Impression.should have(@impression_count + 1).records
106
+ controller.stub!(:controller_name).and_return("article")
107
+ controller.impressionist_subapp_filter(nil, [:controller_name])
108
+ controller.impressionist_subapp_filter(nil, [:controller_name])
109
+ Impression.should have(@impression_count + 2).records
110
+ end
111
+
112
+ it "should recognize different session" do
113
+ controller.stub!(:session_hash).and_return("foo")
114
+ controller.impressionist_subapp_filter(nil, [:session_hash])
115
+ controller.impressionist_subapp_filter(nil, [:session_hash])
116
+ Impression.should have(@impression_count + 1).records
117
+ controller.stub!(:session_hash).and_return("bar")
118
+ controller.impressionist_subapp_filter(nil, [:session_hash])
119
+ controller.impressionist_subapp_filter(nil, [:session_hash])
120
+ Impression.should have(@impression_count + 2).records
121
+ end
122
+
123
+ it "should recognize different ip" do
124
+ controller.request.stub!(:remote_ip).and_return("1.2.3.4")
125
+ controller.impressionist_subapp_filter(nil, [:ip_address])
126
+ controller.impressionist_subapp_filter(nil, [:ip_address])
127
+ Impression.should have(@impression_count + 1).records
128
+ controller.request.stub!(:remote_ip).and_return("5.6.7.8")
129
+ controller.impressionist_subapp_filter(nil, [:ip_address])
130
+ controller.impressionist_subapp_filter(nil, [:ip_address])
131
+ Impression.should have(@impression_count + 2).records
132
+ end
133
+
134
+ it "should recognize different referer" do
135
+ controller.request.stub!(:referer).and_return("http://foo/bar")
136
+ controller.impressionist_subapp_filter(nil, [:referrer])
137
+ controller.impressionist_subapp_filter(nil, [:referrer])
138
+ Impression.should have(@impression_count + 1).records
139
+ controller.request.stub!(:referer).and_return("http://bar/fo")
140
+ controller.impressionist_subapp_filter(nil, [:referrer])
141
+ controller.impressionist_subapp_filter(nil, [:referrer])
142
+ Impression.should have(@impression_count + 2).records
143
+ end
144
+
145
+ it "should recognize different id" do
146
+ controller.stub!(:params).and_return({:id => "666"}) # for correct impressionable id in filter
147
+ controller.impressionist_subapp_filter(nil, [:impressionable_type, :impressionable_id])
148
+ controller.impressionist_subapp_filter(nil, [:impressionable_type, :impressionable_id])
149
+ controller.stub!(:params).and_return({:id => "42"}) # for correct impressionable id in filter
150
+ controller.impressionist_subapp_filter(nil, [:impressionable_type, :impressionable_id])
151
+ controller.impressionist_subapp_filter(nil, [:impressionable_type, :impressionable_id])
152
+ Impression.should have(@impression_count + 2).records
153
+ end
154
+
155
+ it "should recognize combined uniqueness" do
156
+ controller.stub!(:action_name).and_return("test_action")
157
+ controller.impressionist_subapp_filter(nil, [:ip_address, :request_hash, :action_name])
158
+ controller.impressionist_subapp_filter(nil, [:request_hash, :ip_address, :action_name])
159
+ controller.impressionist_subapp_filter(nil, [:request_hash, :action_name])
160
+ controller.impressionist_subapp_filter(nil, [:ip_address, :action_name])
161
+ controller.impressionist_subapp_filter(nil, [:ip_address, :request_hash])
162
+ controller.impressionist_subapp_filter(nil, [:action_name])
163
+ controller.impressionist_subapp_filter(nil, [:ip_address])
164
+ controller.impressionist_subapp_filter(nil, [:request_hash])
165
+ Impression.should have(@impression_count + 1).records
166
+ end
167
+
168
+ it "should recognize combined non-uniqueness" do
169
+ controller.stub!(:action_name).and_return(nil)
170
+ controller.impressionist_subapp_filter(nil, [:ip_address, :action_name])
171
+ controller.stub!(:action_name).and_return("test_action")
172
+ controller.impressionist_subapp_filter(nil, [:ip_address, :action_name])
173
+ controller.stub!(:action_name).and_return("another_action")
174
+ controller.impressionist_subapp_filter(nil, [:ip_address, :action_name])
175
+ Impression.should have(@impression_count + 3).records
176
+ end
177
+
178
+ end
179
+
180
+ describe "impressionist method uniqueness for impressionables" do
181
+
182
+ # in this test we reuse the post model. might break if model changes.
183
+
184
+ it "should ignore uniqueness if not requested" do
185
+ impressionable = Post.create
186
+ controller.impressionist impressionable
187
+ controller.impressionist impressionable
188
+ Impression.should have(@impression_count + 2).records
189
+ end
190
+
191
+ it "should recognize unique session" do
192
+ controller.stub!(:session_hash).and_return(request.session_options[:id])
193
+ impressionable = Post.create
194
+ controller.impressionist(impressionable, nil, :unique => [:session_hash])
195
+ controller.impressionist(impressionable, nil, :unique => [:session_hash])
196
+ Impression.should have(@impression_count + 1).records
197
+ end
198
+
199
+ it "should recognize unique ip" do
200
+ controller.request.stub!(:remote_ip).and_return("1.2.3.4")
201
+ impressionable = Post.create
202
+ controller.impressionist(impressionable, nil, :unique => [:ip_address])
203
+ controller.impressionist(impressionable, nil, :unique => [:ip_address])
204
+ Impression.should have(@impression_count + 1).records
205
+ end
206
+
207
+ it "should recognize unique request" do
208
+ impressionable = Post.create
209
+ controller.impressionist(impressionable, nil, :unique => [:request_hash])
210
+ controller.impressionist(impressionable, nil, :unique => [:request_hash])
211
+ Impression.should have(@impression_count + 1).records
212
+ end
213
+
214
+ it "should recognize unique user" do
215
+ controller.stub!(:user_id).and_return(666)
216
+ impressionable = Post.create
217
+ controller.impressionist(impressionable, nil, :unique => [:user_id])
218
+ controller.impressionist(impressionable, nil, :unique => [:user_id])
219
+ Impression.should have(@impression_count + 1).records
220
+ end
221
+
222
+ it "should recognize unique referer" do
223
+ controller.request.stub!(:referer).and_return("http://foo/bar")
224
+ impressionable = Post.create
225
+ controller.impressionist(impressionable, nil, :unique => [:referrer])
226
+ controller.impressionist(impressionable, nil, :unique => [:referrer])
227
+ Impression.should have(@impression_count + 1).records
228
+ end
229
+
230
+ it "should recognize different session" do
231
+ impressionable = Post.create
232
+ controller.stub!(:session_hash).and_return("foo")
233
+ controller.impressionist(impressionable, nil, :unique => [:session_hash])
234
+ controller.impressionist(impressionable, nil, :unique => [:session_hash])
235
+ Impression.should have(@impression_count + 1).records
236
+ controller.stub!(:session_hash).and_return("bar")
237
+ controller.impressionist(impressionable, nil, :unique => [:session_hash])
238
+ controller.impressionist(impressionable, nil, :unique => [:session_hash])
239
+ Impression.should have(@impression_count + 2).records
240
+ end
241
+
242
+ it "should recognize different ip" do
243
+ controller.request.stub!(:remote_ip).and_return("1.2.3.4")
244
+ impressionable = Post.create
245
+ controller.impressionist(impressionable, nil, :unique => [:ip_address])
246
+ controller.impressionist(impressionable, nil, :unique => [:ip_address])
247
+ Impression.should have(@impression_count + 1).records
248
+ controller.request.stub!(:remote_ip).and_return("5.6.7.8")
249
+ controller.impressionist(impressionable, nil, :unique => [:ip_address])
250
+ controller.impressionist(impressionable, nil, :unique => [:ip_address])
251
+ Impression.should have(@impression_count + 2).records
252
+ end
253
+
254
+ it "should recognize different user" do
255
+ impressionable = Post.create
256
+ controller.stub!(:user_id).and_return(666)
257
+ controller.impressionist(impressionable, nil, :unique => [:user_id])
258
+ controller.impressionist(impressionable, nil, :unique => [:user_id])
259
+ Impression.should have(@impression_count + 1).records
260
+ controller.stub!(:user_id).and_return(42)
261
+ controller.impressionist(impressionable, nil, :unique => [:user_id])
262
+ controller.impressionist(impressionable, nil, :unique => [:user_id])
263
+ Impression.should have(@impression_count + 2).records
264
+ end
265
+
266
+ it "should recognize combined uniqueness" do
267
+ impressionable = Post.create
268
+ controller.stub!(:session_hash).and_return("foo")
269
+ controller.impressionist(impressionable, nil, :unique => [:ip_address, :request_hash, :session_hash])
270
+ controller.impressionist(impressionable, nil, :unique => [:request_hash, :ip_address, :session_hash])
271
+ controller.impressionist(impressionable, nil, :unique => [:request_hash, :session_hash])
272
+ controller.impressionist(impressionable, nil, :unique => [:ip_address, :session_hash])
273
+ controller.impressionist(impressionable, nil, :unique => [:ip_address, :request_hash])
274
+ controller.impressionist(impressionable, nil, :unique => [:session_hash])
275
+ controller.impressionist(impressionable, nil, :unique => [:ip_address])
276
+ controller.impressionist(impressionable, nil, :unique => [:request_hash])
277
+ Impression.should have(@impression_count + 1).records
278
+ end
279
+
280
+ it "should recognize combined non-uniqueness" do
281
+ impressionable = Post.create
282
+ controller.stub!(:session_hash).and_return(nil)
283
+ controller.impressionist(impressionable, nil, :unique => [:ip_address, :session_hash])
284
+ controller.stub!(:session_hash).and_return("foo")
285
+ controller.impressionist(impressionable, nil, :unique => [:ip_address, :session_hash])
286
+ controller.stub!(:session_hash).and_return("bar")
287
+ controller.impressionist(impressionable, nil, :unique => [:ip_address, :session_hash])
288
+ Impression.should have(@impression_count + 3).records
289
+ end
290
+
291
+ end
292
+
293
+ describe "impressionist filter and method uniqueness" do
294
+
295
+ it "should recognize uniqueness" do
296
+ impressionable = Post.create
297
+ controller.stub!(:controller_name).and_return("posts") # for correct impressionable type in filter
298
+ controller.stub!(:params).and_return({:id => impressionable.id.to_s}) # for correct impressionable id in filter
299
+ controller.stub!(:session_hash).and_return("foo")
300
+ controller.request.stub!(:remote_ip).and_return("1.2.3.4")
301
+ # order of the following methods is important for the test!
302
+ controller.impressionist_subapp_filter(nil, [:ip_address, :request_hash, :session_hash])
303
+ controller.impressionist(impressionable, nil, :unique => [:ip_address, :request_hash, :session_hash])
304
+ Impression.should have(@impression_count + 1).records
305
+ end
306
+
307
+ end
308
+
309
+ end
310
+