blackbeard 0.0.4.0 → 0.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.
- 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