blackbeard 0.0.2.0 → 0.0.3.1
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.
- 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
|