right_support 2.7.0 → 2.8.0

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.
@@ -43,151 +43,263 @@ describe RightSupport::Stats::Activity do
43
43
  @stats = RightSupport::Stats::Activity.new
44
44
  end
45
45
 
46
- it "initializes stats data" do
47
- @stats.instance_variable_get(:@interval).should == 0.0
48
- @stats.instance_variable_get(:@last_start_time).should == @now
49
- @stats.instance_variable_get(:@avg_duration).should be_nil
50
- @stats.instance_variable_get(:@total).should == 0
51
- @stats.instance_variable_get(:@count_per_type).should == {}
46
+ context :initialize do
47
+ it "initializes stats data" do
48
+ @stats.instance_variable_get(:@interval).should == 0.0
49
+ @stats.instance_variable_get(:@last_start_time).should == @now
50
+ @stats.instance_variable_get(:@avg_duration).should be_nil
51
+ @stats.instance_variable_get(:@total).should == 0
52
+ @stats.instance_variable_get(:@count_per_type).should == {}
53
+ end
52
54
  end
53
55
 
54
- it "updates count and interval information" do
55
- flexmock(Time).should_receive(:now).and_return(1000010)
56
- @stats.update
57
- @stats.instance_variable_get(:@interval).should == 1.0
58
- @stats.instance_variable_get(:@last_start_time).should == @now + 10
59
- @stats.instance_variable_get(:@avg_duration).should be_nil
60
- @stats.instance_variable_get(:@total).should == 1
61
- @stats.instance_variable_get(:@count_per_type).should == {}
62
- end
56
+ context :update do
57
+ it "updates count and interval information" do
58
+ flexmock(Time).should_receive(:now).and_return(1000010)
59
+ @stats.update
60
+ @stats.instance_variable_get(:@interval).should == 1.0
61
+ @stats.instance_variable_get(:@last_start_time).should == @now + 10
62
+ @stats.instance_variable_get(:@avg_duration).should be_nil
63
+ @stats.instance_variable_get(:@total).should == 1
64
+ @stats.instance_variable_get(:@count_per_type).should == {}
65
+ end
63
66
 
64
- it "updates weight the average interval toward recent activity" do
65
- end
67
+ it "updates counts per type when type provided" do
68
+ flexmock(Time).should_receive(:now).and_return(1000010)
69
+ @stats.update("test")
70
+ @stats.instance_variable_get(:@interval).should == 1.0
71
+ @stats.instance_variable_get(:@last_start_time).should == @now + 10
72
+ @stats.instance_variable_get(:@avg_duration).should be_nil
73
+ @stats.instance_variable_get(:@total).should == 1
74
+ @stats.instance_variable_get(:@count_per_type).should == {"test" => 1}
75
+ end
66
76
 
67
- it "updates counts per type when type provided" do
68
- flexmock(Time).should_receive(:now).and_return(1000010)
69
- @stats.update("test")
70
- @stats.instance_variable_get(:@interval).should == 1.0
71
- @stats.instance_variable_get(:@last_start_time).should == @now + 10
72
- @stats.instance_variable_get(:@avg_duration).should be_nil
73
- @stats.instance_variable_get(:@total).should == 1
74
- @stats.instance_variable_get(:@count_per_type).should == {"test" => 1}
75
- end
77
+ it "doesn't update counts when type contains 'stats'" do
78
+ flexmock(Time).should_receive(:now).and_return(1000010)
79
+ @stats.update("my stats")
80
+ @stats.instance_variable_get(:@interval).should == 0.0
81
+ @stats.instance_variable_get(:@last_start_time).should == @now
82
+ @stats.instance_variable_get(:@avg_duration).should be_nil
83
+ @stats.instance_variable_get(:@total).should == 0
84
+ @stats.instance_variable_get(:@count_per_type).should == {}
85
+ end
76
86
 
77
- it "doesn't update counts when type contains 'stats'" do
78
- flexmock(Time).should_receive(:now).and_return(1000010)
79
- @stats.update("my stats")
80
- @stats.instance_variable_get(:@interval).should == 0.0
81
- @stats.instance_variable_get(:@last_start_time).should == @now
82
- @stats.instance_variable_get(:@avg_duration).should be_nil
83
- @stats.instance_variable_get(:@total).should == 0
84
- @stats.instance_variable_get(:@count_per_type).should == {}
85
- end
87
+ it "limits length of type string when submitting update" do
88
+ flexmock(Time).should_receive(:now).and_return(1000010)
89
+ @stats.update("test 12345678901234567890123456789012345678901234567890123456789")
90
+ @stats.instance_variable_get(:@total).should == 1
91
+ @stats.instance_variable_get(:@count_per_type).should ==
92
+ {"test 1234567890123456789012345678901234567890123456789012..." => 1}
93
+ end
86
94
 
