blackbeard 0.0.3.1 → 0.0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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