blackbeard 0.0.2.0 → 0.0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +9 -0
  3. data/Guardfile +8 -0
  4. data/README.md +162 -20
  5. data/Rakefile +6 -0
  6. data/TODO.md +13 -34
  7. data/blackbeard.gemspec +5 -1
  8. data/console.rb +3 -0
  9. data/dashboard/public/bootstrap3-editable/css/bootstrap-editable.css +663 -0
  10. data/dashboard/public/bootstrap3-editable/img/clear.png +0 -0
  11. data/dashboard/public/bootstrap3-editable/img/loading.gif +0 -0
  12. data/dashboard/public/bootstrap3-editable/js/bootstrap-editable.min.js +7 -0
  13. data/dashboard/public/fonts/glyphicons-halflings-regular.eot +0 -0
  14. data/dashboard/public/fonts/glyphicons-halflings-regular.svg +229 -0
  15. data/dashboard/public/fonts/glyphicons-halflings-regular.ttf +0 -0
  16. data/dashboard/public/fonts/glyphicons-halflings-regular.woff +0 -0
  17. data/dashboard/public/javascripts/bootstrap.min.js +7 -0
  18. data/dashboard/public/javascripts/jquery-1.10.2.min.js +6 -0
  19. data/dashboard/public/stylesheets/application.css +28 -0
  20. data/dashboard/public/stylesheets/bootstrap-theme.css +7 -0
  21. data/dashboard/public/stylesheets/bootstrap.css +7 -0
  22. data/dashboard/routes/base.rb +19 -0
  23. data/dashboard/routes/groups.rb +22 -0
  24. data/dashboard/routes/home.rb +11 -0
  25. data/dashboard/routes/metrics.rb +30 -0
  26. data/dashboard/routes/tests.rb +23 -0
  27. data/dashboard/views/groups/index.erb +22 -0
  28. data/dashboard/views/groups/show.erb +58 -0
  29. data/dashboard/views/index.erb +4 -0
  30. data/dashboard/views/layout.erb +48 -0
  31. data/dashboard/views/metrics/_metric_data.erb +59 -0
  32. data/dashboard/views/metrics/index.erb +23 -0
  33. data/dashboard/views/metrics/show.erb +73 -0
  34. data/dashboard/views/tests/index.erb +21 -0
  35. data/dashboard/views/tests/show.erb +58 -0
  36. data/lib/blackbeard/configuration.rb +8 -1
  37. data/lib/blackbeard/configuration_methods.rb +24 -0
  38. data/lib/blackbeard/context.rb +33 -21
  39. data/lib/blackbeard/dashboard.rb +17 -21
  40. data/lib/blackbeard/dashboard_helpers.rb +29 -0
  41. data/lib/blackbeard/errors.rb +2 -2
  42. data/lib/blackbeard/group.rb +35 -0
  43. data/lib/blackbeard/metric.rb +34 -32
  44. data/lib/blackbeard/metric_data/base.rb +101 -0
  45. data/lib/blackbeard/metric_data/total.rb +39 -0
  46. data/lib/blackbeard/metric_data/unique.rb +58 -0
  47. data/lib/blackbeard/metric_date.rb +11 -0
  48. data/lib/blackbeard/metric_hour.rb +17 -0
  49. data/lib/blackbeard/pirate.rb +33 -22
  50. data/lib/blackbeard/redis_store.rb +46 -2
  51. data/lib/blackbeard/selected_variation.rb +13 -0
  52. data/lib/blackbeard/storable.rb +39 -27
  53. data/lib/blackbeard/storable_attributes.rb +54 -0
  54. data/lib/blackbeard/storable_has_many.rb +60 -0
  55. data/lib/blackbeard/storable_has_set.rb +59 -0
  56. data/lib/blackbeard/test.rb +21 -0
  57. data/lib/blackbeard/version.rb +1 -1
  58. data/lib/blackbeard.rb +0 -8
  59. data/spec/configuration_spec.rb +15 -0
  60. data/spec/context_spec.rb +94 -19
  61. data/spec/dashboard/groups_spec.rb +50 -0
  62. data/spec/dashboard/home_spec.rb +20 -0
  63. data/spec/dashboard/metrics_spec.rb +57 -0
  64. data/spec/dashboard/tests_spec.rb +43 -0
  65. data/spec/group_spec.rb +36 -0
  66. data/spec/metric_data/base_spec.rb +57 -0
  67. data/spec/metric_data/total_spec.rb +116 -0
  68. data/spec/metric_data/unique_spec.rb +91 -0
  69. data/spec/metric_spec.rb +52 -44
  70. data/spec/pirate_spec.rb +32 -15
  71. data/spec/redis_store_spec.rb +121 -0
  72. data/spec/spec_helper.rb +13 -1
  73. data/spec/storable_attributes_spec.rb +47 -0
  74. data/spec/storable_has_many_spec.rb +49 -0
  75. data/spec/storable_has_set_spec.rb +39 -0
  76. data/spec/storable_spec.rb +33 -0
  77. data/spec/test_spec.rb +25 -0
  78. metadata +133 -17
  79. data/lib/blackbeard/dashboard/helpers.rb +0 -8
  80. data/lib/blackbeard/dashboard/views/layout.erb +0 -15
  81. data/lib/blackbeard/dashboard/views/metrics/index.erb +0 -10
  82. data/lib/blackbeard/dashboard/views/metrics/show.erb +0 -16
  83. data/lib/blackbeard/feature.rb +0 -13
  84. data/lib/blackbeard/metric/total.rb +0 -17
  85. data/lib/blackbeard/metric/unique.rb +0 -18
  86. data/spec/dashboard_spec.rb +0 -38
  87. data/spec/total_metric_spec.rb +0 -65
  88. data/spec/unique_metric_spec.rb +0 -60