87
- it "limits length of type string when submitting update" do
88
- flexmock(Time).should_receive(:now).and_return(1000010)
89
- @stats.update("test 12345678901234567890123456789012345678901234567890123456789")
90
- @stats.instance_variable_get(:@total).should == 1
91
- @stats.instance_variable_get(:@count_per_type).should ==
92
- {"test 1234567890123456789012345678901234567890123456789012..." => 1}
93
- end
95
+ it "doesn't convert symbol or boolean to string when submitting update" do
96
+ flexmock(Time).should_receive(:now).and_return(1000010)
97
+ @stats.update(:test)
98
+ @stats.update(true)
99
+ @stats.update(false)
100
+ @stats.instance_variable_get(:@total).should == 3
101
+ @stats.instance_variable_get(:@count_per_type).should == {:test => 1, true => 1, false => 1}
102
+ end
94
103
 
95
- it "doesn't convert symbol or boolean to string when submitting update" do
96
- flexmock(Time).should_receive(:now).and_return(1000010)
97
- @stats.update(:test)
98
- @stats.update(true)
99
- @stats.update(false)
100
- @stats.instance_variable_get(:@total).should == 3
101
- @stats.instance_variable_get(:@count_per_type).should == {:test => 1, true => 1, false => 1}
102
- end
104
+ it "converts arbitrary type value to limited-length string when submitting update" do
105
+ flexmock(Time).should_receive(:now).and_return(1000010)
106
+ @stats.update({1 => 11, 2 => 22})
107
+ @stats.update({1 => 11, 2 => 22, 3 => 12345678901234567890123456789012345678901234567890123456789})
108
+ @stats.instance_variable_get(:@total).should == 2
109
+ @stats.instance_variable_get(:@count_per_type).should == {"{1=>11, 2=>22}" => 1,
110
+ "{1=>11, 2=>22, 3=>123456789012345678901234567890123456789..." => 1}
111
+ end
103
112
 
104
- it "converts arbitrary type value to limited-length string when submitting update" do
105
- flexmock(Time).should_receive(:now).and_return(1000010)
106
- @stats.update({1 => 11, 2 => 22})
107
- @stats.update({1 => 11, 2 => 22, 3 => 12345678901234567890123456789012345678901234567890123456789})
108
- @stats.instance_variable_get(:@total).should == 2
109
- @stats.instance_variable_get(:@count_per_type).should == {"{1=>11, 2=>22}" => 1,
110
- "{1=>11, 2=>22, 3=>123456789012345678901234567890123456789..." => 1}
113
+ it "doesn't measure rate if disabled" do
114
+ @stats = RightSupport::Stats::Activity.new(false)
115
+ flexmock(Time).should_receive(:now).and_return(1000010)
116
+ @stats.update
117
+ @stats.instance_variable_get(:@interval).should == 0.0
118
+ @stats.instance_variable_get(:@last_start_time).should == @now + 10
119
+ @stats.instance_variable_get(:@avg_duration).should be_nil
120
+ @stats.instance_variable_get(:@total).should == 1
121
+ @stats.instance_variable_get(:@count_per_type).should == {}
122
+ end
111
123
  end
112
124
 
113
- it "doesn't measure rate if disabled" do
114
- @stats = RightSupport::Stats::Activity.new(false)
115
- flexmock(Time).should_receive(:now).and_return(1000010)
116
- @stats.update
117
- @stats.instance_variable_get(:@interval).should == 0.0
118
- @stats.instance_variable_get(:@last_start_time).should == @now + 10
119
- @stats.instance_variable_get(:@avg_duration).should be_nil
120
- @stats.instance_variable_get(:@total).should == 1
121
- @stats.instance_variable_get(:@count_per_type).should == {}
122
- @stats.all.should == {"last" => {"elapsed"=>0}, "total" => 1}
123
- end
125
+ context :finish do
126
+ it "updates duration when finish using internal start time by default" do
127
+ flexmock(Time).should_receive(:now).and_return(1000010)
128
+ @stats.avg_duration.should be_nil
129
+ @stats.finish
130
+ @stats.instance_variable_get(:@interval).should == 0.0
131
+ @stats.instance_variable_get(:@last_start_time).should == @now
132
+ @stats.instance_variable_get(:@avg_duration).should == 1.0
133
+ @stats.instance_variable_get(:@total).should == 0
134
+ @stats.instance_variable_get(:@count_per_type).should == {}
135
+ end
124
136
 
