moses-vanity 1.7.1

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 (98) hide show
  1. data/.autotest +22 -0
  2. data/.gitignore +7 -0
  3. data/.rvmrc +3 -0
  4. data/.travis.yml +13 -0
  5. data/CHANGELOG +374 -0
  6. data/Gemfile +28 -0
  7. data/MIT-LICENSE +21 -0
  8. data/README.rdoc +108 -0
  9. data/Rakefile +189 -0
  10. data/bin/vanity +16 -0
  11. data/doc/_config.yml +2 -0
  12. data/doc/_layouts/_header.html +34 -0
  13. data/doc/_layouts/page.html +47 -0
  14. data/doc/_metrics.textile +12 -0
  15. data/doc/ab_testing.textile +210 -0
  16. data/doc/configuring.textile +45 -0
  17. data/doc/contributing.textile +93 -0
  18. data/doc/credits.textile +23 -0
  19. data/doc/css/page.css +83 -0
  20. data/doc/css/print.css +43 -0
  21. data/doc/css/syntax.css +7 -0
  22. data/doc/email.textile +129 -0
  23. data/doc/experimental.textile +31 -0
  24. data/doc/faq.textile +8 -0
  25. data/doc/identity.textile +43 -0
  26. data/doc/images/ab_in_dashboard.png +0 -0
  27. data/doc/images/clear_winner.png +0 -0
  28. data/doc/images/price_options.png +0 -0
  29. data/doc/images/sidebar_test.png +0 -0
  30. data/doc/images/signup_metric.png +0 -0
  31. data/doc/images/vanity.png +0 -0
  32. data/doc/index.textile +91 -0
  33. data/doc/metrics.textile +231 -0
  34. data/doc/rails.textile +89 -0
  35. data/doc/site.js +27 -0
  36. data/generators/templates/vanity_migration.rb +53 -0
  37. data/generators/vanity_generator.rb +8 -0
  38. data/lib/generators/templates/vanity_migration.rb +53 -0
  39. data/lib/generators/vanity_generator.rb +15 -0
  40. data/lib/vanity.rb +36 -0
  41. data/lib/vanity/adapters/abstract_adapter.rb +140 -0
  42. data/lib/vanity/adapters/active_record_adapter.rb +248 -0
  43. data/lib/vanity/adapters/mock_adapter.rb +157 -0
  44. data/lib/vanity/adapters/mongodb_adapter.rb +178 -0
  45. data/lib/vanity/adapters/redis_adapter.rb +160 -0
  46. data/lib/vanity/backport.rb +26 -0
  47. data/lib/vanity/commands/list.rb +21 -0
  48. data/lib/vanity/commands/report.rb +64 -0
  49. data/lib/vanity/commands/upgrade.rb +34 -0
  50. data/lib/vanity/experiment/ab_test.rb +507 -0
  51. data/lib/vanity/experiment/base.rb +214 -0
  52. data/lib/vanity/frameworks.rb +16 -0
  53. data/lib/vanity/frameworks/rails.rb +318 -0
  54. data/lib/vanity/helpers.rb +66 -0
  55. data/lib/vanity/images/x.gif +0 -0
  56. data/lib/vanity/metric/active_record.rb +85 -0
  57. data/lib/vanity/metric/base.rb +244 -0
  58. data/lib/vanity/metric/google_analytics.rb +83 -0
  59. data/lib/vanity/metric/remote.rb +53 -0
  60. data/lib/vanity/playground.rb +396 -0
  61. data/lib/vanity/templates/_ab_test.erb +28 -0
  62. data/lib/vanity/templates/_experiment.erb +5 -0
  63. data/lib/vanity/templates/_experiments.erb +7 -0
  64. data/lib/vanity/templates/_metric.erb +14 -0
  65. data/lib/vanity/templates/_metrics.erb +13 -0
  66. data/lib/vanity/templates/_report.erb +27 -0
  67. data/lib/vanity/templates/_vanity.js.erb +20 -0
  68. data/lib/vanity/templates/flot.min.js +1 -0
  69. data/lib/vanity/templates/jquery.min.js +19 -0
  70. data/lib/vanity/templates/vanity.css +26 -0
  71. data/lib/vanity/templates/vanity.js +82 -0
  72. data/lib/vanity/version.rb +11 -0
  73. data/test/adapters/redis_adapter_test.rb +17 -0
  74. data/test/experiment/ab_test.rb +771 -0
  75. data/test/experiment/base_test.rb +150 -0
  76. data/test/experiments/age_and_zipcode.rb +19 -0
  77. data/test/experiments/metrics/cheers.rb +3 -0
  78. data/test/experiments/metrics/signups.rb +2 -0
  79. data/test/experiments/metrics/yawns.rb +3 -0
  80. data/test/experiments/null_abc.rb +5 -0
  81. data/test/metric/active_record_test.rb +277 -0
  82. data/test/metric/base_test.rb +293 -0
  83. data/test/metric/google_analytics_test.rb +104 -0
  84. data/test/metric/remote_test.rb +109 -0
  85. data/test/myapp/app/controllers/application_controller.rb +2 -0
  86. data/test/myapp/app/controllers/main_controller.rb +7 -0
  87. data/test/myapp/config/boot.rb +110 -0
  88. data/test/myapp/config/environment.rb +10 -0
  89. data/test/myapp/config/environments/production.rb +0 -0
  90. data/test/myapp/config/routes.rb +3 -0
  91. data/test/passenger_test.rb +43 -0
  92. data/test/playground_test.rb +26 -0
  93. data/test/rails_dashboard_test.rb +37 -0
  94. data/test/rails_helper_test.rb +36 -0
  95. data/test/rails_test.rb +389 -0
  96. data/test/test_helper.rb +145 -0
  97. data/vanity.gemspec +26 -0
  98. metadata +202 -0
