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.
- checksums.yaml +4 -4
- data/.travis.yml +9 -0
- data/Guardfile +8 -0
- data/README.md +162 -20
- data/Rakefile +6 -0
- data/TODO.md +13 -34
- data/blackbeard.gemspec +5 -1
- data/console.rb +3 -0
- data/dashboard/public/bootstrap3-editable/css/bootstrap-editable.css +663 -0
- data/dashboard/public/bootstrap3-editable/img/clear.png +0 -0
- data/dashboard/public/bootstrap3-editable/img/loading.gif +0 -0
- data/dashboard/public/bootstrap3-editable/js/bootstrap-editable.min.js +7 -0
- data/dashboard/public/fonts/glyphicons-halflings-regular.eot +0 -0
- data/dashboard/public/fonts/glyphicons-halflings-regular.svg +229 -0
- data/dashboard/public/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/dashboard/public/fonts/glyphicons-halflings-regular.woff +0 -0
- data/dashboard/public/javascripts/bootstrap.min.js +7 -0
- data/dashboard/public/javascripts/jquery-1.10.2.min.js +6 -0
- data/dashboard/public/stylesheets/application.css +28 -0
- data/dashboard/public/stylesheets/bootstrap-theme.css +7 -0
- data/dashboard/public/stylesheets/bootstrap.css +7 -0
- data/dashboard/routes/base.rb +19 -0
- data/dashboard/routes/groups.rb +22 -0
- data/dashboard/routes/home.rb +11 -0
- data/dashboard/routes/metrics.rb +30 -0
- data/dashboard/routes/tests.rb +23 -0
- data/dashboard/views/groups/index.erb +22 -0
- data/dashboard/views/groups/show.erb +58 -0
- data/dashboard/views/index.erb +4 -0
- data/dashboard/views/layout.erb +48 -0
- data/dashboard/views/metrics/_metric_data.erb +59 -0
- data/dashboard/views/metrics/index.erb +23 -0
- data/dashboard/views/metrics/show.erb +73 -0
- data/dashboard/views/tests/index.erb +21 -0
- data/dashboard/views/tests/show.erb +58 -0
- data/lib/blackbeard/configuration.rb +8 -1
- data/lib/blackbeard/configuration_methods.rb +24 -0
- data/lib/blackbeard/context.rb +33 -21
- data/lib/blackbeard/dashboard.rb +17 -21
- data/lib/blackbeard/dashboard_helpers.rb +29 -0
- data/lib/blackbeard/errors.rb +2 -2
- data/lib/blackbeard/group.rb +35 -0
- data/lib/blackbeard/metric.rb +34 -32
- data/lib/blackbeard/metric_data/base.rb +101 -0
- data/lib/blackbeard/metric_data/total.rb +39 -0
- data/lib/blackbeard/metric_data/unique.rb +58 -0
- data/lib/blackbeard/metric_date.rb +11 -0
- data/lib/blackbeard/metric_hour.rb +17 -0
- data/lib/blackbeard/pirate.rb +33 -22
- data/lib/blackbeard/redis_store.rb +46 -2
- data/lib/blackbeard/selected_variation.rb +13 -0
- data/lib/blackbeard/storable.rb +39 -27
- data/lib/blackbeard/storable_attributes.rb +54 -0
- data/lib/blackbeard/storable_has_many.rb +60 -0
- data/lib/blackbeard/storable_has_set.rb +59 -0
- data/lib/blackbeard/test.rb +21 -0
- data/lib/blackbeard/version.rb +1 -1
- data/lib/blackbeard.rb +0 -8
- data/spec/configuration_spec.rb +15 -0
- data/spec/context_spec.rb +94 -19
- data/spec/dashboard/groups_spec.rb +50 -0
- data/spec/dashboard/home_spec.rb +20 -0
- data/spec/dashboard/metrics_spec.rb +57 -0
- data/spec/dashboard/tests_spec.rb +43 -0
- data/spec/group_spec.rb +36 -0
- data/spec/metric_data/base_spec.rb +57 -0
- data/spec/metric_data/total_spec.rb +116 -0
- data/spec/metric_data/unique_spec.rb +91 -0
- data/spec/metric_spec.rb +52 -44
- data/spec/pirate_spec.rb +32 -15
- data/spec/redis_store_spec.rb +121 -0
- data/spec/spec_helper.rb +13 -1
- data/spec/storable_attributes_spec.rb +47 -0
- data/spec/storable_has_many_spec.rb +49 -0
- data/spec/storable_has_set_spec.rb +39 -0
- data/spec/storable_spec.rb +33 -0
- data/spec/test_spec.rb +25 -0
- metadata +133 -17
- data/lib/blackbeard/dashboard/helpers.rb +0 -8
- data/lib/blackbeard/dashboard/views/layout.erb +0 -15
- data/lib/blackbeard/dashboard/views/metrics/index.erb +0 -10
- data/lib/blackbeard/dashboard/views/metrics/show.erb +0 -16
- data/lib/blackbeard/feature.rb +0 -13
- data/lib/blackbeard/metric/total.rb +0 -17
- data/lib/blackbeard/metric/unique.rb +0 -18
- data/spec/dashboard_spec.rb +0 -38
- data/spec/total_metric_spec.rb +0 -65
- 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
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
data/spec/group_spec.rb
ADDED
@@ -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
|