125
- it "updates duration when finish using internal start time by default" do
126
- flexmock(Time).should_receive(:now).and_return(1000010)
127
- @stats.finish
128
- @stats.instance_variable_get(:@interval).should == 0.0
129
- @stats.instance_variable_get(:@last_start_time).should == @now
130
- @stats.instance_variable_get(:@avg_duration).should == 1.0
131
- @stats.instance_variable_get(:@total).should == 0
132
- @stats.instance_variable_get(:@count_per_type).should == {}
137
+ it "updates duration when finish using specified start time" do
138
+ flexmock(Time).should_receive(:now).and_return(1000030)
139
+ @stats.avg_duration.should be_nil
140
+ @stats.finish(1000010)
141
+ @stats.instance_variable_get(:@interval).should == 0.0
142
+ @stats.instance_variable_get(:@last_start_time).should == @now
143
+ @stats.instance_variable_get(:@avg_duration).should == 2.0
144
+ @stats.instance_variable_get(:@total).should == 0
145
+ @stats.instance_variable_get(:@count_per_type).should == {}
146
+ end
133
147
  end
134
148
 
135
- it "updates duration when finish using specified start time" do
136
- flexmock(Time).should_receive(:now).and_return(1000030)
137
- @stats.avg_duration.should be_nil
138
- @stats.finish(1000010)
139
- @stats.instance_variable_get(:@interval).should == 0.0
140
- @stats.instance_variable_get(:@last_start_time).should == @now
141
- @stats.instance_variable_get(:@avg_duration).should == 2.0
142
- @stats.instance_variable_get(:@total).should == 0
143
- @stats.instance_variable_get(:@count_per_type).should == {}
149
+ context :avg_rate do
150
+ it "converts interval to rate" do
151
+ flexmock(Time).should_receive(:now).and_return(1000020)
152
+ @stats.avg_rate.should be_nil
153
+ @stats.update
154
+ @stats.instance_variable_get(:@interval).should == 2.0
155
+ @stats.avg_rate.should == 0.5
156
+ end
144
157
  end
145
158
 
146
- it "converts interval to rate" do
147
- flexmock(Time).should_receive(:now).and_return(1000020)
148
- @stats.avg_rate.should be_nil
149
- @stats.update
150
- @stats.instance_variable_get(:@interval).should == 2.0
151
- @stats.avg_rate.should == 0.5
159
+ context :last do
160
+ it "reports number of seconds since last update or nil if no updates" do
161
+ flexmock(Time).should_receive(:now).and_return(1000010)
162
+ @stats.last.should be_nil
163
+ @stats.update
164
+ @stats.last.should == {"elapsed" => 0}
165
+ end
166
+
167
+ it "reports number of seconds since last update and last type" do
168
+ @stats.update("test")
169
+ flexmock(Time).should_receive(:now).and_return(1000010)
170
+ @stats.last.should == {"elapsed" => 10, "type" => "test"}
171
+ end
172
+
173
+ it "reports whether last activity is still active" do
174
+ @stats.update("test", "token")
175
+ flexmock(Time).should_receive(:now).and_return(1000010)
176
+ @stats.last.should == {"elapsed" => 10, "type" => "test", "active" => true}
177
+ @stats.finish(@now - 10, "token")
178
+ @stats.last.should == {"elapsed" => 10, "type" => "test", "active" => false}
179
+ @stats.instance_variable_get(:@avg_duration).should == 2.0
180
+ end
152
181
  end
153
182
 