data/spec/context_spec.rb CHANGED
@@ -1,26 +1,101 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
- describe Blackbeard::Context do
4
- let(:pirate) { Blackbeard::Pirate.new }
5
- let(:context) { Blackbeard::Context.new(pirate, :user_id => 9) }
6
- let(:uid) { context.unique_identifier }
7
- let(:total_metric) { Blackbeard::Metric::Total.new(:total_things) }
8
- let(:unique_metric) { Blackbeard::Metric::Unique.new(:unique_things) }
9
-
10
- describe "#add_total" do
11
- it "should call add on the total metric" do
12
- pirate.should_receive(:total_metric).with(total_metric.name){ total_metric }
13
- total_metric.should_receive(:add).with(uid, 3)
14
- context.add_total( total_metric.name, 3 )
3
+ module Blackbeard
4
+ describe Context do
5
+ let(:pirate) { Pirate.new }
6
+ let(:user) { double(:id => 1) }
7
+ let(:context) { Context.new(pirate, user) }
8
+ let(:uid) { context.unique_identifier }
9
+ let(:total_metric) { Metric.new(:total, :things) }
10
+ let(:unique_metric) { Metric.new(:unique, :things) }
11
+ let(:test) { Test.new(:example_test) }
12
+
13
+ describe "#add_total" do
14
+ it "should call add on the total metric" do
15
+ pirate.should_receive(:metric).with(:total, total_metric.id){ total_metric }
16
+ total_metric.should_receive(:add).with(context, 3)
17
+ context.add_total( total_metric.id, 3 )
18
+ end
15
19
  end
16
- end
17
20
 
18
- describe "#add_unique" do
19
- it "should call add on the unique metric" do
20
- pirate.should_receive(:unique_metric).with(unique_metric.name){ unique_metric }
21
- unique_metric.should_receive(:add).with(uid)
22
- context.add_unique( unique_metric.name )
21
+ describe "#add_unique" do
22
+ it "should call add on the unique metric" do
23
+ pirate.should_receive(:metric).with(:unique, unique_metric.id){ unique_metric }
24
+ unique_metric.should_receive(:add).with(context, 1)
25
+ context.add_unique( unique_metric.id )
26
+ end
23
27
  end
24
- end
25
28
 
