blackbeard 0.0.3.1 → 0.0.4.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 +31 -20
- data/dashboard/public/stylesheets/application.css +4 -0
- data/dashboard/routes/features.rb +31 -0
- data/dashboard/routes/groups.rb +2 -2
- data/dashboard/routes/metrics.rb +6 -6
- data/dashboard/routes/tests.rb +2 -2
- data/dashboard/views/features/index.erb +21 -0
- data/dashboard/views/features/show.erb +163 -0
- data/dashboard/views/groups/show.erb +1 -1
- data/dashboard/views/layout.erb +2 -1
- data/lib/blackbeard.rb +18 -7
- data/lib/blackbeard/configuration.rb +3 -2
- data/lib/blackbeard/context.rb +11 -7
- data/lib/blackbeard/dashboard.rb +2 -0
- data/lib/blackbeard/errors.rb +4 -0
- data/lib/blackbeard/feature.rb +45 -0
- data/lib/blackbeard/feature_rollout.rb +47 -0
- data/lib/blackbeard/metric.rb +22 -4
- data/lib/blackbeard/pirate.rb +11 -5
- data/lib/blackbeard/redis_store.rb +4 -0
- data/lib/blackbeard/storable.rb +72 -6
- data/lib/blackbeard/storable_attributes.rb +50 -3
- data/lib/blackbeard/storable_has_many.rb +1 -0
- data/lib/blackbeard/storable_has_set.rb +1 -0
- data/lib/blackbeard/version.rb +1 -1
- data/spec/blackbeard_spec.rb +13 -0
- data/spec/configuration_spec.rb +6 -0
- data/spec/context_spec.rb +12 -12
- data/spec/dashboard/features_spec.rb +52 -0
- data/spec/dashboard/groups_spec.rb +4 -4
- data/spec/dashboard/metrics_spec.rb +6 -6
- data/spec/dashboard/tests_spec.rb +4 -4
- data/spec/feature_rollout_spec.rb +147 -0
- data/spec/feature_spec.rb +58 -0
- data/spec/group_spec.rb +1 -1
- data/spec/metric_data/total_spec.rb +1 -1
- data/spec/metric_data/unique_spec.rb +1 -1
- data/spec/metric_spec.rb +5 -5
- data/spec/pirate_spec.rb +16 -12
- data/spec/redis_store_spec.rb +6 -0
- data/spec/spec_helper.rb +3 -1
- data/spec/storable_attributes_spec.rb +58 -6
- data/spec/storable_has_many_spec.rb +2 -2
- data/spec/storable_has_set_spec.rb +1 -1
- data/spec/storable_spec.rb +119 -23
- data/spec/test_spec.rb +1 -1
- metadata +13 -2
data/spec/group_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
3
|
describe Blackbeard::Group do
|
4
|
-
let(:group){ Blackbeard::Group.
|
4
|
+
let(:group){ Blackbeard::Group.find_or_create('example') }
|
5
5
|
let(:context){ double(:controller => double, :user => double) }
|
6
6
|
describe "segment" do
|
7
7
|
context "with no code defined" do
|
@@ -5,7 +5,7 @@ module Blackbeard
|
|
5
5
|
|
6
6
|
describe Total do
|
7
7
|
|
8
|
-
let(:metric) { Blackbeard::Metric.
|
8
|
+
let(:metric) { Blackbeard::Metric.create(:total, "page views") }
|
9
9
|
let(:metric_data) { metric.metric_data }
|
10
10
|
let(:uid) { "unique identifier" }
|
11
11
|
let(:ouid) { "other unique identifier" }
|
@@ -4,7 +4,7 @@ module Blackbeard
|
|
4
4
|
module MetricData
|
5
5
|
describe Unique do
|
6
6
|
|
7
|
-
let(:metric) { Blackbeard::Metric.
|
7
|
+
let(:metric) { Blackbeard::Metric.create(:unique, "join") }
|
8
8
|
let(:metric_data) { metric.metric_data }
|
9
9
|
let(:uid) { "unique identifier" }
|
10
10
|
let(:ouid) { "other unique identifier" }
|
data/spec/metric_spec.rb
CHANGED
@@ -2,16 +2,16 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
2
|
|
3
3
|
module Blackbeard
|
4
4
|
describe Metric do
|
5
|
-
let(:metric) { Metric.
|
6
|
-
let(:group) { Group.
|
5
|
+
let(:metric) { Metric.create(:total, "one-total") }
|
6
|
+
let(:group) { Group.create(:example) }
|
7
7
|
let(:metric_data) { metric.metric_data }
|
8
8
|
let(:group_metric_data) { metric.metric_data(group) }
|
9
9
|
|
10
10
|
describe "self.all" do
|
11
11
|
before :each do
|
12
|
-
Metric.
|
13
|
-
Metric.
|
14
|
-
Metric.
|
12
|
+
Metric.create(:total, "one-total")
|
13
|
+
Metric.create(:total, "two-total")
|
14
|
+
Metric.create(:unique, "one-unique")
|
15
15
|
end
|
16
16
|
it "should return a Metric Object for each Metric created" do
|
17
17
|
Metric.all.should have(3).metrics
|
data/spec/pirate_spec.rb
CHANGED
@@ -7,15 +7,19 @@ describe Blackbeard::Pirate do
|
|
7
7
|
let(:name){ "bond" }
|
8
8
|
|
9
9
|
it "should get metrics once" do
|
10
|
-
Blackbeard::Metric.should_receive(:
|
10
|
+
Blackbeard::Metric.should_receive(:find_or_create).with(:total, name).once.and_return(double)
|
11
11
|
4.times{ pirate.metric(:total, name) }
|
12
12
|
end
|
13
13
|
|
14
14
|
it "should get test once" do
|
15
|
-
Blackbeard::Test.should_receive(:
|
15
|
+
Blackbeard::Test.should_receive(:find_or_create).with(name).once.and_return(double)
|
16
16
|
4.times{ pirate.test(name) }
|
17
17
|
end
|
18
18
|
|
19
|
+
it "should get features once" do
|
20
|
+
Blackbeard::Feature.should_receive(:find_or_create).with(name).once.and_return(double)
|
21
|
+
4.times{ pirate.feature(name) }
|
22
|
+
end
|
19
23
|
|
20
24
|
end
|
21
25
|
|
@@ -29,20 +33,20 @@ describe Blackbeard::Pirate do
|
|
29
33
|
|
30
34
|
describe "set context delegations" do
|
31
35
|
context "with no set context" do
|
32
|
-
it "add_unique should raise
|
36
|
+
it "add_unique should not raise error" do
|
33
37
|
expect{ pirate.add_unique(:example) }.to_not raise_error
|
34
38
|
end
|
35
39
|
|
36
|
-
it "add_total should raise
|
40
|
+
it "add_total should not raise error" do
|
37
41
|
expect{ pirate.add_total(:example, 1) }.to_not raise_error
|
38
42
|
end
|
39
43
|
|
40
|
-
it "ab_test should raise
|
44
|
+
it "ab_test should not raise error" do
|
41
45
|
expect{ pirate.ab_test(:example, :on => 1, :off => 2) }.to_not raise_error
|
42
46
|
end
|
43
47
|
|
44
|
-
it "active? should raise
|
45
|
-
expect{ pirate.
|
48
|
+
it "active? should not raise error" do
|
49
|
+
expect{ pirate.feature_active?(:example) }.to_not raise_error
|
46
50
|
end
|
47
51
|
|
48
52
|
end
|
@@ -61,13 +65,13 @@ describe Blackbeard::Pirate do
|
|
61
65
|
end
|
62
66
|
|
63
67
|
it "should delegate #ab_test" do
|
64
|
-
set_context.should_receive(:ab_test).with(:
|
65
|
-
pirate.ab_test(:
|
68
|
+
set_context.should_receive(:ab_test).with(:example_test, :on => 1, :off => 2).and_return(set_context)
|
69
|
+
pirate.ab_test(:example_test, :on => 1, :off => 2)
|
66
70
|
end
|
67
71
|
|
68
|
-
it "should delegate #
|
69
|
-
set_context.should_receive(:
|
70
|
-
pirate.
|
72
|
+
it "should delegate #feature_active?" do
|
73
|
+
set_context.should_receive(:feature_active?).with(:example_feature).and_return(false)
|
74
|
+
pirate.feature_active?(:example_feature)
|
71
75
|
end
|
72
76
|
end
|
73
77
|
end
|
data/spec/redis_store_spec.rb
CHANGED
@@ -51,6 +51,12 @@ module Blackbeard
|
|
51
51
|
db.hash_increment_by_float('a_hash', 'field', 2.5)
|
52
52
|
db.hash_get('a_hash', 'field').should == "3.5"
|
53
53
|
end
|
54
|
+
|
55
|
+
it "should determine if key exists" do
|
56
|
+
expect{
|
57
|
+
db.hash_set('a_hash', 'field', 'exists')
|
58
|
+
}.to change{db.hash_field_exists('a_hash', 'field')}.from(false).to(true)
|
59
|
+
end
|
54
60
|
end
|
55
61
|
|
56
62
|
describe "sets" do
|
data/spec/spec_helper.rb
CHANGED
@@ -6,8 +6,10 @@ CodeClimate::TestReporter.start
|
|
6
6
|
|
7
7
|
RSpec.configure do |config|
|
8
8
|
config.before do
|
9
|
+
Blackbeard.configure! do |c|
|
10
|
+
c.namespace = "BlackbeardTests"
|
11
|
+
end
|
9
12
|
redis = Blackbeard.config.db
|
10
|
-
namespace = "BlackbeardTests"
|
11
13
|
keys = redis.keys
|
12
14
|
redis.del(keys) if keys.any?
|
13
15
|
end
|
@@ -2,31 +2,79 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
2
|
|
3
3
|
describe Blackbeard::Storable do
|
4
4
|
class ExampleStorableAttrBase < Blackbeard::Storable
|
5
|
+
integer_attributes :number
|
5
6
|
string_attributes :name
|
7
|
+
json_attributes :list
|
6
8
|
end
|
7
9
|
|
8
10
|
class ExampleStorableAttr < ExampleStorableAttrBase
|
9
11
|
set_master_key :example
|
10
12
|
end
|
11
13
|
|
14
|
+
let(:example){ ExampleStorableAttr.create("id") }
|
15
|
+
|
16
|
+
describe "json_attributes" do
|
17
|
+
it "should not blow up when nil" do
|
18
|
+
example.list.should be_nil
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should read and write" do
|
22
|
+
example.list = ["hello", "world"]
|
23
|
+
example.list.should == ["hello", "world"]
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should not persist if not saved" do
|
27
|
+
example.list = ["hello", "world"]
|
28
|
+
example.reload.list.should_not == ["hello", "world"]
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should persist if saved" do
|
32
|
+
example.list = ["hello", "world"]
|
33
|
+
example.save
|
34
|
+
example.reload.list.should == ["hello", "world"]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "integer_attributes" do
|
39
|
+
it "should be read and write" do
|
40
|
+
example.number = 3
|
41
|
+
example.number.should == 3
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should not persist if not saved" do
|
45
|
+
example.number = 4
|
46
|
+
example.reload.number.should_not == 4
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should persist when saved" do
|
50
|
+
example.number = 5
|
51
|
+
example.save
|
52
|
+
|
53
|
+
example.reload.number.should == 5
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
12
57
|
describe "string_attributes" do
|
13
58
|
it "should be read and write" do
|
14
|
-
example = ExampleStorableAttr.new("id")
|
15
59
|
example.name = "Some name"
|
16
60
|
example.name.should == "Some name"
|
17
61
|
end
|
18
62
|
|
19
|
-
it "should persist" do
|
20
|
-
example = ExampleStorableAttr.new("id")
|
63
|
+
it "should not persist if not saved" do
|
21
64
|
example.name = "Some name"
|
65
|
+
example.reload.name.should_not == "Some name"
|
66
|
+
end
|
22
67
|
|
23
|
-
|
24
|
-
|
68
|
+
it "should persist when saved" do
|
69
|
+
example.name = "Some name"
|
70
|
+
example.save
|
71
|
+
|
72
|
+
example.reload.name.should == "Some name"
|
25
73
|
end
|
26
74
|
end
|
27
75
|
|
28
76
|
describe "update_attributes" do
|
29
|
-
let(:storable){ ExampleStorableAttr.
|
77
|
+
let(:storable){ ExampleStorableAttr.create("id") }
|
30
78
|
it "should not raise raise_error with non-attributes" do
|
31
79
|
expect{
|
32
80
|
storable.update_attributes(:name => 'hello')
|
@@ -43,5 +91,9 @@ describe Blackbeard::Storable do
|
|
43
91
|
storable.update_attributes("name" => 'hello')
|
44
92
|
}.to change{ storable.name }.from(nil).to('hello')
|
45
93
|
end
|
94
|
+
it "should persist the changes" do
|
95
|
+
storable.update_attributes("name" => 'hello')
|
96
|
+
storable.reload.name.should == 'hello'
|
97
|
+
end
|
46
98
|
end
|
47
99
|
end
|
@@ -12,8 +12,8 @@ module Blackbeard
|
|
12
12
|
end
|
13
13
|
|
14
14
|
describe StorableHasMany do
|
15
|
-
let(:example){ HasManyExample.
|
16
|
-
let(:thing){ Thing.
|
15
|
+
let(:example){ HasManyExample.create(:example) }
|
16
|
+
let(:thing){ Thing.create(:foo) }
|
17
17
|
|
18
18
|
it "should add and remove things" do
|
19
19
|
example.add_thing(thing)
|
data/spec/storable_spec.rb
CHANGED
@@ -1,33 +1,129 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
module Blackbeard
|
4
|
+
describe Storable do
|
5
|
+
class ExampleStorable < Storable
|
6
|
+
set_master_key :example
|
7
|
+
string_attributes :name
|
8
|
+
end
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
-
|
10
|
+
class AnotherStorable < Storable
|
11
|
+
set_master_key :another
|
12
|
+
end
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
describe "initialize" do
|
15
|
+
it "should be able to instantiate" do
|
16
|
+
expect{
|
17
|
+
ExampleStorable.new(:some_id)
|
18
|
+
}.to_not raise_error
|
19
|
+
end
|
17
20
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
it "should not save" do
|
22
|
+
expect{
|
23
|
+
ExampleStorable.new(:some_id)
|
24
|
+
}.to_not change{ ExampleStorable.count }
|
25
|
+
end
|
22
26
|
end
|
23
|
-
end
|
24
27
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
28
|
+
describe "self.find" do
|
29
|
+
it "should find an existing record" do
|
30
|
+
example = ExampleStorable.create(:some_id)
|
31
|
+
ExampleStorable.find(:some_id)
|
32
|
+
end
|
33
|
+
it "should return nil if the key does not exist" do
|
34
|
+
ExampleStorable.find(:some_id).should be_nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "self.create" do
|
39
|
+
it "should raise DuplicateKey if there is an existing record" do
|
40
|
+
example = ExampleStorable.create(:some_id)
|
41
|
+
expect{
|
42
|
+
ExampleStorable.create(:some_id)
|
43
|
+
}.to raise_error(StorableDuplicateKey)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should create a new record" do
|
47
|
+
expect{ ExampleStorable.create(:this_id) }.to change{ExampleStorable.count}.by(1)
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should update attributes" do
|
51
|
+
storable = ExampleStorable.create(:some_id, {:name => 'hello world'})
|
52
|
+
storable.reload.name.should == 'hello world'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "self.find_or_create" do
|
57
|
+
it "should create a new record if one doesn't exist" do
|
58
|
+
expect{ ExampleStorable.find_or_create(:this_id) }.to change{ExampleStorable.count}.by(1)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should find an existing record if one exists" do
|
62
|
+
example = ExampleStorable.create(:this_id)
|
63
|
+
ExampleStorable.find_or_create(:this_id)
|
64
|
+
end
|
30
65
|
end
|
31
|
-
end
|
32
66
|
|
67
|
+
describe "self.all" do
|
68
|
+
before :each do
|
69
|
+
@this = ExampleStorable.create(:this)
|
70
|
+
@not_this = AnotherStorable.create(:not_this)
|
71
|
+
@that = ExampleStorable.create(:that)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should return all the record" do
|
75
|
+
ExampleStorable.all.should include(@this, @that)
|
76
|
+
ExampleStorable.all.should_not include(@not_this)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should mark them as not new records" do
|
80
|
+
ExampleStorable.all.each do |r|
|
81
|
+
r.should_not be_new_record
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "self.count" do
|
87
|
+
before :each do
|
88
|
+
ExampleStorable.create(:this)
|
89
|
+
AnotherStorable.create(:this)
|
90
|
+
ExampleStorable.create(:that)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should return the number of committed storables" do
|
94
|
+
ExampleStorable.count.should == 2
|
95
|
+
AnotherStorable.count.should == 1
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe "save" do
|
100
|
+
let(:new_record) { ExampleStorable.new(:an_id) }
|
101
|
+
it "should commit to db" do
|
102
|
+
expect{
|
103
|
+
new_record.save
|
104
|
+
}.to change{ ExampleStorable.count }.by(1)
|
105
|
+
end
|
106
|
+
it "should set @new_record = false" do
|
107
|
+
expect{
|
108
|
+
new_record.save
|
109
|
+
}.to change{ new_record.new_record }.from(true).to(false)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "master_key" do
|
114
|
+
it "should be by class" do
|
115
|
+
ExampleStorable.master_key.should == 'example'
|
116
|
+
AnotherStorable.master_key.should == 'another'
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe "==" do
|
121
|
+
it "should match class and id" do
|
122
|
+
(ExampleStorable.new("thing") == ExampleStorable.new("thing")).should be_true
|
123
|
+
(ExampleStorable.new("thing") == ExampleStorable.new("thing2")).should be_false
|
124
|
+
(ExampleStorable.new("thing") == AnotherStorable.new("thing")).should be_false
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
33
129
|
end
|
data/spec/test_spec.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: blackbeard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Graff
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-03-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -222,10 +222,13 @@ files:
|
|
222
222
|
- dashboard/public/stylesheets/bootstrap-theme.css
|
223
223
|
- dashboard/public/stylesheets/bootstrap.css
|
224
224
|
- dashboard/routes/base.rb
|
225
|
+
- dashboard/routes/features.rb
|
225
226
|
- dashboard/routes/groups.rb
|
226
227
|
- dashboard/routes/home.rb
|
227
228
|
- dashboard/routes/metrics.rb
|
228
229
|
- dashboard/routes/tests.rb
|
230
|
+
- dashboard/views/features/index.erb
|
231
|
+
- dashboard/views/features/show.erb
|
229
232
|
- dashboard/views/groups/index.erb
|
230
233
|
- dashboard/views/groups/show.erb
|
231
234
|
- dashboard/views/index.erb
|
@@ -242,6 +245,8 @@ files:
|
|
242
245
|
- lib/blackbeard/dashboard.rb
|
243
246
|
- lib/blackbeard/dashboard_helpers.rb
|
244
247
|
- lib/blackbeard/errors.rb
|
248
|
+
- lib/blackbeard/feature.rb
|
249
|
+
- lib/blackbeard/feature_rollout.rb
|
245
250
|
- lib/blackbeard/group.rb
|
246
251
|
- lib/blackbeard/metric.rb
|
247
252
|
- lib/blackbeard/metric_data/base.rb
|
@@ -261,10 +266,13 @@ files:
|
|
261
266
|
- spec/blackbeard_spec.rb
|
262
267
|
- spec/configuration_spec.rb
|
263
268
|
- spec/context_spec.rb
|
269
|
+
- spec/dashboard/features_spec.rb
|
264
270
|
- spec/dashboard/groups_spec.rb
|
265
271
|
- spec/dashboard/home_spec.rb
|
266
272
|
- spec/dashboard/metrics_spec.rb
|
267
273
|
- spec/dashboard/tests_spec.rb
|
274
|
+
- spec/feature_rollout_spec.rb
|
275
|
+
- spec/feature_spec.rb
|
268
276
|
- spec/group_spec.rb
|
269
277
|
- spec/metric_data/base_spec.rb
|
270
278
|
- spec/metric_data/total_spec.rb
|
@@ -306,10 +314,13 @@ test_files:
|
|
306
314
|
- spec/blackbeard_spec.rb
|
307
315
|
- spec/configuration_spec.rb
|
308
316
|
- spec/context_spec.rb
|
317
|
+
- spec/dashboard/features_spec.rb
|
309
318
|
- spec/dashboard/groups_spec.rb
|
310
319
|
- spec/dashboard/home_spec.rb
|
311
320
|
- spec/dashboard/metrics_spec.rb
|
312
321
|
- spec/dashboard/tests_spec.rb
|
322
|
+
- spec/feature_rollout_spec.rb
|
323
|
+
- spec/feature_spec.rb
|
313
324
|
- spec/group_spec.rb
|
314
325
|
- spec/metric_data/base_spec.rb
|
315
326
|
- spec/metric_data/total_spec.rb
|