154
- it "reports number of seconds since last update or nil if no updates" do
155
- flexmock(Time).should_receive(:now).and_return(1000010)
156
- @stats.last.should be_nil
157
- @stats.update
158
- @stats.last.should == {"elapsed" => 0}
183
+ context :percentage do
184
+ it "converts count per type to percentages" do
185
+ flexmock(Time).should_receive(:now).and_return(1000010)
186
+ @stats.update("foo")
187
+ @stats.instance_variable_get(:@total).should == 1
188
+ @stats.instance_variable_get(:@count_per_type).should == {"foo" => 1}
189
+ @stats.percentage.should == {"total" => 1, "percent" => {"foo" => 100.0}}
190
+ @stats.update("bar")
191
+ @stats.instance_variable_get(:@total).should == 2
192
+ @stats.instance_variable_get(:@count_per_type).should == {"foo" => 1, "bar" => 1}
193
+ @stats.percentage.should == {"total" => 2, "percent" => {"foo" => 50.0, "bar" => 50.0}}
194
+ @stats.update("foo")
195
+ @stats.update("foo")
196
+ @stats.instance_variable_get(:@total).should == 4
197
+ @stats.instance_variable_get(:@count_per_type).should == {"foo" => 3, "bar" => 1}
198
+ @stats.percentage.should == {"total" => 4, "percent" => {"foo" => 75.0, "bar" => 25.0}}
199
+ end
159
200
  end
160
201
 
161
- it "reports number of seconds since last update and last type" do
162
- @stats.update("test")
163
- flexmock(Time).should_receive(:now).and_return(1000010)
164
- @stats.last.should == {"elapsed" => 10, "type" => "test"}
202
+ context :all do
203
+ it "returns all activity aspects that were measured except duration" do
204
+ flexmock(Time).should_receive(:now).and_return(1000010)
205
+ @stats.update
206
+ @stats.all.should == {"last" => {"elapsed" => 0}, "total" => 1, "rate" => 1.0}
207
+ end
208
+
209
+ it "excludes rate if it is not being measured" do
210
+ @stats = RightSupport::Stats::Activity.new(false)
211
+ flexmock(Time).should_receive(:now).and_return(1000010)
212
+ @stats.update
213
+ @stats.all.should == {"last" => {"elapsed" => 0}, "total" => 1}
214
+ end
215
+
216
+ it "includes percentage breakdown when update recorded per type" do
217
+ @stats = RightSupport::Stats::Activity.new(false)
218
+ flexmock(Time).should_receive(:now).and_return(1000010, 1000010, 1000020, 1000020, 1000030, 1000030, 1000040)
219
+ @stats.update("foo")
220
+ @stats.all.should == {"last" => {"elapsed" => 0, "type" => "foo"}, "total" => 1, "percent" => {"foo" => 100.0}}
221
+ @stats.update("bar")
222
+ @stats.all.should == {"last" => {"elapsed" => 0, "type" => "bar"}, "total" => 2, "percent" => {"foo" => 50.0, "bar" => 50.0}}
223
+ @stats.update("bar")
224
+ @stats.update("foo")
225
+ @stats.all.should == {"last" => {"elapsed" => 10, "type" => "foo"}, "total" => 4, "percent" => {"foo" => 50.0, "bar" => 50.0}}
226
+ end
227
+
228
+ it "returns nil if there was no activity" do
229
+ @stats.all.should be_nil
230
+ end
165
231
  end
166
232
 
167
- it "reports whether last activity is still active" do
168
- @stats.update("test", "token")
169
- flexmock(Time).should_receive(:now).and_return(1000010)
170
- @stats.last.should == {"elapsed" => 10, "type" => "test", "active" => true}
171
- @stats.finish(@now - 10, "token")
172
- @stats.last.should == {"elapsed" => 10, "type" => "test", "active" => false}
173
- @stats.instance_variable_get(:@avg_duration).should == 2.0
233
+ context :average do
234
+ it "weights average toward past activity" do
235
+ @stats.send(:average, 0.0, 10.0).should == 1.0
236
+ @stats.send(:average, 1.0, 10.0).should == 1.9
237
+ @stats.send(:average, 1.9, 10.0).should == 2.71
238
+ @stats.send(:average, 2.71, 10.0).should == 3.439
239
+ @stats.send(:average, 3.439, 10.0).should == 4.0951
240
+ @stats.send(:average, 4.0951, 10.0).should == 4.68559
241
+ @stats.send(:average, 4.68559, 10.0).should == 5.217031
242
+ end
174
243
  end
175
244
 