29
+ describe "#ab_test" do
30
+ before :each do
31
+ pirate.should_receive(:test).with(test.id).and_return(test)
32
+ end
33
+
34
+ it "should call select_variation on the test" do
35
+ test.should_receive(:add_variations).with([:on, :off]).and_return(test)
36
+ test.should_receive(:select_variation).and_return(:off)
37
+ context.ab_test(:example_test, :on => 1, :off => 2)
38
+ end
39
+
40
+ context "when passed options" do
41
+ before :each do
42
+ test.should_receive(:select_variation).and_return('double')
43
+ end
44
+
45
+ it "should return the value of selected option" do
46
+ context.ab_test(:example_test, :on => 1, :off => 2, :double => 'trouble').should == 'trouble'
47
+ end
48
+
49
+ it "should return nil when the selected variation is not an option" do
50
+ context.ab_test(:example_test, :on => 1, :off => 2).should be_nil
51
+ end
52
+ end
53
+
54
+ context "when not passed options" do
55
+ before :each do
56
+ test.should_receive(:select_variation).and_return('double')
57
+ end
58
+
59
+ it "should return a select_variation obj equal to the selected variation" do
60
+ test_result = context.ab_test(:example_test)
61
+ test_result.should be_a(Blackbeard::SelectedVariation)
62
+ test_result.should == :double
63
+ end
64
+ end
65
+
66
+ end
67
+
68
+ describe "unique_identifier" do
69
+ it "should work with users" do
70
+ Context.new(pirate, user, nil).unique_identifier.should == "a1"
71
+ end
72
+ it "should work without users" do
73
+ request = double(:cookies => {})
74
+ controller = double(:request => request)
75
+ Context.new(pirate, nil, controller).unique_identifier.should == "b1"
76
+ end
77
+ end
78
+
79
+ describe "#active?" do
80
+ let(:inactive_test) { Blackbeard::Test.new(:inactive_test) }
81
+ let(:active_test) { Blackbeard::Test.new(:active_test) }
82
+
83
+ before :each do
84
+ pirate.stub(:test).with(active_test.id).and_return(active_test)
85
+ pirate.stub(:test).with(inactive_test.id).and_return(inactive_test)
86
+ end
87
+
88
+ it "should return true when active" do
89
+ active_test.should_receive(:select_variation).and_return('active')
90
+ context.active?(:active_test).should be_true
91
+ end
92
+
93
+ it "should return true when active" do
94
+ inactive_test.should_receive(:select_variation).and_return('inactive')
95
+ context.active?(:inactive_test).should be_false
96
+ end
97
+
98
+ end
99
+
100
+ end
26
101
  end
