fnordmetric 0.3.2 → 0.5.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.
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