fnordmetric 0.3.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/Gemfile +6 -0
  2. data/Gemfile.lock +21 -0
  3. data/Procfile +1 -2
  4. data/VERSION +1 -1
  5. data/_spec/app_spec.rb +178 -0
  6. data/{spec → _spec}/cache_spec.rb +0 -0
  7. data/{spec → _spec}/combine_metric_spec.rb +0 -0
  8. data/{spec → _spec}/core_spec.rb +0 -0
  9. data/{spec → _spec}/count_metric_spec.rb +0 -0
  10. data/_spec/dashboard_spec.rb +67 -0
  11. data/_spec/event_spec.rb +46 -0
  12. data/{spec → _spec}/metric_spec.rb +0 -0
  13. data/{spec → _spec}/report_spec.rb +0 -0
  14. data/{spec → _spec}/sum_metric_spec.rb +0 -0
  15. data/_spec/widget_spec.rb +107 -0
  16. data/doc/import_dump.rb +26 -0
  17. data/em_runner.rb +33 -0
  18. data/fnordmetric.gemspec +59 -20
  19. data/haml/app.haml +26 -12
  20. data/lib/fnordmetric.rb +150 -15
  21. data/lib/fnordmetric/app.rb +70 -11
  22. data/lib/fnordmetric/cache.rb +4 -4
  23. data/lib/fnordmetric/context.rb +65 -0
  24. data/lib/fnordmetric/dashboard.rb +16 -12
  25. data/lib/fnordmetric/event.rb +65 -15
  26. data/lib/fnordmetric/gauge.rb +46 -0
  27. data/lib/fnordmetric/gauge_calculations.rb +43 -0
  28. data/lib/fnordmetric/gauge_modifiers.rb +43 -0
  29. data/lib/fnordmetric/inbound_stream.rb +66 -0
  30. data/lib/fnordmetric/logger.rb +38 -0
  31. data/lib/fnordmetric/namespace.rb +120 -0
  32. data/lib/fnordmetric/numbers_widget.rb +29 -11
  33. data/lib/fnordmetric/session.rb +131 -0
  34. data/lib/fnordmetric/standalone.rb +31 -0
  35. data/lib/fnordmetric/timeline_widget.rb +29 -9
  36. data/lib/fnordmetric/widget.rb +50 -45
  37. data/lib/fnordmetric/worker.rb +80 -0
  38. data/pub/fnordmetric/fnordmetric.css +76 -9
  39. data/pub/fnordmetric/fnordmetric.js +541 -42
  40. data/pub/raphael-min.js +8 -0
  41. data/pub/raphael-utils.js +221 -0
  42. data/readme.rdoc +172 -27
  43. data/server.rb +22 -0
  44. data/spec/app_spec.rb +359 -117
  45. data/spec/context_spec.rb +42 -0
  46. data/spec/dashboard_spec.rb +7 -47
  47. data/spec/event_spec.rb +114 -33
  48. data/spec/gauge_modifiers_spec.rb +276 -0
  49. data/spec/gauge_spec.rb +128 -0
  50. data/spec/namespace_spec.rb +104 -0
  51. data/spec/session_spec.rb +231 -0
  52. data/spec/spec_helper.rb +27 -4
  53. data/spec/widget_spec.rb +81 -75
  54. data/spec/worker_spec.rb +37 -0
  55. data/test_stream.sh +187 -0
  56. data/ulm_stats.rb +198 -0
  57. metadata +114 -35
  58. data/lib/fnordmetric/core.rb +0 -66
  59. data/lib/fnordmetric/engine.rb +0 -3
data/Gemfile CHANGED
@@ -4,10 +4,16 @@ gem "mongoid", "~> 2.2.0"
4
4
  gem "mongo", "~> 1.4.0"
5
5
  gem "bson_ext", "~> 1.4.0"
6
6
  gem "sinatra", "~> 1.2.6"
7
+ gem "redis", "~> 2.2.2"
8
+ gem "eventmachine"
9
+ gem "em-hiredis"
7
10
  gem "json"