@@ -0,0 +1,50 @@
1
+ require File.expand_path(File.dirname(__FILE__) + './../spec_helper')
2
+
3
+ require 'rack/test'
4
+ require 'blackbeard/dashboard'
5
+
6
+ module Blackbeard
7
+ describe Dashboard do
8
+ include Rack::Test::Methods
9
+
10
+ let(:app) { Dashboard }
11
+
12
+ describe "get /" do
13
+ it "should redirect" do
14
+ get "/"
15
+ last_response.should be_ok
16
+ end
17
+ end
18
+
19
+ describe "get /groups" do
20
+ it "should list all the groups" do
21
+ Group.new("jostling")
22
+ get "/groups"
23
+
24
+ last_response.should be_ok
25
+ last_response.body.should include('jostling')
26
+ end
27
+ end
28
+
29
+ describe "get /groups/:id" do
30
+ it "should show a metric" do
31
+ group = Group.new("jostling")
32
+ get "/groups/#{group.id}"
33
+
34
+ last_response.should be_ok
35
+ last_response.body.should include("jostling")
36
+ end
37
+ end
38
+
39
+ describe "post /groups/:id" do
40
+ it "should update the group" do
41
+ group = Group.new("jostling")
42
+ post "/groups/#{group.id}", :name => 'hello'
43
+
44
+ last_response.should be_ok
45
+ Group.new("jostling").name.should == 'hello'
46
+ end
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,20 @@
1
+ require File.expand_path(File.dirname(__FILE__) + './../spec_helper')
2
+
3
+ require 'rack/test'
4
+ require 'blackbeard/dashboard'
5
+
6
+ module Blackbeard
7
+ describe Dashboard do
8
+ include Rack::Test::Methods
9
+
10
+ let(:app) { Dashboard }
11
+
12
+ describe "get /" do
13
+ it "should redirect" do
14
+ get "/"
15
+ last_response.should be_ok
16
+ end
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,57 @@
1
+ require File.expand_path(File.dirname(__FILE__) + './../spec_helper')
2
+
3
+ require 'rack/test'
4
+ require 'blackbeard/dashboard'
5
+
6
+ module Blackbeard
7
+ describe Dashboard do
8
+ include Rack::Test::Methods
9
+
10
+ let(:app) { Dashboard }
11
+
12
+ describe "get /metrics" do
13
+ it "should list all the metrics" do
14
+ Metric.new("total", "jostling")
15
+ get "/metrics"
16
+
17
+ last_response.should be_ok
18
+ last_response.body.should include('jostling')
19
+ end
20
+ end
21
+
22
+ describe "get /metrics/:type/:type_id" do
23
+ it "should show a metric" do
24
+ metric = Metric.new("total", "jostling")
25
+ get "/metrics/#{metric.type}/#{metric.type_id}"
26
+
27
+ last_response.should be_ok
28
+ last_response.body.should include("jostling")
29
+ end
30
+ end
31
+
32
+ describe "post /metrics/:type/:type_id" do
33
+ it "should update the metric" do
34
+ metric = Metric.new("total", "jostling")
35
+ post "/metrics/#{metric.type}/#{metric.type_id}", :name => 'hello'
36
+
37
+ last_response.should be_ok
38
+ Metric.new(:total, "jostling").name.should == 'hello'
39
+ end
40
+ end
41
+
42
+ describe "post /metrics/:type/:type_id/groups" do
43
+ it "should add a group to the metric" do
44
+ metric = Metric.new("total", "jostling")
45
+ group = Group.new("admin")
46
+ post "/metrics/#{metric.type}/#{metric.type_id}/groups", :group_id => group.id
47
+
48
+ last_response.should be_redirect
49
+ follow_redirect!
50
+ last_request.url.should == "http://example.org/metrics/#{metric.type}/#{metric.type_id}?group_id=#{group.id}"
51
+ metric.has_group?(group).should be_true
52
+ end
53
+ end
54
+
55
+
56
+ end
57
+ end
@@ -0,0 +1,43 @@
1
+ require File.expand_path(File.dirname(__FILE__) + './../spec_helper')
2
+
3
+ require 'rack/test'
4
+ require 'blackbeard/dashboard'
5
+
6
+ module Blackbeard
7
+ describe Dashboard do
8
+ include Rack::Test::Methods
9
+
10
+ let(:app) { Dashboard }
11
+
12
+ describe "get /tests" do
13
+ it "should list all the test" do
14
+ Test.new("jostling")
15
+ get "/tests"
16
+
17
+ last_response.should be_ok
18
+ last_response.body.should include('jostling')
19
+ end
20
+ end
21
+
22
+ describe "get /tests/:id" do
23
+ it "should show a test" do
24
+ test = Test.new("jostling")
25
+ get "/tests/#{test.id}"
26
+
27
+ last_response.should be_ok
28
+ last_response.body.should include("jostling")
29
+ end
30
+ end
31
+
32
+ describe "post /tests/:id" do
33
+ it "should update the test" do
34
+ test = Test.new("jostling")
35
+ post "/tests/#{test.id}", :name => 'hello'
36
+
37
+ last_response.should be_ok
38
+ Test.new("jostling").name.should == 'hello'
39
+ end
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,36 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Blackbeard::Group do
4
+ let(:group){ Blackbeard::Group.new('example') }
5
+ let(:context){ double(:controller => double, :user => double) }
6
+ describe "segment" do
7
+ context "with no code defined" do
8
+ it "should return nil" do
9
+ group.segment_for(context).should be(nil)
10
+ end
11
+ end
12
+ context "with code defined" do
13
+ it "return nil for nil" do
14
+ Blackbeard.config.define_group(:example){ |r,u| nil }
15
+ group.segment_for(context).should be(nil)
16
+ end
17
+ it "return nil for false" do
18
+ Blackbeard.config.define_group(:example){ |r,u| false }
19
+ group.segment_for(context).should be(nil)
20
+ end
21
+ it "return string for true" do
22
+ Blackbeard.config.define_group(:example){ |r,u| true }
23
+ group.segment_for(context).should eq('example')
24
+ end
25
+ it "return string for string" do
26
+ Blackbeard.config.define_group(:example){ |r,u| 'foo' }
27
+ group.segment_for(context).should eq('foo')
28
+ end
29
+ it "return string for int" do
30
+ Blackbeard.config.define_group(:example){ |r,u| 12 }
31
+ group.segment_for(context).should eq('12')
32
+ end
33
+ end
34
+ end
35
+
36
+ end
@@ -0,0 +1,57 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ module Blackbeard
4
+ module MetricData
5
+ describe Base do
6
+ let(:metric) { Blackbeard::Metric.new(:total, "one-total") }
7
+ let(:metric2) { Blackbeard::Metric.new(:total, "two-total") }
8
+ let(:metric_data) { metric.metric_data }
9
+
10
+ describe "key" do
11
+ it "should auto increment" do
12
+ metric_data.key.should == "data::1"
13
+ metric2.metric_data.key.should == "data::2"
14
+ end
15
+ end
16
+
17
+ describe "hour_keys" do
18
+
19
+ it "should return an empty array if no metrics" do
20
+ metric_data.send(:hour_keys).should == []
21
+ end
22
+
23
+ it "should return an array for each hour" do
24
+ metric_data.add('user1', 1)
25
+ key = metric_data.send(:key_for_hour, tz.now)
26
+ metric_data.send(:hour_keys).should have(1).key
27
+ end
28
+ end
29
+
30
+ describe "recent_hours" do
31
+ let(:start_at) { Time.new(2014,1,1,12,0,0) }
32
+
33
+ it "should return results for recent hours" do
34
+ metric_data.recent_hours(3, start_at).should have(3).metric_hours
35
+ end
36
+ end
37
+
38
+ describe "recent_days" do
39
+ let(:start_on) { Date.new(2014,1,3) }
40
+
41
+ it "should return results for recent days" do
42
+ metric_data.recent_days(3, start_on).should have(3).metric_days
43
+ end
44
+ end
45
+
46
+ describe "hour_keys_for_day" do
47
+ it "should return 1 key for every hour from morning to night" do
48
+ keys_for_day = metric_data.hour_keys_for_day(Date.new(2014,1,1))
49
+ keys_for_day.should have(24).keys
50
+ keys_for_day.first.should == metric_data.send(:key_for_hour, Time.new(2014,1,1,0,0,0))
51
+ keys_for_day.last.should == metric_data.send(:key_for_hour, Time.new(2014,1,1,23,0,0))
52
+ end
53
+ end
54
+
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,116 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ module Blackbeard
4
+ module MetricData
5
+
6
+ describe Total do
7
+
8
+ let(:metric) { Blackbeard::Metric.new(:total, "page views") }
9
+ let(:metric_data) { metric.metric_data }
10
+ let(:uid) { "unique identifier" }
11
+ let(:ouid) { "other unique identifier" }
12
+
13
+ describe "add" do
14
+ it "should increment the metric by the amount" do
15
+ expect{
16
+ metric_data.add(uid, 2)
17
+ }.to change{ metric_data.result_for_hour(tz.now)["total"] }.from(nil).to(2)
18
+ end
19
+
20
+ it "should increment an existing amount" do
21
+ metric_data.add(uid, 1)
22
+ expect{
23
+ metric_data.add(uid, 2)
24
+ }.to change{ metric_data.result_for_hour(tz.now)["total"] }.from(1).to(3)
25
+ end
26
+
27
+ it "should handle negatives ok" do
28
+ metric_data.add(uid, 2)
29
+ expect{
30
+ metric_data.add(uid, -1)
31
+ }.to change{ metric_data.result_for_hour(tz.now)["total"] }.from(2).to(1)
32
+ end
33
+
34
+ it "should handle floats" do
35
+ metric_data.add(uid, 2.5)
36
+ expect{
37
+ metric_data.add(uid, 1.25)
38
+ }.to change{ metric_data.result_for_hour(tz.now)["total"] }.to(3.75)
39
+ end
40
+
41
+ context "with segment" do
42
+ it "should increment the segment" do
43
+ expect{
44
+ metric_data.add(uid, 1, "segment")
45
+ }.to change{ metric_data.result_for_hour(tz.now)["segment"] }.from(nil).to(1)
46
+ end
47
+ end
48
+
49
+
50
+ end
51
+
52
+
53
+
54
+ describe "result_for_hour" do
55
+ it "should return 0 if no metric has been recorded" do
56
+ metric_data.result_for_hour(tz.now).should be_empty
57
+ end
58
+
59
+ it "should return sum if metric called more than once" do
60
+ metric_data.add(uid, 2)
61
+ metric_data.add(uid, 4)
62
+ metric_data.result_for_hour(tz.now).should == {"total"=>6.0}
63
+ end
64
+ end
65
+
66
+ describe "result_for_day" do
67
+ let(:date) { Date.new(2014,1,1) }
68
+ context "result in db" do
69
+ before :each do
70
+ day_key = metric_data.send(:key_for_date, date)
71
+ db.hash_set(day_key, "total", 4)
72
+ end
73
+ it "should return the result from db" do
74
+ metric_data.result_for_day(date).should == {"total"=>4.0}
75
+ end
76
+ it "should not remerge the results" do
77
+ metric_data.should_not_receive(:generate_result_for_day).with(date)
78
+ metric_data.result_for_day(date)
79
+ end
80
+ end
81
+
82
+ context "result not in db" do
83
+ it "should merge hours" do
84
+ metric_data.should_receive(:generate_result_for_day).with(date).and_return({"total" => "2"})
85
+ metric_data.result_for_day(date).should == {"total" => 2.0 }
86
+ end
87
+ end
88
+ end
89
+
90
+
91
+ describe "generate_result_for_day" do
92
+ let(:date) { Date.new(2014,1,1) }
93
+ before :each do
94
+ at_1am = Time.new(2014,1,1,1)
95
+ metric_data.add_at(at_1am, '1' )
96
+ metric_data.add_at(at_1am, '2' )
97
+ at_2pm = Time.new(2014,1,1,14)
98
+ metric_data.add_at(at_2pm, '2' )
99
+ metric_data.add_at(at_2pm, '3' )
100
+ metric_data.add_at(at_2pm, '4' )
101
+ end
102
+
103
+ it "should sum the hours" do
104
+ metric_data.send(:generate_result_for_day, date).should == {"total" => 5.0}
105
+ end
106
+
107
+ it "should store the result if it's not today's result" do
108
+ day_key = metric_data.send(:key_for_date, date)
109
+ db.should_receive(:hash_multi_set).with(day_key, {"total" => 5})
110
+ metric_data.send(:generate_result_for_day, date)
111
+ end
112
+
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,91 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ module Blackbeard
4
+ module MetricData
5
+ describe Unique do
6
+
7
+ let(:metric) { Blackbeard::Metric.new(:unique, "join") }
8
+ let(:metric_data) { metric.metric_data }
9
+ let(:uid) { "unique identifier" }
10
+ let(:ouid) { "other unique identifier" }
11
+
12
+ describe "add" do
13
+ it "should increment the metric for the uid" do
14
+ expect{
15
+ metric_data.add(uid)
16
+ }.to change{ metric_data.result_for_hour(tz.now)["uniques"] }.from(nil).to(1)
17
+ end
18
+
19
+ it "should not increment the metric for duplicate uids" do
20
+ metric_data.add(uid)
21
+ expect{
22
+ metric_data.add(uid)
23
+ }.to_not change{ metric_data.result_for_hour(tz.now) }
24
+ end
25
+
26
+ context "with segment" do
27
+ it "should increment the segment" do
28
+ expect{
29
+ metric_data.add(uid, 1, "segment")
30
+ }.to change{ metric_data.result_for_hour(tz.now)["segment"] }
31
+ end
32
+
33
+ it "should not increment the global" do
34
+ expect{
35
+ metric_data.add(uid, 1, "segment")
36
+ }.to_not change{ metric_data.result_for_hour(tz.now)["uniques"] }
37
+ end
38
+ end
39
+
40
+ end
41
+
42
+ describe "result_for_hour" do
43
+ it "should empty if no metric has been recorded" do
44
+ metric_data.result_for_hour(tz.now).should be_empty
45
+ end
46
+
47
+ it "should return 1 if metric called once" do
48
+ metric_data.add(uid)
49
+ metric_data.result_for_hour(tz.now).should == {"uniques" => 1}
50
+ end
51
+
52
+ it "should return 1 if metric called more than once" do
53
+ 3.times{ metric_data.add(uid) }
54
+ metric_data.result_for_hour(tz.now).should == {"uniques" => 1}
55
+ end
56
+
57
+ it "should return 2 if metric was called with 2 uniques" do
58
+ metric_data.add(uid)
59
+ metric_data.add(ouid)
60
+ metric_data.result_for_hour(tz.now).should == {"uniques" => 2}
61
+ end
62
+
63
+ end
64
+
65
+ describe "generate_result_for_day" do
66
+ let(:date) { Date.new(2014,1,1) }
67
+ before :each do
68
+ at_1am = Time.new(2014,1,1,1)
69
+ metric_data.add_at(at_1am, '1' )
70
+ metric_data.add_at(at_1am, '2' )
71
+ at_2pm = Time.new(2014,1,1,14)
72
+ metric_data.add_at(at_2pm, '2' )
73
+ metric_data.add_at(at_2pm, '3' )
74
+ metric_data.add_at(at_2pm, '4' )
75
+ end
76
+
77
+ it "should sum the hours" do
78
+ metric_data.send(:generate_result_for_day, date).should == {"uniques" => 4}
79
+ end
80
+
81
+ it "should store the result if it's not today's result" do
82
+ day_key = metric_data.send(:key_for_date, date)
83
+ db.should_receive(:hash_multi_set).with(day_key, {"uniques" => 4})
84
+ metric_data.send(:generate_result_for_day, date)
85
+ end
86
+
87
+ end
88
+ end
89
+ end
90
+
91
+ end