176
- it "converts count per type to percentages" do
177
- flexmock(Time).should_receive(:now).and_return(1000010)
178
- @stats.update("foo")
179
- @stats.instance_variable_get(:@total).should == 1
180
- @stats.instance_variable_get(:@count_per_type).should == {"foo" => 1}
181
- @stats.percentage.should == {"total" => 1, "percent" => {"foo" => 100.0}}
182
- @stats.update("bar")
183
- @stats.instance_variable_get(:@total).should == 2
184
- @stats.instance_variable_get(:@count_per_type).should == {"foo" => 1, "bar" => 1}
185
- @stats.percentage.should == {"total" => 2, "percent" => {"foo" => 50.0, "bar" => 50.0}}
186
- @stats.update("foo")
187
- @stats.update("foo")
188
- @stats.instance_variable_get(:@total).should == 4
189
- @stats.instance_variable_get(:@count_per_type).should == {"foo" => 3, "bar" => 1}
190
- @stats.percentage.should == {"total" => 4, "percent" => {"foo" => 75.0, "bar" => 25.0}}
245
+ describe "class methods" do
246
+
247
+ context :all do
248
+ it "aggregates stats from multiple all calls" do
249
+ stats = [{"last" => {"elapsed" => 10, "type" => "foo"}, "total" => 1, "percent" => {"foo" => 100.0}},
250
+ {"last" => {"elapsed" => 20, "type" => "bar"}, "total" => 4, "percent" => {"bar" => 100.0}}]
251
+ RightSupport::Stats::Activity.all(stats).should ==
252
+ {"last" => {"elapsed" => 10, "type" => "foo"}, "total" => 5, "percent" => {"foo" => 20.0, "bar" => 80.0}}
253
+ end
254
+
255
+ it "includes rate if provided" do
256
+ stats = [{"last" => {"elapsed" => 10, "type" => "foo"}, "total" => 1, "percent" => {"foo" => 100.0}, "rate" => 0.5},
257
+ {"last" => {"elapsed" => 20, "type" => "bar"}, "total" => 4, "percent" => {"bar" => 100.0}, "rate" => 0.1}]
258
+ RightSupport::Stats::Activity.all(stats).should ==
259
+ {"last" => {"elapsed" => 10, "type" => "foo"}, "total" => 5, "percent" => {"foo" => 20.0, "bar" => 80.0}, "rate" => 0.18}
260
+ end
261
+
262
+ it "returns nil if there are no stats" do
263
+ RightSupport::Stats::Activity.all([]).should be_nil
264
+ end
265
+ end
266
+
267
+ context :percentage do
268
+ it "aggregates multiple percentage stats" do
269
+ stats = [{"total" => 1, "percent" => {"foo" => 100.0}},
270
+ {"total" => 5, "percent" => {"bar" => 100.0}},
271
+ {"total" => 4, "percent" => {"foo" => 75.0, "bar" => 25.0}}]
272
+ RightSupport::Stats::Activity.percentage(stats, 10).should == {"total" => 10, "percent" => {"foo" => 40.0, "bar" => 60.0}}
273
+ end
274
+
275
+ it "returns only total if there is no data" do
276
+ RightSupport::Stats::Activity.percentage([], 0).should == {"total" => 0}
277
+ end
278
+ end
279
+
280
+ context :avg_rate do
281
+ it "computes average rate from multiple average rates" do
282
+ stats = [{"total" => 1, "rate" => 0.5},
283
+ {"total" => 5, "rate" => 0.1},
284
+ {"total" => 4, "rate" => 0.2}]
285
+ RightSupport::Stats::Activity.avg_rate(stats, 10).should == 0.18
286
+ end
287
+
288
+ it "returns nil if there is no data" do
289
+ RightSupport::Stats::Activity.avg_rate([], 0).should be_nil
290
+ end
291
+ end
292
+
293
+ context :last do
294
+ it "determines last activity from multiple last activity stats" do
295
+ stats = [{"last" => {"elapsed" => 0, "type" => "foo"}, "total" => 1, "percent" => {"foo" => 100.0}},
296
+ {"last" => {"elapsed" => 0, "type" => "foo"}, "total" => 1, "percent" => {"foo" => 100.0}}]
297
+ end
298
+
299
+ it "returns nil if there is no data" do
300
+ RightSupport::Stats::Activity.last([]).should be_nil
301
+ end
302
+ end
191
303
  end
192
304
 
193
305
  end # RightSupport::Stats::Activity
@@ -33,90 +33,196 @@ describe RightSupport::Stats::Exceptions do
33
33
  @exception = Exception.new("Test error")
34
34
  end
35
35
 
36
- it "initializes stats data" do
37
- @stats.stats.should be_nil
38
- @stats.instance_variable_get(:@callback).should be_nil
36
+ context :initialize do
37
+ it "initializes stats data" do
38
+ @stats.stats.should be_nil
39
+ @stats.instance_variable_get(:@callback).should be_nil
40
+ end
39
41
  end