8
11
  gem "haml"
9
12
  gem "rack"
10
13
  gem "rack-test"
14
+ gem "yajl-ruby", :git => "git://github.com/brianmario/yajl-ruby.git"
15
+ gem "thin"
16
+
11
17
 
12
18
  group :development do
13
19
  gem "delorean", ">= 0"
data/Gemfile.lock CHANGED
@@ -1,3 +1,9 @@
1
+ GIT
2
+ remote: git://github.com/brianmario/yajl-ruby.git
3
+ revision: eef5c48be81b6404af66da3f185ec9301e5214d8
4
+ specs:
5
+ yajl-ruby (1.1.0)
6
+
1
7
  GEM
2
8
  remote: http://rubygems.org/
3
9
  specs:
@@ -13,11 +19,16 @@ GEM
13
19
  bson_ext (1.4.0)
14
20
  builder (3.0.0)
15
21
  chronic (0.6.4)
22
+ daemons (1.1.4)
16
23
  delorean (1.1.0)
17
24
  chronic
18
25
  diff-lcs (1.1.3)
26
+ em-hiredis (0.1.0)
27
+ hiredis (~> 0.3.0)
28
+ eventmachine (0.12.10)
19
29
  git (1.2.5)
20
30
  haml (3.1.2)
31
+ hiredis (0.3.2)
21
32
  i18n (0.6.0)
22
33
  jeweler (1.5.2)
23
34
  bundler (~> 1.0.0)
@@ -35,6 +46,7 @@ GEM
35
46
  rack-test (0.6.0)
36
47
  rack (>= 1.0)
37
48
  rake (0.9.2)
49
+ redis (2.2.2)
38
50
  rspec (2.6.0)
39
51
  rspec-core (~> 2.6.0)
40
52
  rspec-expectations (~> 2.6.0)
@@ -47,6 +59,10 @@ GEM
47
59
  sinatra (1.2.6)
48
60
  rack (~> 1.1)
49
61
  tilt (>= 1.2.2, < 2.0)
62
+ thin (1.2.11)
63
+ daemons (>= 1.0.9)
64
+ eventmachine (>= 0.12.6)
65
+ rack (>= 1.0.0)
50
66
  tilt (1.3.2)
51
67
  tzinfo (0.3.29)
52
68
 
@@ -57,6 +73,8 @@ DEPENDENCIES
57
73
  bson_ext (~> 1.4.0)
58
74
  bundler (~> 1.0.0)
59
75
  delorean
76
+ em-hiredis
77
+ eventmachine
60
78
  haml
61
79
  jeweler (~> 1.5.2)
62
80
  json
@@ -64,6 +82,9 @@ DEPENDENCIES
64
82
  mongoid (~> 2.2.0)
65
83
  rack
66
84
  rack-test
85
+ redis (~> 2.2.2)
67
86
  rspec (~> 2.6.0)
68
87
  shoulda
69
88
  sinatra (~> 1.2.6)
