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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +31 -20
  3. data/dashboard/public/stylesheets/application.css +4 -0
  4. data/dashboard/routes/features.rb +31 -0
  5. data/dashboard/routes/groups.rb +2 -2
  6. data/dashboard/routes/metrics.rb +6 -6
  7. data/dashboard/routes/tests.rb +2 -2
  8. data/dashboard/views/features/index.erb +21 -0
  9. data/dashboard/views/features/show.erb +163 -0
  10. data/dashboard/views/groups/show.erb +1 -1
  11. data/dashboard/views/layout.erb +2 -1
  12. data/lib/blackbeard.rb +18 -7
  13. data/lib/blackbeard/configuration.rb +3 -2
  14. data/lib/blackbeard/context.rb +11 -7
  15. data/lib/blackbeard/dashboard.rb +2 -0
  16. data/lib/blackbeard/errors.rb +4 -0
  17. data/lib/blackbeard/feature.rb +45 -0
  18. data/lib/blackbeard/feature_rollout.rb +47 -0
  19. data/lib/blackbeard/metric.rb +22 -4
  20. data/lib/blackbeard/pirate.rb +11 -5
  21. data/lib/blackbeard/redis_store.rb +4 -0
  22. data/lib/blackbeard/storable.rb +72 -6
  23. data/lib/blackbeard/storable_attributes.rb +50 -3
  24. data/lib/blackbeard/storable_has_many.rb +1 -0
  25. data/lib/blackbeard/storable_has_set.rb +1 -0
  26. data/lib/blackbeard/version.rb +1 -1
  27. data/spec/blackbeard_spec.rb +13 -0
  28. data/spec/configuration_spec.rb +6 -0
  29. data/spec/context_spec.rb +12 -12
  30. data/spec/dashboard/features_spec.rb +52 -0
  31. data/spec/dashboard/groups_spec.rb +4 -4
  32. data/spec/dashboard/metrics_spec.rb +6 -6
  33. data/spec/dashboard/tests_spec.rb +4 -4
  34. data/spec/feature_rollout_spec.rb +147 -0
  35. data/spec/feature_spec.rb +58 -0
  36. data/spec/group_spec.rb +1 -1
  37. data/spec/metric_data/total_spec.rb +1 -1
  38. data/spec/metric_data/unique_spec.rb +1 -1
  39. data/spec/metric_spec.rb +5 -5
  40. data/spec/pirate_spec.rb +16 -12
  41. data/spec/redis_store_spec.rb +6 -0
  42. data/spec/spec_helper.rb +3 -1
  43. data/spec/storable_attributes_spec.rb +58 -6
  44. data/spec/storable_has_many_spec.rb +2 -2
  45. data/spec/storable_has_set_spec.rb +1 -1
  46. data/spec/storable_spec.rb +119 -23
  47. data/spec/test_spec.rb +1 -1
  48. metadata +13 -2
@@ -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.new('example') }
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.new(:total, "page views") }
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.new(:unique, "join") }
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" }
@@ -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.new(:total, "one-total") }
6
- let(:group) { Group.new(:example) }
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.new(:total, "one-total")
13
- Metric.new(:total, "two-total")
14
- Metric.new(:unique, "one-unique")
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
@@ -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(:new).with(:total, name).once.and_return(double)
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(:new).with(name).once.and_return(double)
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 Blackbeard::MissingContextError" do
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 Blackbeard::MissingContextError" do
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 Blackbeard::MissingContextError" do
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 Blackbeard::MissingContextError" do
45
- expect{ pirate.active?(:example) }.to_not raise_error
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(:example_metric, :on => 1, :off => 2).and_return(set_context)
65
- pirate.ab_test(:example_metric, :on => 1, :off => 2)
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 #active?" do
69
- set_context.should_receive(:active?).with(:example_metric).and_return(false)
70
- pirate.active?(:example_metric)
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
@@ -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
@@ -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
- example_reloaded = ExampleStorableAttr.new("id")
24
- example_reloaded.name.should == "Some name"
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.new("id") }
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.new(:example) }
16
- let(:thing){ Thing.new(:foo) }
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)
@@ -8,7 +8,7 @@ module Blackbeard
8
8
  end
9
9
 
10
10
  describe StorableHasMany do
11
- let(:example){ HasSetExample.new(:example) }
11
+ let(:example){ HasSetExample.create(:example) }
12
12
  let(:thing) { "foo" }
13
13
 
14
14
  it "should add and remove things" do
@@ -1,33 +1,129 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
- describe Blackbeard::Storable do
4
- class ExampleStorable < Blackbeard::Storable
5
- set_master_key :example
6
- end
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
- class AnotherStorable < Blackbeard::Storable
9
- set_master_key :another
10
- end
10
+ class AnotherStorable < Storable
11
+ set_master_key :another
12
+ end
11
13
 
12
- it "should be able to instantiate" do
13
- expect{
14
- ExampleStorable.new(:some_id)
15
- }.to_not raise_error
16
- end
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
- describe "master_key" do
19
- it "should be by class" do
20
- ExampleStorable.master_key.should == 'example'
21
- AnotherStorable.master_key.should == 'another'
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
- describe "==" do
26
- it "should match class and id" do
27
- (ExampleStorable.new("thing") == ExampleStorable.new("thing")).should be_true
28
- (ExampleStorable.new("thing") == ExampleStorable.new("thing2")).should be_false
29
- (ExampleStorable.new("thing") == AnotherStorable.new("thing")).should be_false
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
@@ -1,7 +1,7 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
3
  describe Blackbeard::Test do
4
- let(:test){ Blackbeard::Test.new('example') }
4
+ let(:test){ Blackbeard::Test.create('example') }
5
5
 
6
6
  describe "#select_variation" do
7
7
  # '*' - experimenting
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.3.1
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-02-24 00:00:00.000000000 Z
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