40
42
 
41
- it "tracks submitted exception information by category" do
42
- @stats.track("testing", @exception)
43
- @stats.stats.should == {"testing" => {"total" => 1,
44
- "recent" => [{"count" => 1, "type" => "Exception", "message" => "Test error",
45
- "when" => @now, "where" => nil}]}}
43
+ context :reset do
44
+ it "clears any currently stored exceptions" do
45
+ @stats.track("testing", @exception)
46
+ @stats.stats.should_not be_nil
47
+ @stats.reset
48
+ @stats.stats.should be_nil
49
+ end
46
50
  end
47
51
 
48
- it "recognizes and counts repeated exceptions" do
49
- @stats.track("testing", @exception)
50
- @stats.stats.should == {"testing" => {"total" => 1,
51
- "recent" => [{"count" => 1, "type" => "Exception", "message" => "Test error",
52
- "when" => @now, "where" => nil}]}}
53
- flexmock(Time).should_receive(:now).and_return(1000010)
54
- category = "another"
55
- backtrace = ["here", "and", "there"]
56
- 4.times do |i|
52
+ context :track do
53
+ it "tracks submitted exception information by category" do
54
+ @stats.track("testing", @exception)
55
+ @stats.stats.should == {"testing" => {"total" => 1,
56
+ "recent" => [{"count" => 1, "type" => "Exception", "message" => "Test error",
57
+ "when" => @now, "where" => nil}]}}
58
+ end
59
+
60
+ it "tracks where exception occurred if it has a backtrace" do
57
61
  begin
58
- raise ArgumentError, "badarg"
62
+ raise Exception.new("Test error")
59
63
  rescue Exception => e
60
- flexmock(e).should_receive(:backtrace).and_return(backtrace)
61
- @stats.track(category, e)
62
- backtrace.shift(2) if i == 1
63
- category = "testing" if i == 2
64
+ @exception = e
64
65
  end
66
+ @stats.track("testing", @exception)
67
+ @stats.stats["testing"]["recent"][0]["where"].should =~ /right_support\/spec\/stats\/exceptions_spec.rb/
68
+ end
69
+
70
+ it "recognizes and counts repeated exceptions" do
71
+ @stats.track("testing", @exception)
72
+ @stats.stats.should == {"testing" => {"total" => 1,
73
+ "recent" => [{"count" => 1, "type" => "Exception", "message" => "Test error",
74
+ "when" => @now, "where" => nil}]}}
75
+ flexmock(Time).should_receive(:now).and_return(1000010)
76
+ category = "another"
77
+ backtrace = ["here", "and", "there"]
78
+ 4.times do |i|
79
+ begin
80
+ raise ArgumentError, "badarg"
81
+ rescue Exception => e
82
+ flexmock(e).should_receive(:backtrace).and_return(backtrace)
83
+ @stats.track(category, e)
84
+ backtrace.shift(2) if i == 1
85
+ category = "testing" if i == 2
86
+ end
87
+ end
88
+ @stats.stats.should == {"testing" => {"total" => 2,
89
+ "recent" => [{"count" => 1, "type" => "Exception", "message" => "Test error",
90
+ "when" => @now, "where" => nil},
91
+ {"count" => 1, "type" => "ArgumentError", "message" => "badarg",
92
+ "when" => @now + 10, "where" => "there"}]},
93
+ "another" => {"total" => 3,
94
+ "recent" => [{"count" => 2, "type" => "ArgumentError", "message" => "badarg",
95
+ "when" => @now + 10, "where" => "here"},
96
+ {"count" => 1, "type" => "ArgumentError", "message" => "badarg",
97
+ "when" => @now + 10, "where" => "there"}]}}
98
+ end
99
+
100
+ it "limits the number of exceptions stored by eliminating older exceptions" do
101
+ (RightSupport::Stats::Exceptions::MAX_RECENT_EXCEPTIONS + 1).times do |i|
102
+ begin
103
+ raise ArgumentError, "badarg"
104
+ rescue Exception => e
105
+ flexmock(e).should_receive(:backtrace).and_return([i.to_s])
106
+ @stats.track("testing", e)
107
+ end
108
+ end
109
+ stats = @stats.stats
110
+ stats["testing"]["total"].should == RightSupport::Stats::Exceptions::MAX_RECENT_EXCEPTIONS + 1
111
+ stats["testing"]["recent"].size.should == RightSupport::Stats::Exceptions::MAX_RECENT_EXCEPTIONS
112
+ stats["testing"]["recent"][0]["where"].should == "1"
113
+ end
114
+
115
+ it "makes callback if callback and message defined" do
116
+ called = 0
117
+ callback = lambda do |exception, message, server|
118
+ called += 1
119
+ exception.should == @exception
120
+ message.should == "message"
121
+ server.should == "server"
122
+ end
123
+ @stats = RightSupport::Stats::Exceptions.new("server", callback)
124
+ @stats.track("testing", @exception, "message")
125
+ @stats.stats.should == {"testing" => {"total" => 1,
126
+ "recent" => [{"count" => 1, "type" => "Exception", "message" => "Test error",
127
+ "when" => @now, "where" => nil}]}}
128
+ called.should == 1
65
129
  end