89
+ thin
90
+ yajl-ruby!
data/Procfile CHANGED
@@ -1,2 +1 @@
1
- app: bundle exec ruby zoe_app.rb
2
- switchboard: bundle exec ruby zoe_switchboard.rb
1
+ server: bundle exec ruby server.rb
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.2
1
+ 0.5.0
data/_spec/app_spec.rb ADDED
@@ -0,0 +1,178 @@
1
+ require ::File.expand_path('../spec_helper.rb', __FILE__)
2
+
3
+ include Rack::Test::Methods
4
+
5
+ describe "app" do
6
+
7
+ before(:each) do
8
+ FnordMetric::Event.destroy_all
9
+ end
10
+
11
+ def app
12
+ @app ||= FnordMetric::App
13
+ end
14
+
15
+ it "should redirect to the default dashboard" do
16
+ get "/"
17
+ last_response.status.should == 302
18
+ last_response.location.should == "http://example.org/dashboard/default"
19
+ end
20
+
21
+ it "should render the dashboard" do
22
+ FnordMetric.dashboard("Deine Mama"){|dash|}
23
+ get "/dashboard/default"
24
+ last_response.status.should == 200
25
+ last_response.body.should include("Deine Mama")
26
+ end
27
+
28
+ it "should render the right dashboard" do
29
+ FnordMetric.dashboard("Deine Mama"){|dash|}
30
+ FnordMetric.dashboard("My Dashboard"){|dash|}
31
+ get "/dashboard/DeineMama"
32
+ last_response.status.should == 200
33
+ last_response.body.should include("Deine Mama")
34
+ get "/dashboard/MyDashboard"
35
+ last_response.status.should == 200
36
+ last_response.body.should include("My Dashboard")
37
+ end
38
+
39
+ it "should track an event without auth" do
40
+ post "/events", :type => "myevent", :fnord => "foobar"
41
+ last_response.status.should == 200
42
+ FnordMetric::Event.last.type.should == "myevent"
43
+ FnordMetric::Event.last.fnord.should == "foobar"
44
+ end
45
+
46
+ it "should return 400 if no type is provided" do
47
+ post "/events", :fnord => "foobar"
48
+ last_response.status.should == 400
49
+ last_response.body.should == "please specify the event_type"
50
+ end
51
+
52
+ it "should track an event in the past" do
53
+ my_time = (Time.now-3.years).to_i
54
+ post "/events", :type => "myevent", :time => my_time
55
+ last_response.status.should == 200
56
+ FnordMetric::Event.last.type.should == "myevent"
57
+ FnordMetric::Event.last.time.should == my_time
58
+ end
59
+
60
+ it "should track an event with integer data" do
61
+ post "/events", :type => "myevent", :blubb => "123"
62
+ last_response.status.should == 200
63
+ FnordMetric::Event.last.type.should == "myevent"
64
+ FnordMetric::Event.last.blubb.should == 123
65
+ end
66
+
67
+ it "should track an event with float data" do
68
+ post "/events", :type => "myevent", :blubb => "42.23"
69
+ last_response.status.should == 200
70
+ FnordMetric::Event.last.type.should == "myevent"
71
+ FnordMetric::Event.last.blubb.should == 42.23
72
+ end
73
+
74
+
75
+ describe "metrics api" do
76
+
77
+ before(:each) do
78
+ FnordMetric::Event.destroy_all
79
+ FnordMetric.metric('my_event_count', :count => true, :types => [:my_event_type])
80
+ FnordMetric.track('my_event_type', :time => 33.hours.ago)
81
+ FnordMetric.track('my_event_type', :time => 32.hours.ago)
82
+ FnordMetric.track('my_event_type', :time => 29.hours.ago)
83
+ FnordMetric.track('my_event_type', :time => 27.hours.ago)
84
+ FnordMetric.track('my_event_type', :time => 26.hours.ago)
85
+ FnordMetric.track('my_event_type', :time => 13.hours.ago)
86
+ FnordMetric.track('my_event_type', :time => 12.hours.ago)
87
+ FnordMetric.track('my_event_type', :time => 2.hours.ago)
88
+ FnordMetric.track('my_event_type', :time => 3.hours.ago)
89
+ end
90
+
91
+ it "should return the right answer for: /metric/:name" do
92
+ get "/metric/my_event_count"
93
+ JSON.parse(last_response.body)["value"].to_i.should == 9
94
+ end
95
+
96
+ it "should return the right answer for: /metric/:name?at=timestamp" do
97
+ get "/metric/my_event_count", :at => 18.hours.ago.to_i.to_s
98
+ JSON.parse(last_response.body)["value"].to_i.should == 5
99
+ end
100
+
101
+ it "should return the right answer for: /metric/:name?at=timestamp-timstamp" do
102
+ get "/metric/my_event_count", :at => "#{30.hours.ago.to_i}-#{20.hours.ago.to_i}"
103
+ JSON.parse(last_response.body)["value"].to_i.should == 3
104
+ end
105
+
106
+ it "should return the right answer for: /metric/:name?at=timestamp-timstamp&tick=seconds" do
107
+ get "/metric/my_event_count", :at => "#{34.hours.ago.to_i}-#{1.hour.ago.to_i}", :tick => 6.hours.to_i, :delta => true
108
+ JSON.parse(last_response.body)["values"].length.should == 6
109
+ end
110
+
111
+ it "should return the right answer for: /metric/:name?at=timestamp-timstamp&tick=seconds" do
112
+ get "/metric/my_event_count", :at => "#{34.hours.ago.to_i}-#{1.hour.ago.to_i}", :tick => 6.hours.to_i, :delta => true
113
+ JSON.parse(last_response.body)["values"][0].first.should == 34.hours.ago.to_i
114
+ JSON.parse(last_response.body)["values"][0].last.should == 3
115
+ end
116
+
117
+ it "should return the right answer for: /metric/:name?at=timestamp-timstamp&tick=seconds" do
118
+ get "/metric/my_event_count", :at => "#{34.hours.ago.to_i}-#{1.hour.ago.to_i}", :tick => 6.hours.to_i, :delta => true
119
+ JSON.parse(last_response.body)["values"][1].first.should == 28.hours.ago.to_i
120
+ JSON.parse(last_response.body)["values"][1].last.should == 2
121
+ end
122
+
123
+ it "should return the right answer for: /metric/:name?at=timestamp-timstamp&tick=seconds" do
124
+ get "/metric/my_event_count", :at => "#{34.hours.ago.to_i}-#{1.hour.ago.to_i}", :tick => 6.hours.to_i, :delta => true
125
+ JSON.parse(last_response.body)["values"][2].first.should == 22.hours.ago.to_i
126
+ JSON.parse(last_response.body)["values"][2].last.should == 0
127
+ end
128
+
129
+ it "should return the right answer for: /metric/:name?at=timestamp-timstamp&tick=seconds" do
130
+ get "/metric/my_event_count", :at => "#{34.hours.ago.to_i}-#{1.hour.ago.to_i}", :tick => 6.hours.to_i, :delta => true
131
+ JSON.parse(last_response.body)["values"][3].first.should == 16.hours.ago.to_i
132
+ JSON.parse(last_response.body)["values"][3].last.should == 2
133
+ end
134
+
135
+ it "should return the right answer for: /metric/:name?at=timestamp-timstamp&tick=seconds" do
136
+ get "/metric/my_event_count", :at => "#{34.hours.ago.to_i}-#{1.hour.ago.to_i}", :tick => 6.hours.to_i, :delta => true
137
+ JSON.parse(last_response.body)["values"][5].first.should == 4.hours.ago.to_i
138
+ JSON.parse(last_response.body)["values"][5].last.should == 2
139
+ end
140
+
141
+ it "should return the right answer for: /metric/:name?at=timestamp-timstamp&tick=seconds" do
142
+ get "/metric/my_event_count", :at => "#{34.hours.ago.to_i}-#{1.hour.ago.to_i}", :tick => 6.hours.to_i
143
+ JSON.parse(last_response.body)["values"].length.should == 6
144
+ end
145
+
146
+ it "should return the right answer for: /metric/:name?at=timestamp-timstamp&tick=seconds" do
147
+ get "/metric/my_event_count", :at => "#{34.hours.ago.to_i}-#{1.hour.ago.to_i}", :tick => 6.hours.to_i
148
+ JSON.parse(last_response.body)["values"][0].first.should == 34.hours.ago.to_i
149
+ JSON.parse(last_response.body)["values"][0].last.should == 0
150
+ end
151
+
152
+ it "should return the right answer for: /metric/:name?at=timestamp-timstamp&tick=seconds" do
153
+ get "/metric/my_event_count", :at => "#{34.hours.ago.to_i}-#{1.hour.ago.to_i}", :tick => 6.hours.to_i
154
+ JSON.parse(last_response.body)["values"][1].first.should == 28.hours.ago.to_i
155
+ JSON.parse(last_response.body)["values"][1].last.should == 3
156
+ end
157
+
158
+ it "should return the right answer for: /metric/:name?at=timestamp-timstamp&tick=seconds" do
159
+ get "/metric/my_event_count", :at => "#{34.hours.ago.to_i}-#{1.hour.ago.to_i}", :tick => 6.hours.to_i
160
+ JSON.parse(last_response.body)["values"][2].first.should == 22.hours.ago.to_i
161
+ JSON.parse(last_response.body)["values"][2].last.should == 5
162
+ end
163
+
164
+ it "should return the right answer for: /metric/:name?at=timestamp-timstamp&tick=seconds" do
165
+ get "/metric/my_event_count", :at => "#{34.hours.ago.to_i}-#{1.hour.ago.to_i}", :tick => 6.hours.to_i
166
+ JSON.parse(last_response.body)["values"][3].first.should == 16.hours.ago.to_i
167
+ JSON.parse(last_response.body)["values"][3].last.should == 5
168
+ end
169
+
170
+ it "should return the right answer for: /metric/:name?at=timestamp-timstamp&tick=seconds" do
171
+ get "/metric/my_event_count", :at => "#{34.hours.ago.to_i}-#{1.hour.ago.to_i}", :tick => 6.hours.to_i
172
+ JSON.parse(last_response.body)["values"][5].first.should == 4.hours.ago.to_i
173
+ JSON.parse(last_response.body)["values"][5].last.should == 7
174
+ end
175
+
176
+ end
177
+
178
+ end
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,67 @@
1
+ require ::File.expand_path('../spec_helper.rb', __FILE__)
2
+
3
+ describe FnordMetric::Dashboard do
4
+
5
+ before(:each) do
6
+ FnordMetric::Event.destroy_all
7
+ FnordMetric.reset_metrics
8
+ end
9
+
10
+ it "should remember it's title" do
11
+ dashboard = FnordMetric::Dashboard.new(:title => 'My Foobar Dashboard'){ |dash| }
12
+ dashboard.title.should == 'My Foobar Dashboard'
13
+ end
14
+
15
+ it "should build a token" do
16
+ dashboard = FnordMetric::Dashboard.new(:title => 'My!F00bar-.Dash_board'){ |dash| }
17
+ dashboard.token.should == 'MyF00barDash_board'
18
+ end
19
+
20
+ it "should add a widget" do
21
+ dashboard = FnordMetric::Dashboard.new(:title => 'My!F00bar-.Dash_board'){ |dash| }
22
+ FnordMetric.metric(:my_metric, :sum => :my_field)
23
+ widget = FnordMetric.widget(:my_widget, :metrics => :my_metric, :title => "My Widget", :type => :timeline)
24
+ dashboard.add_widget(widget)
25
+ dashboard.widgets.first.should == widget
26
+ end
27
+
28
+ it "should add a widget by name" do
29
+ dashboard = FnordMetric::Dashboard.new(:title => 'My!F00bar-.Dash_board'){ |dash| }
30
+ FnordMetric.metric(:my_metric, :sum => :my_field)
31
+ widget = FnordMetric.widget(:my_widget, :metrics => :my_metric, :title => "My Widget", :type => :timeline)
32
+ dashboard.add_widget(:my_widget)
33
+ dashboard.widgets.first.should == widget
34
+ end
35
+
36
+ it "should add the report on init (and to all widgets)" do
37
+ FnordMetric.metric(:my_metric, :sum => :my_field)
38
+ report = FnordMetric.report(:range => (4.days.ago..Time.now))
39
+ dashboard = FnordMetric::Dashboard.new(:title => 'My Foobar Dashboard', :report => report){ |dash|
40
+ dash.add_widget FnordMetric.widget(:my_widget, :metrics => :my_metric, :title => "My Widget", :type => :timeline)
41
+ }
42
+ dashboard.report.should == report
43
+ dashboard.widgets.last.report.should == report
44
+ end
45
+
46
+ it "should add the report after init (and to all widgets)" do
47
+ FnordMetric.metric(:my_metric, :sum => :my_field)
48
+ report = FnordMetric.report(:range => (4.days.ago..Time.now))
49
+ dashboard = FnordMetric::Dashboard.new(:title => 'My Foobar Dashboard'){ |dash|
50
+ dash.add_widget FnordMetric.widget(:my_widget, :metrics => :my_metric, :title => "My Widget", :type => :timeline)
51
+ }
52
+ dashboard.report.should == nil
53
+ dashboard.add_report(report)
54
+ dashboard.report.should == report
55
+ dashboard.widgets.last.report.should == report
56
+ end
57
+
58
+ it "should call the config block" do
59
+ block_called = false
60
+ FnordMetric::Dashboard.new(:title => 'My Dashboard') do |dash|
61
+ block_called = true
62
+ dash.should be_a(FnordMetric::Dashboard)
63
+ end
64
+ block_called.should be_true
65
+ end
66
+
67
+ end
@@ -0,0 +1,46 @@
1
+ require ::File.expand_path('../spec_helper.rb', __FILE__)
2
+
3
+ include FnordMetric
4
+
5
+ describe "event" do
6
+
7
+ before(:each) do
8
+ Event.destroy_all
9
+ end
10
+
11
+ it "should track an event" do
12
+ event = Event.track!('_referral', :foobar => "fnord")
13
+ Event.last[:type].should == "_referral"
14
+ Event.last[:foobar].should == "fnord"
15
+ end
16
+
17
+ it "should track an event via the proxy method" do
18
+ FnordMetric.track('blubb', :foo => "bar")
19
+ FnordMetric::Event.last.foo.should == "bar"
20
+ end
21
+
22
+ it "should access info like a 'ostruct' object" do
23
+ event = Event.track!('_referral', :foobar => "fnord")
24
+ Event.last.type.should == "_referral"
25
+ Event.last.foobar.should == "fnord"
26
+ end
27
+
28
+ it "should insert a data point in the past" do
29
+ my_time = 23.minutes.ago
30
+ event = Event.track!('_referral', :foobar => "fnord", :time => my_time)
31
+ Event.last[:type].should == "_referral"
32
+ Event.last[:foobar].should == "fnord"
33
+ Event.last[:time].should == my_time.to_i
34
+ end
35
+
36
+ it "should save integer data" do
37
+ event = Event.track!('_test', :num => 23)
38
+ Event.last.num.should == 23
39
+ end
40
+
41
+ it "should save float data" do
42
+ event = Event.track!('_test', :num => 42.5)
43
+ Event.last.num.should == 42.5
44
+ end
45
+
46
+ end
File without changes
File without changes
File without changes
@@ -0,0 +1,107 @@
1
+ require ::File.expand_path('../spec_helper.rb', __FILE__)
2
+
3
+ describe FnordMetric::Widget do
4
+
5
+ before(:each) do
6
+ FnordMetric::Event.destroy_all
7
+ end
8
+
9
+ it "should remembe it's own title" do
10
+ widget = FnordMetric::Widget.new(:title => "My Widget")
11
+ widget.title.should == "My Widget"
12
+ end
13
+
14
+ it "should add the report on init" do
15
+ FnordMetric.metric(:my_metric, :sum => :my_field)
16
+ report = FnordMetric.report(:range => (4.days.ago..Time.now))
17
+ widget = FnordMetric::Widget.new(:report => report)
18
+ widget.report.should == report
19
+ end
20
+
21
+ it "should add the report after init" do
22
+ FnordMetric.metric(:my_metric, :sum => :my_field)
23
+ report = FnordMetric.report(:range => (4.days.ago..Time.now))
24
+ widget = FnordMetric::Widget.new
25
+ widget.report.should be_nil
26
+ widget.add_report(report)
27
+ widget.report.should == report
28
+ end
29
+
30
+ it "should define a new widget when given two metric-token" do
31
+ FnordMetric.metric(:first_metric, :count => :true)
32
+ FnordMetric.metric(:second_metric, :count => :true)
33
+ widget = FnordMetric::Widget.new(:metrics => [:first_metric, :second_metric], :title => "My Widget", :type => :timeline)
34
+ widget.metrics.length.should == 2
35
+ widget.metrics.first.should be_a(FnordMetric::CountMetric)
36
+ widget.metrics.first.token.should == :first_metric
37
+ widget.metrics.last.should be_a(FnordMetric::CountMetric)
38
+ widget.metrics.last.token.should == :second_metric
39
+ end
40
+
41
+ it "should define a new widget when given two metrics" do
42
+ my_metrics = [
43
+ FnordMetric.metric(:first_metric, :count => :true),
44
+ FnordMetric.metric(:second_metric, :count => :true)
45
+ ]
46
+ widget = FnordMetric::Widget.new(:metrics => my_metrics, :title => "My Widget", :type => :timeline)
47
+ widget.metrics.length.should == 2
48
+ widget.metrics.first.should be_a(FnordMetric::CountMetric)
49
+ widget.metrics.first.token.should == :first_metric
50
+ widget.metrics.last.should be_a(FnordMetric::CountMetric)
51
+ widget.metrics.last.token.should == :second_metric
52
+ end
53
+
54
+ it "should return the right ticks for 1h intervals" do
55
+ t = Time.now
56
+ widget = FnordMetric::Widget.new(:range => (t-2.days)..t, :tick => 1.hour)
57
+ widget.ticks.length.should == 49
58
+ ranges_should_match! widget.ticks.first, ((t-48.hours)..(t-47.hours))
59
+ ranges_should_match! widget.ticks.last, (t..(t+1.hour))
60
+ end
61
+
62
+ it "should generate a default range for daily graphs" do
63
+ widget = FnordMetric::Widget.new(:tick => 1.day)
64
+ Delorean.time_travel_to(Time.utc(1992,01,13,18,23,23)) do
65
+ widget.default_range.first.should == Time.utc(1991,12,15,00,00,00)
66
+ widget.default_range.last.should == Time.utc(1992,1,13,23,59,59)
67
+ end
68
+ end
69
+
70
+ it "should generate ticks with default range for daily graphs" do
71
+ widget = FnordMetric::Widget.new(:tick => 1.day)
72
+ Delorean.time_travel_to(Time.utc(1992,01,13,18,23,23)) do
73
+ widget.ticks.length.should == 30
74
+ widget.ticks.first.first.utc.should == Time.utc(1991,12,15,00,00,00)
75
+ widget.ticks.first.last.utc.should == Time.utc(1991,12,16,00,00,00)
76
+ widget.ticks.last.first.utc.should == Time.utc(1992,1,13,0,0,0)
77
+ widget.ticks.last.last.utc.should == Time.utc(1992,1,14,0,0,0)
78
+ end
79
+ end
80
+
81
+ it "should generate a default range for hourly graphs" do
82
+ widget = FnordMetric::Widget.new(:tick => 1.hour)
83
+ Delorean.time_travel_to(Time.utc(1992,01,13,18,23,23)) do
84
+ widget.default_range.first.should == Time.utc(1992,1,12,19,00,00)
85
+ widget.default_range.last.should == Time.utc(1992,1,13,18,59,59)
86
+ end
87
+ end
88
+
89
+ it "should generate a default range for hourly graphs" do
90
+ widget = FnordMetric::Widget.new(:tick => 1.hour)
91
+ Delorean.time_travel_to(Time.utc(1992,01,13,18,23,23)) do
92
+ widget.ticks.length.should == 24
93
+ widget.ticks.first.first.utc.should == Time.utc(1992,1,12,19,00,00)
94
+ widget.ticks.first.last.utc.should == Time.utc(1992,1,12,20,00,00)
95
+ widget.ticks.last.first.utc.should == Time.utc(1992,1,13,18,0,0)
96
+ widget.ticks.last.last.utc.should == Time.utc(1992,1,13,19,00,00)
97
+ end
98
+ end
99
+
100
+ private
101
+
102
+ def ranges_should_match!(a, b)
103
+ (a.first.to_i - b.first.to_i).should == 0
104
+ (a.last.to_i - b.last.to_i).should == 0
105
+ end
106
+
107
+ end