blackbeard 0.0.4.0 → 0.0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +44 -16
- data/TODO.md +3 -1
- data/dashboard/routes/cohorts.rb +25 -0
- data/dashboard/routes/features.rb +7 -4
- data/dashboard/routes/groups.rb +6 -3
- data/dashboard/routes/metrics.rb +25 -5
- data/dashboard/routes/tests.rb +6 -3
- data/dashboard/views/cohorts/index.erb +22 -0
- data/dashboard/views/cohorts/show.erb +41 -0
- data/dashboard/views/groups/show.erb +2 -2
- data/dashboard/views/layout.erb +1 -0
- data/dashboard/views/metrics/show.erb +37 -10
- data/dashboard/views/shared/_charts.erb +20 -0
- data/lib/blackbeard/chart.rb +65 -0
- data/lib/blackbeard/chartable.rb +47 -0
- data/lib/blackbeard/cohort.rb +48 -0
- data/lib/blackbeard/cohort_data.rb +72 -0
- data/lib/blackbeard/cohort_metric.rb +47 -0
- data/lib/blackbeard/context.rb +11 -2
- data/lib/blackbeard/dashboard.rb +2 -3
- data/lib/blackbeard/dashboard_helpers.rb +0 -22
- data/lib/blackbeard/errors.rb +2 -0
- data/lib/blackbeard/group.rb +3 -0
- data/lib/blackbeard/group_metric.rb +39 -0
- data/lib/blackbeard/metric.rb +30 -14
- data/lib/blackbeard/metric_data/base.rb +18 -35
- data/lib/blackbeard/metric_data/total.rb +2 -1
- data/lib/blackbeard/metric_data/uid_generator.rb +38 -0
- data/lib/blackbeard/metric_data/unique.rb +1 -1
- data/lib/blackbeard/metric_date.rb +10 -0
- data/lib/blackbeard/metric_hour.rb +8 -0
- data/lib/blackbeard/pirate.rb +18 -0
- data/lib/blackbeard/redis_store.rb +10 -1
- data/lib/blackbeard/storable.rb +1 -0
- data/lib/blackbeard/version.rb +1 -1
- data/spec/chart_spec.rb +38 -0
- data/spec/chartable_spec.rb +56 -0
- data/spec/cohort_data_spec.rb +142 -0
- data/spec/cohort_metric_spec.rb +26 -0
- data/spec/cohort_spec.rb +31 -0
- data/spec/context_spec.rb +9 -1
- data/spec/dashboard/cohorts_spec.rb +43 -0
- data/spec/dashboard/groups_spec.rb +0 -7
- data/spec/dashboard/metrics_spec.rb +35 -0
- data/spec/group_metric_spec.rb +26 -0
- data/spec/metric_data/base_spec.rb +0 -16
- data/spec/metric_data/uid_generator_spec.rb +40 -0
- data/spec/metric_spec.rb +23 -12
- data/spec/pirate_spec.rb +22 -1
- data/spec/redis_store_spec.rb +8 -2
- data/spec/storable_spec.rb +3 -0
- metadata +29 -3
- data/dashboard/views/metrics/_metric_data.erb +0 -59
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
module Blackbeard
|
4
|
+
describe CohortMetric do
|
5
|
+
let(:metric) { Metric.create(:total, "one-total") }
|
6
|
+
let(:cohort) { Cohort.create(:example) }
|
7
|
+
let(:cohort_metric){ CohortMetric.new( cohort, metric) }
|
8
|
+
let(:metric_data) { cohort_metric.metric_data }
|
9
|
+
|
10
|
+
describe "add" do
|
11
|
+
let(:context) { double(:unique_identifier => 'uid', :controller => double, :user => double) }
|
12
|
+
|
13
|
+
it "should increment metric data" do
|
14
|
+
cohort.should_receive(:hour_id_for_participant).with('uid').and_return("2014010101")
|
15
|
+
metric_data.should_receive(:add_at).with("2014010101","uid",1)
|
16
|
+
cohort_metric.add(context, 1)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should not increment non participants" do
|
20
|
+
cohort.should_receive(:hour_id_for_participant).with('uid').and_return(nil)
|
21
|
+
metric_data.should_not_receive(:add_at).with("2014010101","uid",1)
|
22
|
+
cohort_metric.add(context, 1)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/spec/cohort_spec.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
module Blackbeard
|
4
|
+
describe Cohort do
|
5
|
+
let(:uid){ "an id" }
|
6
|
+
let(:hour){ Time.new(2014,3,5,1) }
|
7
|
+
let(:cohort) { Cohort.new(:happy) }
|
8
|
+
let(:cohort_data) { CohortData.new(cohort) }
|
9
|
+
|
10
|
+
describe "add" do
|
11
|
+
let(:context){ double :unique_identifier => uid }
|
12
|
+
before :each do
|
13
|
+
cohort.stub(:data).and_return(cohort_data)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should save the cohort if its new" do
|
17
|
+
cohort.should_receive(:save)
|
18
|
+
cohort.add(context)
|
19
|
+
end
|
20
|
+
it "should call add_with_force if forced used" do
|
21
|
+
cohort_data.should_receive(:add_with_force).with(uid, hour).and_return(true)
|
22
|
+
cohort.add(context, hour, true).should be_true
|
23
|
+
end
|
24
|
+
it "should call add_without_force if not forced used" do
|
25
|
+
cohort_data.should_receive(:add_without_force).with(uid, hour).and_return(true)
|
26
|
+
cohort.add(context, hour).should be_true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
data/spec/context_spec.rb
CHANGED
@@ -9,6 +9,7 @@ module Blackbeard
|
|
9
9
|
let(:total_metric) { Metric.create(:total, :things) }
|
10
10
|
let(:unique_metric) { Metric.create(:unique, :things) }
|
11
11
|
let(:test) { Test.create(:example_test) }
|
12
|
+
let(:cohort) { Cohort.create(:joined) }
|
12
13
|
|
13
14
|
describe "#add_total" do
|
14
15
|
it "should call add on the total metric" do
|
@@ -26,6 +27,14 @@ module Blackbeard
|
|
26
27
|
end
|
27
28
|
end
|
28
29
|
|
30
|
+
describe "#add_to_cohort" do
|
31
|
+
it "should call add on the cohort" do
|
32
|
+
pirate.should_receive(:cohort).with("joined"){ cohort }
|
33
|
+
cohort.should_receive(:add).with(context, nil, false)
|
34
|
+
context.add_to_cohort(:joined)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
29
38
|
describe "#ab_test" do
|
30
39
|
before :each do
|
31
40
|
pirate.should_receive(:test).with(test.id).and_return(test)
|
@@ -94,7 +103,6 @@ module Blackbeard
|
|
94
103
|
inactive_feature.should_receive(:active_for?).with(context).and_return(false)
|
95
104
|
context.feature_active?(:inactive_feature).should be_false
|
96
105
|
end
|
97
|
-
|
98
106
|
end
|
99
107
|
|
100
108
|
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 /cohorts" do
|
13
|
+
it "should list all the groups" do
|
14
|
+
Cohort.create("jostling")
|
15
|
+
get "/cohorts"
|
16
|
+
|
17
|
+
last_response.should be_ok
|
18
|
+
last_response.body.should include('cohorts')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "get /cohorts/:id" do
|
23
|
+
it "should show a metric" do
|
24
|
+
cohort = Cohort.create("jostling")
|
25
|
+
get "/cohorts/#{cohort.id}"
|
26
|
+
|
27
|
+
last_response.should be_ok
|
28
|
+
last_response.body.should include("jostling")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "post /cohorts/:id" do
|
33
|
+
it "should update the cohort" do
|
34
|
+
cohort = Cohort.create("jostling")
|
35
|
+
post "/cohorts/#{cohort.id}", :name => 'hello'
|
36
|
+
|
37
|
+
last_response.should be_ok
|
38
|
+
Cohort.find("jostling").name.should == 'hello'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -9,13 +9,6 @@ module Blackbeard
|
|
9
9
|
|
10
10
|
let(:app) { Dashboard }
|
11
11
|
|
12
|
-
describe "get /" do
|
13
|
-
it "should redirect" do
|
14
|
-
get "/"
|
15
|
-
last_response.should be_ok
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
12
|
describe "get /groups" do
|
20
13
|
it "should list all the groups" do
|
21
14
|
Group.create("jostling")
|
@@ -27,6 +27,27 @@ module Blackbeard
|
|
27
27
|
last_response.should be_ok
|
28
28
|
last_response.body.should include("jostling")
|
29
29
|
end
|
30
|
+
|
31
|
+
it "should show a metric with a group" do
|
32
|
+
metric = Metric.create("total", "jostling")
|
33
|
+
group = Group.create(:example)
|
34
|
+
metric.add_group(group)
|
35
|
+
get "/metrics/#{metric.type}/#{metric.type_id}", :group_id => group.id
|
36
|
+
|
37
|
+
last_response.should be_ok
|
38
|
+
last_response.body.should include("jostling")
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should show a metric with a cohort" do
|
42
|
+
metric = Metric.create("total", "jostling")
|
43
|
+
cohort = Cohort.create(:example)
|
44
|
+
metric.add_cohort(cohort)
|
45
|
+
get "/metrics/#{metric.type}/#{metric.type_id}", :cohort_id => cohort.id
|
46
|
+
|
47
|
+
last_response.should be_ok
|
48
|
+
last_response.body.should include("jostling")
|
49
|
+
end
|
50
|
+
|
30
51
|
end
|
31
52
|
|
32
53
|
describe "post /metrics/:type/:type_id" do
|
@@ -53,5 +74,19 @@ module Blackbeard
|
|
53
74
|
end
|
54
75
|
|
55
76
|
|
77
|
+
describe "post /metrics/:type/:type_id/cohorts" do
|
78
|
+
it "should add a cohort to the metric" do
|
79
|
+
metric = Metric.create("total", "jostling")
|
80
|
+
cohort = Cohort.create("admin")
|
81
|
+
post "/metrics/#{metric.type}/#{metric.type_id}/cohorts", :cohort_id => cohort.id
|
82
|
+
|
83
|
+
last_response.should be_redirect
|
84
|
+
follow_redirect!
|
85
|
+
last_request.url.should == "http://example.org/metrics/#{metric.type}/#{metric.type_id}?cohort_id=#{cohort.id}"
|
86
|
+
metric.has_cohort?(cohort).should be_true
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
|
56
91
|
end
|
57
92
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
module Blackbeard
|
4
|
+
describe GroupMetric do
|
5
|
+
let(:metric) { Metric.create(:total, "one-total") }
|
6
|
+
let(:group) { Group.create(:example) }
|
7
|
+
let(:metric_data) { group_metric.metric_data }
|
8
|
+
# let(:group_metric_data) { metric.metric_data(group) }
|
9
|
+
let(:group_metric){ GroupMetric.new( group, metric) }
|
10
|
+
describe "add" do
|
11
|
+
let(:context) { double(:unique_identifier => 'uid', :controller => double, :user => double) }
|
12
|
+
|
13
|
+
it "should increment metric data" do
|
14
|
+
group.stub(:segment_for).and_return("segment")
|
15
|
+
metric_data.should_receive(:add).with("uid",1, "segment")
|
16
|
+
group_metric.add(context, 1)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should not increment nil segments" do
|
20
|
+
group.stub(:segment_for).and_return(nil)
|
21
|
+
metric_data.should_not_receive(:add).with("uid",1, "segment")
|
22
|
+
group_metric.add(context, 1)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -27,22 +27,6 @@ module Blackbeard
|
|
27
27
|
end
|
28
28
|
end
|
29
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
30
|
describe "hour_keys_for_day" do
|
47
31
|
it "should return 1 key for every hour from morning to night" do
|
48
32
|
keys_for_day = metric_data.hour_keys_for_day(Date.new(2014,1,1))
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
module Blackbeard
|
4
|
+
module MetricData
|
5
|
+
|
6
|
+
describe UidGenerator do
|
7
|
+
let(:metric) { Blackbeard::Metric.new(:total, "one-total") }
|
8
|
+
let(:metric2) { Blackbeard::Metric.new(:total, "two-total") }
|
9
|
+
let(:metric_data) { metric.metric_data }
|
10
|
+
let(:metric_data2) { metric2.metric_data }
|
11
|
+
|
12
|
+
context "already existing uid" do
|
13
|
+
it "should return the existing uid" do
|
14
|
+
UidGenerator.new(metric_data).uid.should == UidGenerator.new(metric_data).uid
|
15
|
+
end
|
16
|
+
end
|
17
|
+
context "new metric_data" do
|
18
|
+
it "should increment to the next uid" do
|
19
|
+
uid = UidGenerator.new(metric_data).uid
|
20
|
+
UidGenerator.new(metric_data2).uid.to_i.should == uid.to_i + 1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "lookup field" do
|
25
|
+
context "with a cohort" do
|
26
|
+
it "should return the field unique to cohort" do
|
27
|
+
metric.save
|
28
|
+
cohort = Cohort.create(:example_cohort)
|
29
|
+
cohort_metric = CohortMetric.new(cohort, metric)
|
30
|
+
metric.add_cohort(cohort)
|
31
|
+
gen1 = UidGenerator.new(cohort_metric.metric_data)
|
32
|
+
gen2 = UidGenerator.new(metric.metric_data)
|
33
|
+
gen1.send(:lookup_field).should_not == gen2.send(:lookup_field)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
data/spec/metric_spec.rb
CHANGED
@@ -3,9 +3,7 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
3
3
|
module Blackbeard
|
4
4
|
describe Metric do
|
5
5
|
let(:metric) { Metric.create(:total, "one-total") }
|
6
|
-
let(:group) { Group.create(:example) }
|
7
6
|
let(:metric_data) { metric.metric_data }
|
8
|
-
let(:group_metric_data) { metric.metric_data(group) }
|
9
7
|
|
10
8
|
describe "self.all" do
|
11
9
|
before :each do
|
@@ -20,31 +18,31 @@ module Blackbeard
|
|
20
18
|
|
21
19
|
describe "add" do
|
22
20
|
let(:context) { double(:unique_identifier => 'uid', :controller => double, :user => double) }
|
23
|
-
before :each do
|
24
|
-
metric.stub(:groups).and_return([group])
|
25
|
-
end
|
26
21
|
|
27
22
|
it "should increment metric data" do
|
28
23
|
metric_data.should_receive(:add).with("uid",1)
|
29
24
|
metric.add(context, 1)
|
30
25
|
end
|
31
26
|
|
32
|
-
it "should
|
33
|
-
|
34
|
-
|
27
|
+
it "should call add on all group metrics" do
|
28
|
+
group_metric = double
|
29
|
+
metric.should_receive(:group_metrics).and_return([group_metric])
|
30
|
+
group_metric.should_receive(:add).with(context, 1)
|
35
31
|
metric.add(context, 1)
|
36
32
|
end
|
37
33
|
|
38
|
-
it "should
|
39
|
-
|
40
|
-
|
34
|
+
it "should call add on all cohort metrics" do
|
35
|
+
cohort_metric = double
|
36
|
+
metric.should_receive(:cohort_metrics).and_return([cohort_metric])
|
37
|
+
cohort_metric.should_receive(:add).with(context, 1)
|
41
38
|
metric.add(context, 1)
|
42
39
|
end
|
40
|
+
|
43
41
|
end
|
44
42
|
|
45
43
|
describe "addable_groups" do
|
44
|
+
let!(:group) { Group.create(:example) }
|
46
45
|
it "should include the groups not added" do
|
47
|
-
group # to initialize it
|
48
46
|
metric.addable_groups.map{|g| g.id }.should include(group.id)
|
49
47
|
end
|
50
48
|
|
@@ -54,5 +52,18 @@ module Blackbeard
|
|
54
52
|
end
|
55
53
|
end
|
56
54
|
|
55
|
+
describe "addable_cohorts" do
|
56
|
+
let!(:cohort){ Cohort.create(:example)}
|
57
|
+
|
58
|
+
it "should include the groups not added" do
|
59
|
+
metric.addable_cohorts.map{|g| g.id }.should include(cohort.id)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should not include the group added" do
|
63
|
+
metric.add_cohort(cohort)
|
64
|
+
metric.addable_cohorts.map{|c| c.id }.should_not include(cohort.id)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
57
68
|
end
|
58
69
|
end
|
data/spec/pirate_spec.rb
CHANGED
@@ -21,6 +21,11 @@ describe Blackbeard::Pirate do
|
|
21
21
|
4.times{ pirate.feature(name) }
|
22
22
|
end
|
23
23
|
|
24
|
+
it "should get cohorts once" do
|
25
|
+
Blackbeard::Cohort.should_receive(:find_or_create).with(name).once.and_return(double)
|
26
|
+
4.times{ pirate.cohort(name) }
|
27
|
+
end
|
28
|
+
|
24
29
|
end
|
25
30
|
|
26
31
|
describe "#context" do
|
@@ -45,10 +50,14 @@ describe Blackbeard::Pirate do
|
|
45
50
|
expect{ pirate.ab_test(:example, :on => 1, :off => 2) }.to_not raise_error
|
46
51
|
end
|
47
52
|
|
48
|
-
it "
|
53
|
+
it "feature_active? should not raise error" do
|
49
54
|
expect{ pirate.feature_active?(:example) }.to_not raise_error
|
50
55
|
end
|
51
56
|
|
57
|
+
it "add_to_cohort should not raise error" do
|
58
|
+
expect{ pirate.add_to_cohort(:example) }.to_not raise_error
|
59
|
+
end
|
60
|
+
|
52
61
|
end
|
53
62
|
context "with context set" do
|
54
63
|
let(:user){ double }
|
@@ -73,6 +82,18 @@ describe Blackbeard::Pirate do
|
|
73
82
|
set_context.should_receive(:feature_active?).with(:example_feature).and_return(false)
|
74
83
|
pirate.feature_active?(:example_feature)
|
75
84
|
end
|
85
|
+
|
86
|
+
it "should delegate add_to_cohort" do
|
87
|
+
timestamp = double
|
88
|
+
set_context.should_receive(:add_to_cohort).with(:example, timestamp).and_return(true)
|
89
|
+
pirate.add_to_cohort(:example, timestamp)
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should delegate add_to_cohort!" do
|
93
|
+
timestamp = double
|
94
|
+
set_context.should_receive(:add_to_cohort!).with(:example, timestamp).and_return(true)
|
95
|
+
pirate.add_to_cohort!(:example, timestamp)
|
96
|
+
end
|
76
97
|
end
|
77
98
|
end
|
78
99
|
|
data/spec/redis_store_spec.rb
CHANGED
@@ -14,9 +14,9 @@ module Blackbeard
|
|
14
14
|
db.hash_get('a_hash', 'hello').should == 'world'
|
15
15
|
end
|
16
16
|
|
17
|
-
it "should multi set" do
|
17
|
+
it "should multi set and get" do
|
18
18
|
db.hash_multi_set('a_hash', {:one => 'two', :three => 'four'})
|
19
|
-
db.
|
19
|
+
db.hash_multi_get('a_hash',['three','one']).should == ['four','two']
|
20
20
|
end
|
21
21
|
|
22
22
|
it "should not raise error on multi set with empty hash" do
|
@@ -52,6 +52,12 @@ module Blackbeard
|
|
52
52
|
db.hash_get('a_hash', 'field').should == "3.5"
|
53
53
|
end
|
54
54
|
|
55
|
+
it "should increment by int" do
|
56
|
+
db.hash_increment_by('a_hash', 'field', 1)
|
57
|
+
db.hash_increment_by('a_hash', 'field', 2.5)
|
58
|
+
db.hash_get('a_hash', 'field').should == "3"
|
59
|
+
end
|
60
|
+
|
55
61
|
it "should determine if key exists" do
|
56
62
|
expect{
|
57
63
|
db.hash_set('a_hash', 'field', 'exists')
|
data/spec/storable_spec.rb
CHANGED