@@ -0,0 +1,293 @@
1
+ require "test/test_helper"
2
+
3
+
4
+ context "Metric via playground" do
5
+
6
+ test "knows all loaded metrics" do
7
+ metric "Yawns/sec", "Cheers/sec"
8
+ assert Vanity.playground.metrics.keys.include?(:yawns_sec)
9
+ assert Vanity.playground.metrics.keys.include?(:cheers_sec)
10
+ end
11
+
12
+ test "loads metric definitions" do
13
+ File.open "tmp/experiments/metrics/yawns_sec.rb", "w" do |f|
14
+ f.write <<-RUBY
15
+ metric "Yawns/sec" do
16
+ def xmts
17
+ "x"
18
+ end
19
+ end
20
+ RUBY
21
+ end
22
+ assert_equal "x", Vanity.playground.metric(:yawns_sec).xmts
23
+ end
24
+
25
+ test "bubbles up loaded metrics" do
26
+ File.open "tmp/experiments/metrics/yawns_sec.rb", "w" do |f|
27
+ f.write "fail 'yawn!'"
28
+ end
29
+ assert_raises NameError do
30
+ Vanity.playground.metric(:yawns_sec)
31
+ end
32
+ end
33
+
34
+ test "map identifier from file name" do
35
+ File.open "tmp/experiments/metrics/yawns_sec.rb", "w" do |f|
36
+ f.write <<-RUBY
37
+ metric "yawns/hour" do
38
+ end
39
+ RUBY
40
+ end
41
+ assert Vanity.playground.metric(:yawns_sec)
42
+ end
43
+
44
+ test "fails tracking unknown metric" do
45
+ assert_raises NameError do
46
+ Vanity.playground.track! :yawns_sec
47
+ end
48
+ end
49
+
50
+ test "reloading metrics" do
51
+ metric "Yawns/sec", "Cheers/sec"
52
+ Vanity.playground.metric(:yawns_sec)
53
+ Vanity.playground.metric(:cheers_sec)
54
+ assert_equal 2, Vanity.playground.metrics.size
55
+ metrics = Vanity.playground.metrics.values
56
+ Vanity.playground.reload!
57
+ assert_equal 0, Vanity.playground.metrics.size
58
+ assert_not_equal metrics, Vanity.playground.metrics.values
59
+ end
60
+
61
+ test "ignores undefined metrics in database" do
62
+ metric "Yawns/sec"
63
+ Vanity.playground.reload!
64
+ assert Vanity.playground.metrics.empty?
65
+ end
66
+
67
+ end
68
+
69
+
70
+ context "Metric tracking" do
71
+ test "disabled when metrics are disabled" do
72
+ not_collecting!
73
+ metric "Yawns/sec", "Cheers/sec"
74
+ Vanity.playground.track! :yawns_sec
75
+ Vanity.playground.track! :cheers_sec
76
+ end
77
+
78
+ test "can count" do
79
+ metric "Yawns/sec", "Cheers/sec"
80
+ 4.times { Vanity.playground.track! :yawns_sec }
81
+ 2.times { Vanity.playground.track! :cheers_sec }
82
+ yawns = Vanity.playground.metric(:yawns_sec).values(today, today).first
83
+ cheers = Vanity.playground.metric(:cheers_sec).values(today, today).first
84
+ assert yawns = 2 * cheers
85
+ end
86
+
87
+ test "can tell the time" do
88
+ metric "Yawns/sec"
89
+ Timecop.freeze(today - 4) { 4.times { Vanity.playground.track! :yawns_sec } }
90
+ Timecop.freeze(today - 2) { 2.times { Vanity.playground.track! :yawns_sec } }
91
+ 1.times { Vanity.playground.track! :yawns_sec }
92
+ boredom = Vanity.playground.metric(:yawns_sec).values(today - 5, today)
93
+ assert_equal [0,4,0,2,0,1], boredom
94
+ end
95
+
96
+ test "with no value" do
97
+ metric "Yawns/sec", "Cheers/sec", "Looks"
98
+ Vanity.playground.track! :yawns_sec, 0
99
+ Vanity.playground.track! :cheers_sec
100
+ assert_equal 0, Vanity.playground.metric(:yawns_sec).values(today, today).sum
101
+ assert_equal 1, Vanity.playground.metric(:cheers_sec).values(today, today).sum
102
+ end
103
+
104
+ test "with count" do
105
+ metric "Yawns/sec"
106
+ Timecop.freeze(today - 4) { Vanity.playground.track! :yawns_sec, 4 }
107
+ Timecop.freeze(today - 2) { Vanity.playground.track! :yawns_sec, 2 }
108
+ Vanity.playground.track! :yawns_sec
109
+ boredom = Vanity.playground.metric(:yawns_sec).values(today - 5, today)
110
+ assert_equal [0,4,0,2,0,1], boredom
111
+ end
112
+
113
+ test "runs hook" do
114
+ metric "Many Happy Returns"
115
+ total = 0
116
+ Vanity.playground.metric(:many_happy_returns).hook do |metric_id, timestamp, count|
117
+ assert_equal :many_happy_returns, metric_id
118
+ assert_in_delta Time.now.to_i, timestamp.to_i, 1
119
+ total += count
120
+ end
121
+ Vanity.playground.track! :many_happy_returns, 6
122
+ assert_equal 6, total
123
+ end
124
+
125
+ test "doesn't runs hook when metrics disabled" do
126
+ not_collecting!
127
+ metric "Many Happy Returns"
128
+ total = 0
129
+ Vanity.playground.metric(:many_happy_returns).hook do |metric_id, timestamp, count|
130
+ total += count
131
+ end
132
+ Vanity.playground.track! :many_happy_returns, 6
133
+ assert_equal 0, total
134
+ end
135
+
136
+ test "runs multiple hooks" do
137
+ metric "Many Happy Returns"
138
+ returns = 0
139
+ Vanity.playground.metric(:many_happy_returns).hook { returns += 1 }
140
+ Vanity.playground.metric(:many_happy_returns).hook { returns += 1 }
141
+ Vanity.playground.metric(:many_happy_returns).hook { returns += 1 }
142
+ Vanity.playground.track! :many_happy_returns
143
+ assert_equal 3, returns
144
+ end
145
+
146
+ test "destroy wipes metrics" do
147
+ metric "Many Happy Returns"
148
+ Vanity.playground.track! :many_happy_returns, 3
149
+ assert_equal [3], Vanity.playground.metric(:many_happy_returns).values(today, today)
150
+ Vanity.playground.metric(:many_happy_returns).destroy!
151
+ assert_equal [0], Vanity.playground.metric(:many_happy_returns).values(today, today)
152
+ end
153
+ end
154
+
155
+
156
+ context "Metric name" do
157
+ test "can be whatever" do
158
+ File.open "tmp/experiments/metrics/yawns_sec.rb", "w" do |f|
159
+ f.write <<-RUBY
160
+ metric "Yawns per second" do
161
+ end
162
+ RUBY
163
+ end
164
+ assert_equal "Yawns per second", Vanity.playground.metric(:yawns_sec).name
165
+ end
166
+ end
167
+
168
+
169
+ context "Metric description" do
170
+ test "metric with description" do
171
+ File.open "tmp/experiments/metrics/yawns_sec.rb", "w" do |f|
172
+ f.write <<-RUBY
173
+ metric "Yawns/sec" do
174
+ description "Am I that boring?"
175
+ end
176
+ RUBY
177
+ end
178
+ assert_equal "Am I that boring?", Vanity::Metric.description(Vanity.playground.metric(:yawns_sec))
179
+ end
180
+
181
+ test "metric without description" do
182
+ File.open "tmp/experiments/metrics/yawns_sec.rb", "w" do |f|
183
+ f.write <<-RUBY
184
+ metric "Yawns/sec" do
185
+ end
186
+ RUBY
187
+ end
188
+ assert_nil Vanity::Metric.description(Vanity.playground.metric(:yawns_sec))
189
+ end
190
+
191
+ test "metric with no method description" do
192
+ metric = Object.new
193
+ assert_nil Vanity::Metric.description(metric)
194
+ end
195
+ end
196
+
197
+
198
+ context "Metric bounds" do
199
+ test "metric with bounds" do
200
+ File.open "tmp/experiments/metrics/sky_is_limit.rb", "w" do |f|
201
+ f.write <<-RUBY
202
+ metric "Sky is limit" do
203
+ def bounds
204
+ [6,12]
205
+ end
206
+ end
207
+ RUBY
208
+ end
209
+ assert_equal [6,12], Vanity::Metric.bounds(Vanity.playground.metric(:sky_is_limit))
210
+ end
211
+
212
+ test "metric without bounds" do
213
+ metric "Sky is limit"
214
+ assert_equal [nil, nil], Vanity::Metric.bounds(Vanity.playground.metric(:sky_is_limit))
215
+ end
216
+
217
+ test "metric with no method bounds" do
218
+ metric = Object.new
219
+ assert_equal [nil, nil], Vanity::Metric.bounds(metric)
220
+ end
221
+ end
222
+
223
+
224
+ context "Metric last_update_at" do
225
+ test "for new metric" do
226
+ metric "Coolness"
227
+ metric = Vanity.playground.metric(:coolness)
228
+ assert_nil metric.last_update_at
229
+ end
230
+
231
+ test "with data point" do
232
+ metric "Coolness"
233
+ metric = Vanity.playground.metric(:coolness)
234
+ metric.track!
235
+ Timecop.freeze Time.now + 1.day do
236
+ metric.track!
237
+ end
238
+ assert_in_delta metric.last_update_at.to_i, (Time.now + 1.day).to_i, 1
239
+ end
240
+ end
241
+
242
+
243
+ context "Metric data" do
244
+ test "explicit dates" do
245
+ metric "Yawns/sec"
246
+ Timecop.freeze(today - 4) { Vanity.playground.track! :yawns_sec, 4 }
247
+ Timecop.freeze(today - 2) { Vanity.playground.track! :yawns_sec, 2 }
248
+ Vanity.playground.track! :yawns_sec
249
+ boredom = Vanity::Metric.data(Vanity.playground.metric(:yawns_sec), Date.today - 5, Date.today)
250
+ assert_equal [[today - 5, 0], [today - 4, 4], [today - 3, 0], [today - 2, 2], [today - 1, 0], [today, 1]], boredom
251
+ end
252
+
253
+ test "start date only" do
254
+ metric "Yawns/sec"
255
+ Timecop.freeze(today - 4) { Vanity.playground.track! :yawns_sec, 4 }
256
+ Timecop.freeze(today - 2) { Vanity.playground.track! :yawns_sec, 2 }
257
+ Vanity.playground.track! :yawns_sec
258
+ boredom = Vanity::Metric.data(Vanity.playground.metric(:yawns_sec), Date.today - 4)
259
+ assert_equal [[today - 4, 4], [today - 3, 0], [today - 2, 2], [today - 1, 0], [today, 1]], boredom
260
+ end
261
+
262
+ test "start date and duration" do
263
+ metric "Yawns/sec"
264
+ Timecop.freeze(today - 4) { Vanity.playground.track! :yawns_sec, 4 }
265
+ Timecop.freeze(today - 2) { Vanity.playground.track! :yawns_sec, 2 }
266
+ Vanity.playground.track! :yawns_sec
267
+ boredom = Vanity::Metric.data(Vanity.playground.metric(:yawns_sec), 5)
268
+ assert_equal [[today - 4, 4], [today - 3, 0], [today - 2, 2], [today - 1, 0], [today, 1]], boredom
269
+ end
270
+
271
+ test "no data" do
272
+ metric "Yawns/sec"
273
+ boredom = Vanity::Metric.data(Vanity.playground.metric(:yawns_sec))
274
+ assert_equal 90, boredom.size
275
+ assert_equal [today - 89, 0], boredom.first
276
+ assert_equal [today, 0], boredom.last
277
+ end
278
+
279
+ test "using custom values method" do
280
+ File.open "tmp/experiments/metrics/hours_in_day.rb", "w" do |f|
281
+ f.write <<-RUBY
282
+ metric "Hours in day" do
283
+ def values(from, to)
284
+ (from..to).map { |d| 24 }
285
+ end
286
+ end
287
+ RUBY
288
+ end
289
+ data = Vanity::Metric.data(Vanity.playground.metric(:hours_in_day))
290
+ assert_equal [24] * 90, data.map(&:last)
291
+ end
292
+
293
+ end
@@ -0,0 +1,104 @@
1
+ require "test/test_helper"
2
+
3
+
4
+ context "Google Analytics" do
5
+
6
+ setup do
7
+ File.open "tmp/experiments/metrics/ga.rb", "w" do |f|
8
+ f.write <<-RUBY
9
+ metric "GA" do
10
+ google_analytics "UA2"
11
+ end
12
+ RUBY
13
+ end
14
+ end
15
+
16
+ GA_RESULT = Struct.new(:date, :pageviews, :visits)
17
+ GA_PROFILE = Struct.new(:web_property_id)
18
+
19
+ test "fail if Garb not available" do
20
+ File.open "tmp/experiments/metrics/ga.rb", "w" do |f|
21
+ f.write <<-RUBY
22
+ metric "GA" do
23
+ expects(:require).raises LoadError
24
+ google_analytics "UA2"
25
+ end
26
+ RUBY
27
+ end
28
+ assert_raise LoadError do
29
+ Vanity.playground.metrics
30
+ end
31
+ end
32
+
33
+ test "constructs a report" do
34
+ Vanity.playground.metrics
35
+ assert metric(:ga).report
36
+ end
37
+
38
+ test "default to pageviews metric" do
39
+ Vanity.playground.metrics
40
+ assert_equal [:pageviews], metric(:ga).report.metrics.elements
41
+ end
42
+
43
+ test "apply data dimension and sort" do
44
+ Vanity.playground.metrics
45
+ assert_equal [:date], metric(:ga).report.dimensions.elements
46
+ assert_equal [:date], metric(:ga).report.sort.elements
47
+ end
48
+
49
+ test "accept other metrics" do
50
+ File.open "tmp/experiments/metrics/ga.rb", "w" do |f|
51
+ f.write <<-RUBY
52
+ metric "GA" do
53
+ google_analytics "UA2", :visitors
54
+ end
55
+ RUBY
56
+ end
57
+ Vanity.playground.metrics
58
+ assert_equal [:visitors], metric(:ga).report.metrics.elements
59
+ end
60
+
61
+ test "does not support hooks" do
62
+ Vanity.playground.metrics
63
+ assert_raises RuntimeError do
64
+ metric(:ga).hook
65
+ end
66
+ end
67
+
68
+ test "should find matching profile" do
69
+ Vanity.playground.metrics
70
+ Garb::Profile.expects(:all).returns(Array.new(3) { |i| GA_PROFILE.new("UA#{i + 1}") })
71
+ metric(:ga).report.stubs(:send_request_for_body).returns(nil)
72
+ Garb::ReportResponse.stubs(:new).returns(mock(:results=>[]))
73
+ metric(:ga).values(Date.parse("2010-02-10"), Date.parse("2010-02-12"))
74
+ assert_equal "UA2", metric(:ga).report.profile.web_property_id
75
+ end
76
+
77
+ test "should map results from report" do
78
+ Vanity.playground.metrics
79
+ today = Date.today
80
+ response = mock(:results=>Array.new(3) { |i| GA_RESULT.new("2010021#{i}", i + 1) })
81
+ Garb::Profile.stubs(:all).returns([])
82
+ Garb::ReportResponse.expects(:new).returns(response)
83
+ metric(:ga).report.stubs(:send_request_for_body).returns(nil)
84
+ assert_equal [1,2,3], metric(:ga).values(Date.parse("2010-02-10"), Date.parse("2010-02-12"))
85
+ end
86
+
87
+ test "mapping GA metrics to single value" do
88
+ File.open "tmp/experiments/metrics/ga.rb", "w" do |f|
89
+ f.write <<-RUBY
90
+ metric "GA" do
91
+ google_analytics "UA2", :mapper=>lambda { |e| e.pageviews * e.visits }
92
+ end
93
+ RUBY
94
+ end
95
+ Vanity.playground.metrics
96
+ today = Date.today
97
+ response = mock(:results=>Array.new(3) { |i| GA_RESULT.new("2010021#{i}", i + 1, i + 1) })
98
+ Garb::Profile.stubs(:all).returns([])
99
+ Garb::ReportResponse.expects(:new).returns(response)
100
+ metric(:ga).report.stubs(:send_request_for_body).returns(nil)
101
+ assert_equal [1,4,9], metric(:ga).values(Date.parse("2010-02-10"), Date.parse("2010-02-12"))
102
+ end
103
+
104
+ end
@@ -0,0 +1,109 @@
1
+ require "test/test_helper"
2
+
3
+
4
+ context "Remote metrics" do
5
+ setup do
6
+ FileUtils.mkpath "tmp/config"
7
+ File.open "tmp/config/vanity.yml", "w" do |f|
8
+ f.write <<-RUBY
9
+ metrics:
10
+ sandbox: http://api.vanitydash.com/metrics/sandbox
11
+ RUBY
12
+ end
13
+ ::Rails.stubs(:root).returns(Pathname.new(File.expand_path("tmp")))
14
+ Dir.chdir "tmp" do
15
+ Vanity.playground.load!
16
+ end
17
+ end
18
+
19
+ test "load from configuration file" do
20
+ assert Vanity.playground.metrics[:sandbox]
21
+ end
22
+
23
+ test "create remote metric from configuration file" do
24
+ stub_request :post, /vanitydash/
25
+ metric(:sandbox).track!
26
+ assert_requested :post, /api\.vanitydash\.com/
27
+ end
28
+ end
29
+
30
+
31
+ context "Remote send" do
32
+ setup do
33
+ @metric = Vanity::Metric.new(Vanity.playground, :sandbox)
34
+ @metric.remote "http://api.vanitydash.com/metrics/sandbox"
35
+ Vanity.playground.metrics[:sandbox] = @metric
36
+ stub_request :post, /vanitydash/
37
+ end
38
+
39
+ test "remote send in sequence" do
40
+ Vanity.playground.track! :sandbox
41
+ Vanity.playground.track! :sandbox
42
+ assert_requested(:post, "http://api.vanitydash.com/metrics/sandbox", :times=>2)
43
+ end
44
+
45
+ test "remote sends url-encoded data" do
46
+ Vanity.playground.track! :sandbox, 12
47
+ assert_requested(:post, /api/) { |request| request.headers["Content-Type"] == "application/x-www-form-urlencoded" }
48
+ end
49
+
50
+ test "remote sends metric identifier" do
51
+ Vanity.playground.track! :sandbox, 12
52
+ assert_requested(:post, /api/) { |request| Rack::Utils.parse_query(request.body)["metric"] == "sandbox" }
53
+ end
54
+
55
+ test "remote sends RFC 2616 compliant time stamp" do
56
+ Vanity.playground.track! :sandbox, 12
57
+ assert_requested(:post, /api/) { |request| Time.httpdate(Rack::Utils.parse_query(request.body)["timestamp"]) }
58
+ end
59
+
60
+ test "remote sends array of values" do
61
+ Vanity.playground.track! :sandbox, [1,2,3]
62
+ assert_requested(:post, /api/) { |request| Rack::Utils.parse_query(request.body)["values[]"] == %w{1 2 3} }
63
+ end
64
+
65
+ test "remote sends default of 1" do
66
+ Vanity.playground.track! :sandbox
67
+ assert_requested(:post, /api/) { |request| Rack::Utils.parse_query(request.body)["values[]"] == "1" }
68
+ end
69
+
70
+ test "remote sends current identity" do
71
+ Vanity.context = Object.new
72
+ class << Vanity.context
73
+ def vanity_identity
74
+ "xkcd"
75
+ end
76
+ end
77
+ Vanity.playground.track! :sandbox, 12
78
+ assert_requested(:post, /api/) { |request| Rack::Utils.parse_query(request.body)["identity"] == "xkcd" }
79
+ end
80
+
81
+ test "remote sends with additional query parameters" do
82
+ @metric.remote "http://api.vanitydash.com/metrics/sandbox?ask=receive"
83
+ Vanity.playground.track! :sandbox, 12
84
+ assert_requested(:post, /api/) { |request| Rack::Utils.parse_query(request.body)["ask"] == "receive" }
85
+ end
86
+
87
+ test "remote send handles standard error" do
88
+ stub_request(:post, /api/).to_raise(StandardError)
89
+ Vanity.playground.track! :sandbox
90
+ stub_request(:post, /api/)
91
+ Vanity.playground.track! :sandbox
92
+ assert_requested(:post, /api/, :times=>2)
93
+ end
94
+
95
+ test "remote send handles timeout error" do
96
+ stub_request(:post, /api/).to_timeout
97
+ Vanity.playground.track! :sandbox
98
+ stub_request(:post, /api/)
99
+ Vanity.playground.track! :sandbox
100
+ assert_requested(:post, /api/, :times=>2)
101
+ end
102
+
103
+ test "remote does not send when metrics disabled" do
104
+ not_collecting!
105
+ Vanity.playground.track! :sandbox
106
+ Vanity.playground.track! :sandbox
107
+ assert_requested(:post, /api/, :times=>0)
108
+ end
109
+ end