vanity 1.9.3 → 2.0.0.beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. data/.gitignore +0 -1
  2. data/.travis.yml +2 -53
  3. data/Appraisals +3 -12
  4. data/CHANGELOG +1 -5
  5. data/Gemfile +0 -10
  6. data/Gemfile.lock +3 -38
  7. data/README.rdoc +2 -13
  8. data/Rakefile +7 -13
  9. data/bin/vanity +0 -1
  10. data/doc/rails.textile +0 -12
  11. data/gemfiles/rails32.gemfile +2 -4
  12. data/gemfiles/rails32.gemfile.lock +6 -14
  13. data/gemfiles/rails4.gemfile +1 -4
  14. data/gemfiles/rails4.gemfile.lock +5 -15
  15. data/lib/vanity/adapters/active_record_adapter.rb +14 -10
  16. data/lib/vanity/experiment/ab_test.rb +1 -1
  17. data/lib/vanity/frameworks/rails.rb +11 -17
  18. data/lib/vanity/frameworks.rb +3 -10
  19. data/lib/vanity/metric/active_record.rb +20 -19
  20. data/lib/vanity/playground.rb +1 -3
  21. data/lib/vanity/version.rb +1 -1
  22. data/test/adapters/redis_adapter_test.rb +26 -27
  23. data/test/autoconnect_test.rb +19 -17
  24. data/test/cli_test.rb +19 -26
  25. data/test/experiment/ab_test.rb +2 -15
  26. data/test/experiment/base_test.rb +18 -22
  27. data/test/frameworks/rails/action_controller_test.rb +184 -0
  28. data/test/frameworks/rails/action_mailer_test.rb +65 -0
  29. data/test/{rails_helper_test.rb → frameworks/rails/action_view_test.rb} +1 -1
  30. data/test/frameworks/rails/rails_test.rb +285 -0
  31. data/test/helper_test.rb +13 -10
  32. data/test/metric/active_record_test.rb +50 -66
  33. data/test/metric/base_test.rb +39 -41
  34. data/test/metric/google_analytics_test.rb +13 -16
  35. data/test/metric/remote_test.rb +18 -19
  36. data/test/playground_test.rb +1 -1
  37. data/test/test_helper.rb +25 -43
  38. data/test/{rails_dashboard_test.rb → web/rails/dashboard_test.rb} +2 -1
  39. data/vanity.gemspec +3 -2
  40. metadata +33 -33
  41. data/gemfiles/rails3.gemfile +0 -32
  42. data/gemfiles/rails3.gemfile.lock +0 -172
  43. data/gemfiles/rails31.gemfile +0 -32
  44. data/gemfiles/rails31.gemfile.lock +0 -181
  45. data/generators/templates/vanity_migration.rb +0 -54
  46. data/generators/vanity_generator.rb +0 -8
  47. data/test/myapp/app/controllers/application_controller.rb +0 -2
  48. data/test/myapp/app/controllers/main_controller.rb +0 -7
  49. data/test/myapp/config/boot.rb +0 -110
  50. data/test/myapp/config/environment.rb +0 -10
  51. data/test/myapp/config/environments/production.rb +0 -0
  52. data/test/myapp/config/routes.rb +0 -3
  53. data/test/passenger_test.rb +0 -52
  54. data/test/rails_test.rb +0 -554