66
- @stats.stats.should == {"testing" => {"total" => 2,
67
- "recent" => [{"count" => 1, "type" => "Exception", "message" => "Test error",
68
- "when" => @now, "where" => nil},
69
- {"count" => 1, "type" => "ArgumentError", "message" => "badarg",
70
- "when" => @now + 10, "where" => "there"}]},
71
- "another" => {"total" => 3,
72
- "recent" => [{"count" => 2, "type" => "ArgumentError", "message" => "badarg",
73
- "when" => @now + 10, "where" => "here"},
74
- {"count" => 1, "type" => "ArgumentError", "message" => "badarg",
75
- "when" => @now + 10, "where" => "there"}]}}
76
- end
77
130
 
78
- it "limits the number of exceptions stored by eliminating older exceptions" do
79
- (RightSupport::Stats::Exceptions::MAX_RECENT_EXCEPTIONS + 1).times do |i|
131
+ it "catches any exceptions raised internally and log them" do
80
132
  begin
81
- raise ArgumentError, "badarg"
82
- rescue Exception => e
83
- flexmock(e).should_receive(:backtrace).and_return([i.to_s])
84
- @stats.track("testing", e)
133
+ logger = flexmock("logger")
134
+ logger.should_receive(:error).with(/Failed to track exception 'Test error' \(Exception: bad IN/).once
135
+ RightSupport::Log::Mixin.default_logger = logger
136
+ flexmock(@exception).should_receive(:backtrace).and_raise(Exception.new("bad"))
137
+ @stats = RightSupport::Stats::Exceptions.new
138
+ @stats.track("testing", @exception, "message")
139
+ @stats.stats["testing"]["total"].should == 1
140
+ ensure
141
+ RightSupport::Log::Mixin.default_logger = nil
85
142
  end
86
143
  end
87
- stats = @stats.stats
88
- stats["testing"]["total"].should == RightSupport::Stats::Exceptions::MAX_RECENT_EXCEPTIONS + 1
89
- stats["testing"]["recent"].size.should == RightSupport::Stats::Exceptions::MAX_RECENT_EXCEPTIONS
90
- stats["testing"]["recent"][0]["where"].should == "1"
91
144
  end
92
145
 
93
- it "makes callback if callback and message defined" do
94
- called = 0
95
- callback = lambda do |exception, message, server|
96
- called += 1
97
- exception.should == @exception
98
- message.should == "message"
99
- server.should == "server"
100
- end
101
- @stats = RightSupport::Stats::Exceptions.new("server", callback)
102
- @stats.track("testing", @exception, "message")
103
- @stats.stats.should == {"testing" => {"total" => 1,
146
+ context :all do
147
+ it "returns current stats" do
148
+ @stats.track("testing", @exception)
149
+ @stats.all.should == {"testing" => {"total" => 1,
104
150
  "recent" => [{"count" => 1, "type" => "Exception", "message" => "Test error",
105
151
  "when" => @now, "where" => nil}]}}
106
- called.should == 1
152
+ end
153
+
154
+ it "returns nil if there are no stats" do
155
+ @stats.all.should be_nil
156
+ end
107
157
  end
108
158
 
109
- it "catches any exceptions raised internally and log them" do
110
- begin
111
- logger = flexmock("logger")
112
- logger.should_receive(:error).with(/Failed to track exception 'Test error' \(Exception: bad IN/).once
113
- RightSupport::Log::Mixin.default_logger = logger
114
- flexmock(@exception).should_receive(:backtrace).and_raise(Exception.new("bad"))
115
- @stats = RightSupport::Stats::Exceptions.new
116
- @stats.track("testing", @exception, "message")
117
- @stats.stats["testing"]["total"].should == 1
118
- ensure
119
- RightSupport::Log::Mixin.default_logger = nil
159
+ describe "class methods" do
160
+
161
+ context :all do
162
+ before(:each) do
163
+
164
+ end
165
+
166
+ it "aggregates the stats from multiple all calls" do
167
+ stats = [{"testing" => {"total" => 3,
168
+ "recent" => [{"count" => 1, "type" => "Exception", "message" => "Test error",
169
+ "when" => @now, "where" => nil},
170
+ {"count" => 1, "type" => "ArgumentError", "message" => "badarg",
171
+ "when" => @now + 20, "where" => "there"},
172
+ {"count" => 1, "type" => "ArgumentError", "message" => "badarg",
173
+ "when" => @now + 30, "where" => "everywhere"}]}},
174
+ {"testing" => {"total" => 5,
175
+ "recent" => [{"count" => 2, "type" => "ArgumentError", "message" => "badarg",
176
+ "when" => @now + 10, "where" => "here"},
177
+ {"count" => 1, "type" => "ArgumentError", "message" => "badarg",
178
+ "when" => @now + 15, "where" => "there"},
179
+ {"count" => 2, "type" => "ArgumentError", "message" => "badarg",
180
+ "when" => @now + 30, "where" => "everywhere"}]}},
181
+ {"testing" => {"total" => 1,
182
+ "recent" => [{"count" => 1, "type" => "ArgumentError", "message" => "awfularg",
183
+ "when" => @now + 10, "where" => "here"}]}},
184
+ {"another" => {"total" => 3,
185
+ "recent" => [{"count" => 2, "type" => "ArgumentError", "message" => "badarg",
186
+ "when" => @now + 10, "where" => "here"},
187
+ {"count" => 1, "type" => "ArgumentError", "message" => "badarg",
188
+ "when" => @now + 10, "where" => "there"}]}}]
189
+
190
+ RightSupport::Stats::Exceptions.all(stats).should ==
191
+ {"testing" => {"total" => 9,
192
+ "recent" => [{"count" => 1, "type" => "Exception", "message" => "Test error",
193
+ "when" => @now, "where" => nil},
194
+ {"count" => 2, "type" => "ArgumentError", "message" => "badarg",
195
+ "when" => @now + 10, "where" => "here"},
196
+ {"count" => 1, "type" => "ArgumentError", "message" => "awfularg",
197
+ "when" => @now + 10, "where" => "here"},
198
+ {"count" => 1, "type" => "ArgumentError", "message" => "badarg",
199
+ "when" => @now + 15, "where" => "there"},
200
+ {"count" => 1, "type" => "ArgumentError", "message" => "badarg",
201
+ "when" => @now + 20, "where" => "there"},
202
+ {"count" => 3, "type" => "ArgumentError", "message" => "badarg",
203
+ "when" => @now + 30, "where" => "everywhere"}]},
204
+ "another" => {"total" => 3,
205
+ "recent" => [{"count" => 2, "type" => "ArgumentError", "message" => "badarg",
206
+ "when" => @now + 10, "where" => "here"},
207
+ {"count" => 1, "type" => "ArgumentError", "message" => "badarg",
208
+ "when" => @now + 10, "where" => "there"}]}}
209
+ end
210
+
211
+ it "does not allow max exceptions to exceed set limit" do
212
+ max = RightSupport::Stats::Exceptions::MAX_RECENT_EXCEPTIONS
213
+ stats = []
214
+ ((max / 2) + 1).times do |i|
215
+ stats << {"testing" => {"total" => 1,
216
+ "recent" => [{"count" => 1, "type" => "Exception", "message" => "Test error",
217
+ "when" => @now + i, "where" => nil},
218
+ {"count" => 2, "type" => "ArgumentError", "message" => "badarg",
219
+ "when" => @now + i, "where" => "here"}]}}
220
+ end
221
+ all = RightSupport::Stats::Exceptions.all(stats)
222
+ all["testing"]["recent"].size.should == max
223
+ all["testing"]["recent"][max - 1].should == {"count" => 2, "type" => "ArgumentError", "message" => "badarg",
224
+ "when" => @now + (max / 2), "where" => "here"}
225
+ end
120
226
  end
121
227
  end
122
228