data/test/rails_test.rb DELETED
@@ -1,554 +0,0 @@
1
- require "test/test_helper"
2
-
3
- class UseVanityController < ActionController::Base
4
- attr_accessor :current_user
5
-
6
- def index
7
- render :text=>ab_test(:pie_or_cake)
8
- end
9
-
10
- def js
11
- ab_test(:pie_or_cake)
12
- render :inline => "<%= vanity_js -%>"
13
- end
14
- end
15
-
16
- # Pages accessible to everyone, e.g. sign in, community search.
17
- class UseVanityControllerTest < ActionController::TestCase
18
- tests UseVanityController
19
-
20
- def setup
21
- super
22
- metric :sugar_high
23
- new_ab_test :pie_or_cake do
24
- metrics :sugar_high
25
- end
26
- UseVanityController.class_eval do
27
- use_vanity :current_user
28
- end
29
- if ::Rails.respond_to?(:application) # Rails 3 configuration
30
- ::Rails.application.config.session_options[:domain] = '.foo.bar'
31
- end
32
- end
33
-
34
- def test_render_js_for_tests
35
- Vanity.playground.use_js!
36
- get :js
37
- assert_match /script.*e=pie_or_cake.*script/m, @response.body
38
- end
39
-
40
- def test_chooses_sets_alternatives_for_rails_tests
41
- experiment(:pie_or_cake).chooses(true)
42
- get :index
43
- assert_equal 'true', @response.body
44
-
45
- experiment(:pie_or_cake).chooses(false)
46
- get :index
47
- assert_equal 'false', @response.body
48
- end
49
-
50
- def test_adds_participant_to_experiment
51
- get :index
52
- assert_equal 1, experiment(:pie_or_cake).alternatives.map(&:participants).sum
53
- end
54
-
55
- def test_does_not_add_invalid_participant_to_experiment
56
- @request.user_agent = "Googlebot/2.1 ( http://www.google.com/bot.html)"
57
- get :index
58
- assert_equal 0, experiment(:pie_or_cake).alternatives.map(&:participants).sum
59
- end
60
-
61
- def test_vanity_cookie_is_persistent
62
- get :index
63
- cookie = @response["Set-Cookie"].to_s
64
- assert_match /vanity_id=[a-f0-9]{32};/, cookie
65
- expires = cookie[/expires=(.*)(;|$)/, 1]
66
- assert expires
67
- assert_in_delta Time.parse(expires), Time.now + 1.month, 1.day
68
- end
69
-
70
- def test_vanity_cookie_default_id
71
- get :index
72
- assert cookies["vanity_id"] =~ /^[a-f0-9]{32}$/
73
- end
74
-
75
- def test_vanity_cookie_retains_id
76
- @request.cookies["vanity_id"] = "from_last_time"
77
- get :index
78
- # Rails 2 funkieness: if the cookie isn't explicitly set in the response,
79
- # cookies[] is empty. Just make sure it's not re-set.
80
- assert_equal rails3? ? "from_last_time" : nil, cookies["vanity_id"]
81
- end
82
-
83
- def test_vanity_identity_set_from_cookie
84
- @request.cookies["vanity_id"] = "from_last_time"
85
- get :index
86
- assert_equal "from_last_time", @controller.send(:vanity_identity)
87
- end
88
-
89
- def test_vanity_identity_set_from_user
90
- @controller.current_user = mock("user", :id=>"user_id")
91
- get :index
92
- assert_equal "user_id", @controller.send(:vanity_identity)
93
- end
94
-
95
- def test_vanity_identity_with_no_user_model
96
- UseVanityController.class_eval do
97
- use_vanity nil
98
- end
99
- @controller.current_user = Object.new
100
- get :index
101
- assert cookies["vanity_id"] =~ /^[a-f0-9]{32}$/
102
- end
103
-
104
- def test_vanity_identity_set_with_block
105
- UseVanityController.class_eval do
106
- attr_accessor :project_id
107
- use_vanity { |controller| controller.project_id }
108
- end
109
- @controller.project_id = "576"
110
- get :index
111
- assert_equal "576", @controller.send(:vanity_identity)
112
- end
113
-
114
- def test_vanity_identity_set_with_indentity_paramater
115
- get :index, :_identity => "id_from_params"
116
- assert_equal "id_from_params", @controller.send(:vanity_identity)
117
- end
118
-
119
- def test_vanity_identity_prefers_block_over_symbol
120
- UseVanityController.class_eval do
121
- attr_accessor :project_id
122
- use_vanity(:current_user) { |controller| controller.project_id }
123
- end
124
- @controller.project_id = "576"
125
- @controller.current_user = stub(:id=>"user_id")
126
-
127
- get :index
128
- assert_equal "576", @controller.send(:vanity_identity)
129
- end
130
-
131
- def test_vanity_identity_prefers_parameter_over_cookie
132
- @request.cookies['vanity_id'] = "old_id"
133
- get :index, :_identity => "id_from_params"
134
- assert_equal "id_from_params", @controller.send(:vanity_identity)
135
- assert cookies['vanity_id'], "id_from_params"
136
- end
137
-
138
- def test_vanity_identity_prefers_cookie_over_object
139
- @request.cookies['vanity_id'] = "from_last_time"
140
- @controller.current_user = stub(:id=>"user_id")
141
- get :index
142
- assert_equal "from_last_time", @controller.send(:vanity_identity)
143
- end
144
-
145
- # query parameter filter
146
-
147
- def test_redirects_and_loses_vanity_query_parameter
148
- get :index, :foo=>"bar", :_vanity=>"567"
149
- assert_redirected_to "/use_vanity?foo=bar"
150
- end
151
-
152
- def test_sets_choices_from_vanity_query_parameter
153
- first = experiment(:pie_or_cake).alternatives.first
154
- fingerprint = experiment(:pie_or_cake).fingerprint(first)
155
- 10.times do
156
- @controller = nil ; setup_controller_request_and_response
157
- get :index, :_vanity => fingerprint
158
- assert_equal experiment(:pie_or_cake).choose, experiment(:pie_or_cake).alternatives.first
159
- assert experiment(:pie_or_cake).showing?(first)
160
- end
161
- end
162
-
163
- def test_does_nothing_with_vanity_query_parameter_for_posts
164
- experiment(:pie_or_cake).chooses(experiment(:pie_or_cake).alternatives.last.value)
165
- first = experiment(:pie_or_cake).alternatives.first
166
- fingerprint = experiment(:pie_or_cake).fingerprint(first)
167
- post :index, :foo => "bar", :_vanity => fingerprint
168
- assert_response :success
169
- assert !experiment(:pie_or_cake).showing?(first)
170
- end
171
-
172
- def test_track_param_tracks_a_metric
173
- get :index, :_identity => "123", :_track => "sugar_high"
174
- assert_equal experiment(:pie_or_cake).alternatives[0].converted, 1
175
- end
176
-
177
- def test_cookie_domain_from_rails_configuration
178
- get :index
179
- assert_match /domain=.foo.bar/, @response["Set-Cookie"] if ::Rails.respond_to?(:application)
180
- end
181
-
182
- def teardown
183
- super
184
- if !rails3?
185
- UseVanityController.send(:filter_chain).clear
186
- end
187
- end
188
-
189
- end
190
-
191
- class VanityMailer < ActionMailer::Base
192
- include Vanity::Rails::Helpers
193
- include ActionView::Helpers::AssetTagHelper
194
- include ActionView::Helpers::TagHelper
195
-
196
- def ab_test_subject(user, forced_outcome=true)
197
- use_vanity_mailer user
198
- experiment(:pie_or_cake).chooses(forced_outcome)
199
-
200
- if defined?(Rails::Railtie)
201
- mail :subject =>ab_test(:pie_or_cake).to_s, :body => ""
202
- else
203
- subject ab_test(:pie_or_cake).to_s
204
- body ""
205
- end
206
- end
207
-
208
- def ab_test_content(user)
209
- use_vanity_mailer user
210
-
211
- if defined?(Rails::Railtie)
212
- mail do |format|
213
- format.html { render :text=>view_context.vanity_tracking_image(Vanity.context.vanity_identity, :open, :host => "127.0.0.1:3000") }
214
- end
215
- else
216
- body vanity_tracking_image(Vanity.context.vanity_identity, :open, :host => "127.0.0.1:3000")
217
- end
218
- end
219
- end
220
-
221
- class UseVanityMailerTest < ActionMailer::TestCase
222
- tests VanityMailer
223
-
224
- def setup
225
- super
226
- metric :sugar_high
227
- new_ab_test :pie_or_cake do
228
- metrics :sugar_high
229
- end
230
- end
231
-
232
- def test_js_enabled_still_adds_participant
233
- Vanity.playground.use_js!
234
- rails3? ? VanityMailer.ab_test_subject(nil, true) : VanityMailer.deliver_ab_test_subject(nil, true)
235
-
236
- alts = experiment(:pie_or_cake).alternatives
237
- assert_equal 1, alts.map(&:participants).sum
238
- end
239
-
240
- def test_returns_different_alternatives
241
- email = rails3? ? VanityMailer.ab_test_subject(nil, true) : VanityMailer.deliver_ab_test_subject(nil, true)
242
- assert_equal 'true', email.subject
243
-
244
- email = rails3? ? VanityMailer.ab_test_subject(nil, false) : VanityMailer.deliver_ab_test_subject(nil, false)
245
- assert_equal 'false', email.subject
246
- end
247
-
248
- def test_tracking_image_is_rendered
249
- email = rails3? ? VanityMailer.ab_test_content(nil) : VanityMailer.deliver_ab_test_content(nil)
250
- assert email.body =~ /<img/
251
- assert email.body =~ /_identity=/
252
- end
253
- end
254
-
255
- class LoadPathAndConnectionConfigurationTest < Test::Unit::TestCase
256
-
257
- def test_load_path
258
- assert_equal File.expand_path("tmp/experiments"), load_rails("", <<-RB)
259
- $stdout << Vanity.playground.load_path
260
- RB
261
- end
262
-
263
- def test_settable_load_path
264
- assert_equal File.expand_path("tmp/predictions"), load_rails(%Q{\nVanity.playground.load_path = "predictions"\n}, <<-RB)
265
- $stdout << Vanity.playground.load_path
266
- RB
267
- end
268
-
269
- def test_absolute_load_path
270
- Dir.mktmpdir do |dir|
271
- assert_equal dir, load_rails(%Q{\nVanity.playground.load_path = "#{dir}"\n}, <<-RB)
272
- $stdout << Vanity.playground.load_path
273
- RB
274
- end
275
- end
276
-
277
- if ENV['DB'] == 'redis'
278
- def test_default_connection
279
- assert_equal "redis://127.0.0.1:6379/0", load_rails("", <<-RB)
280
- $stdout << Vanity.playground.connection
281
- RB
282
- end
283
-
284
- def test_connection_from_string
285
- assert_equal "redis://192.168.1.1:6379/5", load_rails(%Q{\nVanity.playground.establish_connection "redis://192.168.1.1:6379/5"\n}, <<-RB)
286
- $stdout << Vanity.playground.connection
287
- RB
288
- end
289
-
290
- def test_connection_from_yaml
291
- FileUtils.mkpath "tmp/config"
292
- @original_env = ENV["RAILS_ENV"]
293
- ENV["RAILS_ENV"] = "production"
294
- File.open("tmp/config/vanity.yml", "w") do |io|
295
- io.write <<-YML
296
- production:
297
- adapter: redis
298
- host: somehost
299
- database: 15
300
- YML
301
- end
302
- assert_equal "redis://somehost:6379/15", load_rails("", <<-RB)
303
- $stdout << Vanity.playground.connection
304
- RB
305
- ensure
306
- ENV["RAILS_ENV"] = @original_env
307
- File.unlink "tmp/config/vanity.yml"
308
- end
309
-
310
- def test_connection_from_yaml_url
311
- FileUtils.mkpath "tmp/config"
312
- @original_env = ENV["RAILS_ENV"]
313
- ENV["RAILS_ENV"] = "production"
314
- File.open("tmp/config/vanity.yml", "w") do |io|
315
- io.write <<-YML
316
- production: redis://somehost/15
317
- YML
318
- end
319
- assert_equal "redis://somehost:6379/15", load_rails("", <<-RB)
320
- $stdout << Vanity.playground.connection
321
- RB
322
- ensure
323
- ENV["RAILS_ENV"] = @original_env
324
- File.unlink "tmp/config/vanity.yml"
325
- end
326
-
327
- def test_connection_from_yaml_with_erb
328
- FileUtils.mkpath "tmp/config"
329
- @original_env = ENV["RAILS_ENV"]
330
- ENV["RAILS_ENV"] = "production"
331
- # Pass storage URL through environment like heroku does
332
- @original_redis_url = ENV["REDIS_URL"]
333
- ENV["REDIS_URL"] = "redis://somehost:6379/15"
334
- File.open("tmp/config/vanity.yml", "w") do |io|
335
- io.write <<-YML
336
- production: <%= ENV['REDIS_URL'] %>
337
- YML
338
- end
339
- assert_equal "redis://somehost:6379/15", load_rails("", <<-RB)
340
- $stdout << Vanity.playground.connection
341
- RB
342
- ensure
343
- ENV["RAILS_ENV"] = @original_env
344
- ENV["REDIS_URL"] = @original_redis_url
345
- File.unlink "tmp/config/vanity.yml"
346
- end
347
-
348
- def test_connection_from_redis_yml
349
- FileUtils.mkpath "tmp/config"
350
- yml = File.open("tmp/config/redis.yml", "w")
351
- yml << "production: internal.local:6379\n"
352
- yml.flush
353
- assert_equal "redis://internal.local:6379/0", load_rails("", <<-RB)
354
- $stdout << Vanity.playground.connection
355
- RB
356
- ensure
357
- File.unlink yml.path
358
- end
359
- end
360
-
361
- if ENV['DB'] == 'mongo'
362
- def test_mongo_connection_from_yaml
363
- FileUtils.mkpath "tmp/config"
364
- File.open("tmp/config/vanity.yml", "w") do |io|
365
- io.write <<-YML
366
- mongodb:
367
- adapter: mongodb
368
- host: localhost
369
- port: 27017
370
- database: vanity_test
371
- YML
372
- end
373
-
374
- assert_equal "mongodb://localhost:27017/vanity_test", load_rails("", <<-RB, "mongodb")
375
- $stdout << Vanity.playground.connection
376
- RB
377
- ensure
378
- File.unlink "tmp/config/vanity.yml"
379
- end
380
-
381
- unless ENV['CI'] == 'true' #TODO this doesn't get tested on CI
382
- def test_mongodb_replica_set_connection
383
- FileUtils.mkpath "tmp/config"
384
- File.open("tmp/config/vanity.yml", "w") do |io|
385
- io.write <<-YML
386
- mongodb:
387
- adapter: mongodb
388
- hosts:
389
- - localhost
390
- port: 27017
391
- database: vanity_test
392
- YML
393
- end
394
-
395
- assert_equal "mongodb://localhost:27017/vanity_test", load_rails("", <<-RB, "mongodb")
396
- $stdout << Vanity.playground.connection
397
- RB
398
-
399
- assert_equal "Mongo::ReplSetConnection", load_rails("", <<-RB, "mongodb")
400
- $stdout << Vanity.playground.connection.mongo.class
401
- RB
402
- ensure
403
- File.unlink "tmp/config/vanity.yml"
404
- end
405
- end
406
- end
407
-
408
- def test_connection_from_yaml_missing
409
- FileUtils.mkpath "tmp/config"
410
- File.open("tmp/config/vanity.yml", "w") do |io|
411
- io.write <<-YML
412
- production:
413
- adapter: redis
414
- YML
415
- end
416
-
417
- assert_equal "No configuration for development", load_rails("\nbegin\n", <<-RB, "development")
418
- rescue RuntimeError => e
419
- $stdout << e.message
420
- end
421
- RB
422
- ensure
423
- File.unlink "tmp/config/vanity.yml"
424
- end
425
-
426
- def test_collection_from_vanity_yaml
427
- FileUtils.mkpath "tmp/config"
428
- File.open("tmp/config/vanity.yml", "w") do |io|
429
- io.write <<-YML
430
- production:
431
- collecting: false
432
- adapter: mock
433
- YML
434
- end
435
- assert_equal "false", load_rails("", <<-RB)
436
- $stdout << Vanity.playground.collecting?
437
- RB
438
- ensure
439
- File.unlink "tmp/config/vanity.yml"
440
- end
441
-
442
- def test_collection_true_in_production_by_default
443
- assert_equal "true", load_rails("", <<-RB)
444
- $stdout << Vanity.playground.collecting?
445
- RB
446
- end
447
-
448
- def test_collection_false_in_production_when_configured
449
- assert_equal "false", load_rails("\nVanity.playground.collecting = false\n", <<-RB)
450
- $stdout << Vanity.playground.collecting?
451
- RB
452
- end
453
-
454
- def test_collection_true_in_development_by_default
455
- assert_equal "true", load_rails("", <<-RB, "development")
456
- $stdout << Vanity.playground.collecting?
457
- RB
458
- end
459
-
460
- def test_collection_true_in_development_when_configured
461
- assert_equal "true", load_rails("\nVanity.playground.collecting = true\n", <<-RB, "development")
462
- $stdout << Vanity.playground.collecting?
463
- RB
464
- end
465
-
466
- def test_collection_false_after_test!
467
- assert_equal "false", load_rails("", <<-RB)
468
- Vanity.playground.test!
469
- $stdout << Vanity.playground.collecting?
470
- RB
471
- end
472
-
473
- def test_playground_loads_if_connected
474
- assert_equal "{}", load_rails("", <<-RB)
475
- $stdout << Vanity.playground.instance_variable_get(:@experiments).inspect
476
- RB
477
- end
478
-
479
- def test_playground_does_not_load_if_not_connected
480
- ENV['VANITY_DISABLED'] = '1'
481
- assert_equal "nil", load_rails("", <<-RB)
482
- $stdout << Vanity.playground.instance_variable_get(:@experiments).inspect
483
- RB
484
- ENV['VANITY_DISABLED'] = nil
485
- end
486
-
487
- def load_rails(before_initialize, after_initialize, env="production")
488
- tmp = Tempfile.open("test.rb")
489
- begin
490
- code_setup = <<-RB
491
- $:.delete_if { |path| path[/gems\\/vanity-\\d/] }
492
- $:.unshift File.expand_path("../lib")
493
- RAILS_ROOT = File.expand_path(".")
494
- RB
495
- code = code_setup
496
- code += defined?(Rails::Railtie) ? load_rails_3_or_4(env) : load_rails_2(env)
497
- code += %Q{\nrequire "vanity"\n}
498
- code += before_initialize
499
- code += defined?(Rails::Railtie) ? initialize_rails_3_or_4 : initialize_rails_2
500
- code += after_initialize
501
- tmp.write code
502
- tmp.flush
503
- Dir.chdir "tmp" do
504
- open("| ruby #{tmp.path}").read
505
- end
506
- ensure
507
- tmp.close!
508
- end
509
- end
510
-
511
- def load_rails_2(env)
512
- <<-RB
513
- RAILS_ENV = ENV['RACK_ENV'] = "#{env}"
514
- require "initializer"
515
- require "active_support"
516
- Rails.configuration = Rails::Configuration.new
517
- initializer = Rails::Initializer.new(Rails.configuration)
518
- initializer.check_gem_dependencies
519
- RB
520
- end
521
-
522
- def load_rails_3_or_4(env)
523
- <<-RB
524
- ENV['BUNDLE_GEMFILE'] ||= "#{ENV['BUNDLE_GEMFILE']}"
525
- require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
526
- ENV['RAILS_ENV'] = ENV['RACK_ENV'] = "#{env}"
527
- require "active_model/railtie"
528
- require "action_controller/railtie"
529
-
530
- Bundler.require(:default)
531
-
532
- module Foo
533
- class Application < Rails::Application
534
- config.active_support.deprecation = :notify
535
- config.eager_load = #{env == "production"} if Rails::Application.respond_to?(:eager_load!)
536
- ActiveSupport::Deprecation.silenced = true if ActiveSupport::Deprecation.respond_to?(:silenced) && ENV['CI']
537
- end
538
- end
539
- RB
540
- end
541
-
542
- def initialize_rails_2
543
- <<-RB
544
- initializer.after_initialize
545
- RB
546
- end
547
-
548
- def initialize_rails_3_or_4
549
- <<-RB
550
- Foo::Application.initialize!
551
- RB
552
- end
553
-
554
- end