flipper 0.4.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.
- data/Guardfile +3 -8
- data/README.md +26 -38
- data/examples/percentage_of_actors.rb +17 -12
- data/examples/percentage_of_random.rb +3 -7
- data/lib/flipper.rb +8 -1
- data/lib/flipper/adapter.rb +2 -208
- data/lib/flipper/adapters/decorator.rb +9 -0
- data/lib/flipper/adapters/instrumented.rb +92 -0
- data/lib/flipper/adapters/memoizable.rb +88 -0
- data/lib/flipper/adapters/memory.rb +89 -7
- data/lib/flipper/adapters/operation_logger.rb +31 -45
- data/lib/flipper/decorator.rb +6 -0
- data/lib/flipper/dsl.rb +29 -2
- data/lib/flipper/feature.rb +83 -49
- data/lib/flipper/gate.rb +24 -41
- data/lib/flipper/gates/actor.rb +24 -24
- data/lib/flipper/gates/boolean.rb +28 -15
- data/lib/flipper/gates/group.rb +25 -34
- data/lib/flipper/gates/percentage_of_actors.rb +21 -13
- data/lib/flipper/gates/percentage_of_random.rb +20 -12
- data/lib/flipper/instrumentation/log_subscriber.rb +14 -22
- data/lib/flipper/middleware/memoizer.rb +23 -0
- data/lib/flipper/spec/shared_adapter_specs.rb +141 -92
- data/lib/flipper/types/boolean.rb +5 -1
- data/lib/flipper/version.rb +1 -1
- data/spec/flipper/adapters/instrumented_spec.rb +92 -0
- data/spec/flipper/adapters/memoizable_spec.rb +184 -0
- data/spec/flipper/adapters/memory_spec.rb +1 -11
- data/spec/flipper/adapters/operation_logger_spec.rb +93 -0
- data/spec/flipper/dsl_spec.rb +18 -43
- data/spec/flipper/feature_spec.rb +25 -9
- data/spec/flipper/gate_spec.rb +8 -20
- data/spec/flipper/gates/actor_spec.rb +6 -14
- data/spec/flipper/gates/boolean_spec.rb +80 -13
- data/spec/flipper/gates/group_spec.rb +8 -18
- data/spec/flipper/gates/percentage_of_actors_spec.rb +12 -28
- data/spec/flipper/gates/percentage_of_random_spec.rb +6 -14
- data/spec/flipper/instrumentation/log_subscriber_spec.rb +15 -8
- data/spec/flipper/instrumentation/metriks_subscriber_spec.rb +3 -6
- data/spec/flipper/middleware/{local_cache_spec.rb → memoizer_spec.rb} +25 -55
- data/spec/flipper/types/boolean_spec.rb +13 -3
- data/spec/flipper_spec.rb +7 -0
- data/spec/helper.rb +21 -3
- data/spec/integration_spec.rb +115 -116
- metadata +17 -27
- data/lib/flipper/adapters/memoized.rb +0 -55
- data/lib/flipper/key.rb +0 -38
- data/lib/flipper/middleware/local_cache.rb +0 -36
- data/lib/flipper/toggle.rb +0 -54
- data/lib/flipper/toggles/boolean.rb +0 -54
- data/lib/flipper/toggles/set.rb +0 -25
- data/lib/flipper/toggles/value.rb +0 -25
- data/spec/flipper/adapter_spec.rb +0 -463
- data/spec/flipper/adapters/memoized_spec.rb +0 -93
- data/spec/flipper/key_spec.rb +0 -23
- data/spec/flipper/toggle_spec.rb +0 -22
- data/spec/flipper/toggles/boolean_spec.rb +0 -40
- data/spec/flipper/toggles/set_spec.rb +0 -35
- data/spec/flipper/toggles/value_spec.rb +0 -55
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flipper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-02-
|
12
|
+
date: 2013-02-16 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Feature flipper for any adapter
|
15
15
|
email:
|
@@ -38,9 +38,12 @@ files:
|
|
38
38
|
- flipper.gemspec
|
39
39
|
- lib/flipper.rb
|
40
40
|
- lib/flipper/adapter.rb
|
41
|
-
- lib/flipper/adapters/
|
41
|
+
- lib/flipper/adapters/decorator.rb
|
42
|
+
- lib/flipper/adapters/instrumented.rb
|
43
|
+
- lib/flipper/adapters/memoizable.rb
|
42
44
|
- lib/flipper/adapters/memory.rb
|
43
45
|
- lib/flipper/adapters/operation_logger.rb
|
46
|
+
- lib/flipper/decorator.rb
|
44
47
|
- lib/flipper/dsl.rb
|
45
48
|
- lib/flipper/errors.rb
|
46
49
|
- lib/flipper/feature.rb
|
@@ -55,14 +58,9 @@ files:
|
|
55
58
|
- lib/flipper/instrumentation/metriks_subscriber.rb
|
56
59
|
- lib/flipper/instrumenters/memory.rb
|
57
60
|
- lib/flipper/instrumenters/noop.rb
|
58
|
-
- lib/flipper/
|
59
|
-
- lib/flipper/middleware/local_cache.rb
|
61
|
+
- lib/flipper/middleware/memoizer.rb
|
60
62
|
- lib/flipper/registry.rb
|
61
63
|
- lib/flipper/spec/shared_adapter_specs.rb
|
62
|
-
- lib/flipper/toggle.rb
|
63
|
-
- lib/flipper/toggles/boolean.rb
|
64
|
-
- lib/flipper/toggles/set.rb
|
65
|
-
- lib/flipper/toggles/value.rb
|
66
64
|
- lib/flipper/type.rb
|
67
65
|
- lib/flipper/types/actor.rb
|
68
66
|
- lib/flipper/types/boolean.rb
|
@@ -71,9 +69,10 @@ files:
|
|
71
69
|
- lib/flipper/types/percentage_of_actors.rb
|
72
70
|
- lib/flipper/types/percentage_of_random.rb
|
73
71
|
- lib/flipper/version.rb
|
74
|
-
- spec/flipper/
|
75
|
-
- spec/flipper/adapters/
|
72
|
+
- spec/flipper/adapters/instrumented_spec.rb
|
73
|
+
- spec/flipper/adapters/memoizable_spec.rb
|
76
74
|
- spec/flipper/adapters/memory_spec.rb
|
75
|
+
- spec/flipper/adapters/operation_logger_spec.rb
|
77
76
|
- spec/flipper/dsl_spec.rb
|
78
77
|
- spec/flipper/feature_spec.rb
|
79
78
|
- spec/flipper/gate_spec.rb
|
@@ -86,13 +85,8 @@ files:
|
|
86
85
|
- spec/flipper/instrumentation/metriks_subscriber_spec.rb
|
87
86
|
- spec/flipper/instrumenters/memory_spec.rb
|
88
87
|
- spec/flipper/instrumenters/noop_spec.rb
|
89
|
-
- spec/flipper/
|
90
|
-
- spec/flipper/middleware/local_cache_spec.rb
|
88
|
+
- spec/flipper/middleware/memoizer_spec.rb
|
91
89
|
- spec/flipper/registry_spec.rb
|
92
|
-
- spec/flipper/toggle_spec.rb
|
93
|
-
- spec/flipper/toggles/boolean_spec.rb
|
94
|
-
- spec/flipper/toggles/set_spec.rb
|
95
|
-
- spec/flipper/toggles/value_spec.rb
|
96
90
|
- spec/flipper/types/actor_spec.rb
|
97
91
|
- spec/flipper/types/boolean_spec.rb
|
98
92
|
- spec/flipper/types/group_spec.rb
|
@@ -116,7 +110,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
116
110
|
version: '0'
|
117
111
|
segments:
|
118
112
|
- 0
|
119
|
-
hash:
|
113
|
+
hash: -4560839249202297958
|
120
114
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
115
|
none: false
|
122
116
|
requirements:
|
@@ -125,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
119
|
version: '0'
|
126
120
|
segments:
|
127
121
|
- 0
|
128
|
-
hash:
|
122
|
+
hash: -4560839249202297958
|
129
123
|
requirements: []
|
130
124
|
rubyforge_project:
|
131
125
|
rubygems_version: 1.8.23
|
@@ -133,9 +127,10 @@ signing_key:
|
|
133
127
|
specification_version: 3
|
134
128
|
summary: Feature flipper for any adapter
|
135
129
|
test_files:
|
136
|
-
- spec/flipper/
|
137
|
-
- spec/flipper/adapters/
|
130
|
+
- spec/flipper/adapters/instrumented_spec.rb
|
131
|
+
- spec/flipper/adapters/memoizable_spec.rb
|
138
132
|
- spec/flipper/adapters/memory_spec.rb
|
133
|
+
- spec/flipper/adapters/operation_logger_spec.rb
|
139
134
|
- spec/flipper/dsl_spec.rb
|
140
135
|
- spec/flipper/feature_spec.rb
|
141
136
|
- spec/flipper/gate_spec.rb
|
@@ -148,13 +143,8 @@ test_files:
|
|
148
143
|
- spec/flipper/instrumentation/metriks_subscriber_spec.rb
|
149
144
|
- spec/flipper/instrumenters/memory_spec.rb
|
150
145
|
- spec/flipper/instrumenters/noop_spec.rb
|
151
|
-
- spec/flipper/
|
152
|
-
- spec/flipper/middleware/local_cache_spec.rb
|
146
|
+
- spec/flipper/middleware/memoizer_spec.rb
|
153
147
|
- spec/flipper/registry_spec.rb
|
154
|
-
- spec/flipper/toggle_spec.rb
|
155
|
-
- spec/flipper/toggles/boolean_spec.rb
|
156
|
-
- spec/flipper/toggles/set_spec.rb
|
157
|
-
- spec/flipper/toggles/value_spec.rb
|
158
148
|
- spec/flipper/types/actor_spec.rb
|
159
149
|
- spec/flipper/types/boolean_spec.rb
|
160
150
|
- spec/flipper/types/group_spec.rb
|
@@ -1,55 +0,0 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
|
-
module Flipper
|
4
|
-
module Adapters
|
5
|
-
class Memoized
|
6
|
-
# Public
|
7
|
-
def initialize(adapter, cache = {})
|
8
|
-
@adapter = adapter
|
9
|
-
@cache = cache
|
10
|
-
end
|
11
|
-
|
12
|
-
# Public
|
13
|
-
def read(key)
|
14
|
-
@cache.fetch(key) {
|
15
|
-
@cache[key] = @adapter.read(key)
|
16
|
-
}
|
17
|
-
end
|
18
|
-
|
19
|
-
# Public
|
20
|
-
def write(key, value)
|
21
|
-
result = @adapter.write(key, value)
|
22
|
-
@cache.delete(key)
|
23
|
-
result
|
24
|
-
end
|
25
|
-
|
26
|
-
# Public
|
27
|
-
def delete(key)
|
28
|
-
result = @adapter.delete(key)
|
29
|
-
@cache.delete(key)
|
30
|
-
result
|
31
|
-
end
|
32
|
-
|
33
|
-
# Public
|
34
|
-
def set_add(key, value)
|
35
|
-
result = @adapter.set_add(key, value)
|
36
|
-
@cache.delete(key)
|
37
|
-
result
|
38
|
-
end
|
39
|
-
|
40
|
-
# Public
|
41
|
-
def set_delete(key, value)
|
42
|
-
result = @adapter.set_delete(key, value)
|
43
|
-
@cache.delete(key)
|
44
|
-
result
|
45
|
-
end
|
46
|
-
|
47
|
-
# Public
|
48
|
-
def set_members(key)
|
49
|
-
@cache.fetch(key) {
|
50
|
-
@cache[key] = @adapter.set_members(key)
|
51
|
-
}
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
data/lib/flipper/key.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
module Flipper
|
2
|
-
# Private: Used internally in flipper to create key to be used for feature in
|
3
|
-
# the adapter. You should never need to use this.
|
4
|
-
class Key
|
5
|
-
# Private
|
6
|
-
Separator = '/'
|
7
|
-
|
8
|
-
# Private
|
9
|
-
attr_reader :feature_name
|
10
|
-
|
11
|
-
# Private
|
12
|
-
attr_reader :gate_key
|
13
|
-
|
14
|
-
# Internal
|
15
|
-
def initialize(feature_name, gate_key)
|
16
|
-
@feature_name, @gate_key = feature_name, gate_key
|
17
|
-
end
|
18
|
-
|
19
|
-
# Private
|
20
|
-
def separator
|
21
|
-
Separator.dup
|
22
|
-
end
|
23
|
-
|
24
|
-
# Private
|
25
|
-
def to_s
|
26
|
-
"#{feature_name}#{separator}#{gate_key}"
|
27
|
-
end
|
28
|
-
|
29
|
-
# Internal: Pretty string version for debugging.
|
30
|
-
def inspect
|
31
|
-
attributes = [
|
32
|
-
"feature_name=#{feature_name.inspect}",
|
33
|
-
"gate_key=#{gate_key.inspect}",
|
34
|
-
]
|
35
|
-
"#<#{self.class.name}:#{object_id} #{attributes.join(', ')}>"
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
module Flipper
|
2
|
-
module Middleware
|
3
|
-
class LocalCache
|
4
|
-
class Body
|
5
|
-
def initialize(target, flipper, original)
|
6
|
-
@target = target
|
7
|
-
@flipper = flipper
|
8
|
-
@original = original
|
9
|
-
end
|
10
|
-
|
11
|
-
def each(&block)
|
12
|
-
@target.each(&block)
|
13
|
-
end
|
14
|
-
|
15
|
-
def close
|
16
|
-
@target.close if @target.respond_to?(:close)
|
17
|
-
ensure
|
18
|
-
@flipper.adapter.use_local_cache = @original
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def initialize(app, flipper)
|
23
|
-
@app = app
|
24
|
-
@flipper = flipper
|
25
|
-
end
|
26
|
-
|
27
|
-
def call(env)
|
28
|
-
original = @flipper.adapter.using_local_cache?
|
29
|
-
@flipper.adapter.use_local_cache = true
|
30
|
-
|
31
|
-
status, headers, body = @app.call(env)
|
32
|
-
[status, headers, Body.new(body, @flipper, original)]
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
data/lib/flipper/toggle.rb
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
require 'forwardable'
|
2
|
-
|
3
|
-
module Flipper
|
4
|
-
# Internal: Used by gate to toggle values (true/false, add/delete from set, etc.).
|
5
|
-
# Named poorly maybe, but haven't come up with a better name yet.
|
6
|
-
class Toggle
|
7
|
-
extend Forwardable
|
8
|
-
|
9
|
-
attr_reader :gate
|
10
|
-
|
11
|
-
def_delegators :@gate, :adapter_key, :feature, :adapter
|
12
|
-
|
13
|
-
def initialize(gate)
|
14
|
-
@gate = gate
|
15
|
-
end
|
16
|
-
|
17
|
-
# Internal: Enables thing for gate and adds feature to known features.
|
18
|
-
#
|
19
|
-
# Returns Boolean (currently always true).
|
20
|
-
def enable(thing)
|
21
|
-
add_feature_to_set
|
22
|
-
end
|
23
|
-
|
24
|
-
# Internal: Disables thing for gate and adds feature to known features.
|
25
|
-
#
|
26
|
-
# Returns Boolean (currently always true).
|
27
|
-
def disable(thing)
|
28
|
-
add_feature_to_set
|
29
|
-
end
|
30
|
-
|
31
|
-
def value
|
32
|
-
raise 'Not implemented'
|
33
|
-
end
|
34
|
-
|
35
|
-
# Public: Pretty string version for debugging.
|
36
|
-
def inspect
|
37
|
-
attributes = [
|
38
|
-
"gate=#{gate.inspect}",
|
39
|
-
"value=#{value}",
|
40
|
-
]
|
41
|
-
"#<#{self.class.name}:#{object_id} #{attributes.join(', ')}>"
|
42
|
-
end
|
43
|
-
|
44
|
-
private
|
45
|
-
|
46
|
-
def add_feature_to_set
|
47
|
-
adapter.feature_add adapter_key.feature_name
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
require 'flipper/toggles/boolean'
|
53
|
-
require 'flipper/toggles/set'
|
54
|
-
require 'flipper/toggles/value'
|
@@ -1,54 +0,0 @@
|
|
1
|
-
module Flipper
|
2
|
-
module Toggles
|
3
|
-
class Boolean < Toggle
|
4
|
-
TruthMap = {
|
5
|
-
true => true,
|
6
|
-
'true' => true,
|
7
|
-
'TRUE' => true,
|
8
|
-
'True' => true,
|
9
|
-
't' => true,
|
10
|
-
'T' => true,
|
11
|
-
'1' => true,
|
12
|
-
'on' => true,
|
13
|
-
'ON' => true,
|
14
|
-
1 => true,
|
15
|
-
1.0 => true,
|
16
|
-
false => false,
|
17
|
-
'false' => false,
|
18
|
-
'FALSE' => false,
|
19
|
-
'False' => false,
|
20
|
-
'f' => false,
|
21
|
-
'F' => false,
|
22
|
-
'0' => false,
|
23
|
-
'off' => false,
|
24
|
-
'OFF' => false,
|
25
|
-
0 => false,
|
26
|
-
0.0 => false,
|
27
|
-
nil => false,
|
28
|
-
}
|
29
|
-
|
30
|
-
def enable(thing)
|
31
|
-
super
|
32
|
-
adapter.write adapter_key, thing.value
|
33
|
-
true
|
34
|
-
end
|
35
|
-
|
36
|
-
def disable(thing)
|
37
|
-
super
|
38
|
-
feature.gates.each do |gate|
|
39
|
-
gate.adapter.delete gate.adapter_key
|
40
|
-
end
|
41
|
-
true
|
42
|
-
end
|
43
|
-
|
44
|
-
def value
|
45
|
-
value = adapter.read(adapter_key)
|
46
|
-
!!TruthMap[value]
|
47
|
-
end
|
48
|
-
|
49
|
-
def enabled?
|
50
|
-
value
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
data/lib/flipper/toggles/set.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
module Flipper
|
2
|
-
module Toggles
|
3
|
-
class Set < Toggle
|
4
|
-
def enable(thing)
|
5
|
-
super
|
6
|
-
adapter.set_add adapter_key, thing.value
|
7
|
-
true
|
8
|
-
end
|
9
|
-
|
10
|
-
def disable(thing)
|
11
|
-
super
|
12
|
-
adapter.set_delete adapter_key, thing.value
|
13
|
-
true
|
14
|
-
end
|
15
|
-
|
16
|
-
def value
|
17
|
-
adapter.set_members adapter_key
|
18
|
-
end
|
19
|
-
|
20
|
-
def enabled?
|
21
|
-
!value.empty?
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
module Flipper
|
2
|
-
module Toggles
|
3
|
-
class Value < Toggle
|
4
|
-
def enable(thing)
|
5
|
-
super
|
6
|
-
adapter.write adapter_key, thing.value
|
7
|
-
true
|
8
|
-
end
|
9
|
-
|
10
|
-
def disable(thing)
|
11
|
-
super
|
12
|
-
adapter.delete adapter_key
|
13
|
-
true
|
14
|
-
end
|
15
|
-
|
16
|
-
def value
|
17
|
-
adapter.read adapter_key
|
18
|
-
end
|
19
|
-
|
20
|
-
def enabled?
|
21
|
-
!value.nil? && value.to_i > 0
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,463 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
require 'flipper/adapter'
|
3
|
-
require 'flipper/adapters/memory'
|
4
|
-
require 'flipper/instrumenters/memory'
|
5
|
-
|
6
|
-
describe Flipper::Adapter do
|
7
|
-
let(:local_cache) { {} }
|
8
|
-
let(:source) { {} }
|
9
|
-
let(:adapter) { Flipper::Adapters::Memory.new(source) }
|
10
|
-
let(:features_key) { described_class::FeaturesKey }
|
11
|
-
|
12
|
-
subject { described_class.new(adapter, :local_cache => local_cache) }
|
13
|
-
|
14
|
-
describe ".wrap" do
|
15
|
-
context "with Flipper::Adapter instance" do
|
16
|
-
before do
|
17
|
-
@result = described_class.wrap(subject)
|
18
|
-
end
|
19
|
-
|
20
|
-
it "returns same Flipper::Adapter instance" do
|
21
|
-
@result.should equal(subject)
|
22
|
-
end
|
23
|
-
|
24
|
-
it "wraps adapter that instance was wrapping" do
|
25
|
-
@result.adapter.should be(subject.adapter)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
context "with adapter instance" do
|
30
|
-
before do
|
31
|
-
@result = described_class.wrap(adapter)
|
32
|
-
end
|
33
|
-
|
34
|
-
it "returns Flipper::Adapter instance" do
|
35
|
-
@result.should be_instance_of(described_class)
|
36
|
-
end
|
37
|
-
|
38
|
-
it "wraps adapter" do
|
39
|
-
@result.adapter.should be(adapter)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
context "with adapter instance and options" do
|
44
|
-
let(:instrumenter) { double('Instrumentor') }
|
45
|
-
|
46
|
-
before do
|
47
|
-
@result = described_class.wrap(adapter, :instrumenter => instrumenter)
|
48
|
-
end
|
49
|
-
|
50
|
-
it "returns Flipper::Adapter instance" do
|
51
|
-
@result.should be_instance_of(described_class)
|
52
|
-
end
|
53
|
-
|
54
|
-
it "wraps adapter" do
|
55
|
-
@result.adapter.should be(adapter)
|
56
|
-
end
|
57
|
-
|
58
|
-
it "passes options to initialization" do
|
59
|
-
@result.instrumenter.should be(instrumenter)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
describe "#initialize" do
|
65
|
-
it "sets adapter" do
|
66
|
-
instance = described_class.new(adapter)
|
67
|
-
instance.adapter.should be(adapter)
|
68
|
-
end
|
69
|
-
|
70
|
-
it "sets adapter name" do
|
71
|
-
instance = described_class.new(adapter)
|
72
|
-
instance.name.should be(:memory)
|
73
|
-
end
|
74
|
-
|
75
|
-
it "defaults instrumenter" do
|
76
|
-
instance = described_class.new(adapter)
|
77
|
-
instance.instrumenter.should be(Flipper::Instrumenters::Noop)
|
78
|
-
end
|
79
|
-
|
80
|
-
it "allows overriding instrumenter" do
|
81
|
-
instrumenter = double('Instrumentor', :instrument => nil)
|
82
|
-
instance = described_class.new(adapter, :instrumenter => instrumenter)
|
83
|
-
instance.instrumenter.should be(instrumenter)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
describe "#use_local_cache=" do
|
88
|
-
it "sets value" do
|
89
|
-
subject.use_local_cache = true
|
90
|
-
subject.using_local_cache?.should be_true
|
91
|
-
|
92
|
-
subject.use_local_cache = false
|
93
|
-
subject.using_local_cache?.should be_false
|
94
|
-
end
|
95
|
-
|
96
|
-
it "clears the local cache" do
|
97
|
-
local_cache.should_receive(:clear)
|
98
|
-
subject.use_local_cache = true
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
describe "#using_local_cache?" do
|
103
|
-
it "returns true if enabled" do
|
104
|
-
subject.use_local_cache = true
|
105
|
-
subject.using_local_cache?.should be_true
|
106
|
-
end
|
107
|
-
|
108
|
-
it "returns false if disabled" do
|
109
|
-
subject.use_local_cache = false
|
110
|
-
subject.using_local_cache?.should be_false
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
context "with local cache enabled" do
|
115
|
-
before do
|
116
|
-
subject.use_local_cache = true
|
117
|
-
end
|
118
|
-
|
119
|
-
describe "#read" do
|
120
|
-
before do
|
121
|
-
adapter.write 'foo', 'bar'
|
122
|
-
@result = subject.read('foo')
|
123
|
-
end
|
124
|
-
|
125
|
-
it "returns result of adapter read" do
|
126
|
-
@result.should eq('bar')
|
127
|
-
end
|
128
|
-
|
129
|
-
it "memoizes adapter read value" do
|
130
|
-
local_cache['foo'].should eq('bar')
|
131
|
-
adapter.should_not_receive(:read)
|
132
|
-
subject.read('foo').should eq('bar')
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
describe "#set_members" do
|
137
|
-
before do
|
138
|
-
source['foo'] = Set['1', '2']
|
139
|
-
@result = subject.set_members('foo')
|
140
|
-
end
|
141
|
-
|
142
|
-
it "returns result of adapter set members" do
|
143
|
-
@result.should eq(Set['1', '2'])
|
144
|
-
end
|
145
|
-
|
146
|
-
it "memoizes key" do
|
147
|
-
local_cache['foo'].should eq(Set['1', '2'])
|
148
|
-
adapter.should_not_receive(:set_members)
|
149
|
-
subject.set_members('foo').should eq(Set['1', '2'])
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
describe "#write" do
|
154
|
-
before do
|
155
|
-
subject.write 'foo', 'swanky'
|
156
|
-
end
|
157
|
-
|
158
|
-
it "performs adapter write" do
|
159
|
-
adapter.read('foo').should eq('swanky')
|
160
|
-
end
|
161
|
-
|
162
|
-
it "unmemoizes key" do
|
163
|
-
local_cache.key?('foo').should be_false
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
describe "#delete" do
|
168
|
-
before do
|
169
|
-
adapter.write 'foo', 'bar'
|
170
|
-
subject.delete 'foo'
|
171
|
-
end
|
172
|
-
|
173
|
-
it "performs adapter delete" do
|
174
|
-
adapter.read('foo').should be_nil
|
175
|
-
end
|
176
|
-
|
177
|
-
it "unmemoizes key" do
|
178
|
-
local_cache.key?('foo').should be_false
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
describe "#set_add" do
|
183
|
-
before do
|
184
|
-
source['foo'] = Set['1']
|
185
|
-
local_cache['foo'] = Set['1']
|
186
|
-
subject.set_add 'foo', '2'
|
187
|
-
end
|
188
|
-
|
189
|
-
it "returns result of adapter set members" do
|
190
|
-
adapter.set_members('foo').should eq(Set['1', '2'])
|
191
|
-
end
|
192
|
-
|
193
|
-
it "unmemoizes key" do
|
194
|
-
local_cache.key?('foo').should be_false
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
describe "#set_delete" do
|
199
|
-
before do
|
200
|
-
source['foo'] = Set['1', '2', '3']
|
201
|
-
local_cache['foo'] = Set['1', '2', '3']
|
202
|
-
subject.set_delete 'foo', '3'
|
203
|
-
end
|
204
|
-
|
205
|
-
it "returns result of adapter set members" do
|
206
|
-
adapter.set_members('foo').should eq(Set['1', '2'])
|
207
|
-
end
|
208
|
-
|
209
|
-
it "unmemoizes key" do
|
210
|
-
local_cache.key?('foo').should be_false
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
214
|
-
|
215
|
-
context "with local cache disabled" do
|
216
|
-
before do
|
217
|
-
subject.use_local_cache = false
|
218
|
-
end
|
219
|
-
|
220
|
-
describe "#read" do
|
221
|
-
before do
|
222
|
-
adapter.write 'foo', 'bar'
|
223
|
-
@result = subject.read('foo')
|
224
|
-
end
|
225
|
-
|
226
|
-
it "returns result of adapter read" do
|
227
|
-
@result.should eq('bar')
|
228
|
-
end
|
229
|
-
|
230
|
-
it "does not memoize adapter read value" do
|
231
|
-
local_cache.key?('foo').should be_false
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
describe "#set_members" do
|
236
|
-
before do
|
237
|
-
source['foo'] = Set['1', '2']
|
238
|
-
@result = subject.set_members('foo')
|
239
|
-
end
|
240
|
-
|
241
|
-
it "returns result of adapter set members" do
|
242
|
-
@result.should eq(Set['1', '2'])
|
243
|
-
end
|
244
|
-
|
245
|
-
it "does not memoize the adapter set member result" do
|
246
|
-
local_cache.key?('foo').should be_false
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
describe "#write" do
|
251
|
-
before do
|
252
|
-
adapter.write 'foo', 'bar'
|
253
|
-
local_cache['foo'] = 'bar'
|
254
|
-
subject.write 'foo', 'swanky'
|
255
|
-
end
|
256
|
-
|
257
|
-
it "performs adapter write" do
|
258
|
-
adapter.read('foo').should eq('swanky')
|
259
|
-
end
|
260
|
-
|
261
|
-
it "does not attempt to delete local cache key" do
|
262
|
-
local_cache.key?('foo').should be_true
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
describe "#delete" do
|
267
|
-
before do
|
268
|
-
adapter.write 'foo', 'bar'
|
269
|
-
local_cache['foo'] = 'bar'
|
270
|
-
subject.delete 'foo'
|
271
|
-
end
|
272
|
-
|
273
|
-
it "performs adapter delete" do
|
274
|
-
adapter.read('foo').should be_nil
|
275
|
-
end
|
276
|
-
|
277
|
-
it "does not attempt to delete local cache key" do
|
278
|
-
local_cache.key?('foo').should be_true
|
279
|
-
end
|
280
|
-
end
|
281
|
-
|
282
|
-
describe "#set_add" do
|
283
|
-
before do
|
284
|
-
source['foo'] = Set['1']
|
285
|
-
local_cache['foo'] = Set['1']
|
286
|
-
subject.set_add 'foo', '2'
|
287
|
-
end
|
288
|
-
|
289
|
-
it "performs adapter set add" do
|
290
|
-
adapter.set_members('foo').should eq(Set['1', '2'])
|
291
|
-
end
|
292
|
-
|
293
|
-
it "does not attempt to delete local cache key" do
|
294
|
-
local_cache.key?('foo').should be_true
|
295
|
-
end
|
296
|
-
end
|
297
|
-
|
298
|
-
describe "#set_delete" do
|
299
|
-
before do
|
300
|
-
source['foo'] = Set['1', '2', '3']
|
301
|
-
local_cache['foo'] = Set['1', '2', '3']
|
302
|
-
subject.set_delete 'foo', '3'
|
303
|
-
end
|
304
|
-
|
305
|
-
it "performs adapter set delete" do
|
306
|
-
adapter.set_members('foo').should eq(Set['1', '2'])
|
307
|
-
end
|
308
|
-
|
309
|
-
it "does not attempt to delete local cache key" do
|
310
|
-
local_cache.key?('foo').should be_true
|
311
|
-
end
|
312
|
-
end
|
313
|
-
end
|
314
|
-
|
315
|
-
describe "#eql?" do
|
316
|
-
it "returns true for same class and adapter" do
|
317
|
-
subject.eql?(described_class.new(adapter)).should be_true
|
318
|
-
end
|
319
|
-
|
320
|
-
it "returns false for different adapter" do
|
321
|
-
instance = described_class.new(Flipper::Adapters::Memory.new)
|
322
|
-
subject.eql?(instance).should be_false
|
323
|
-
end
|
324
|
-
|
325
|
-
it "returns false for different class" do
|
326
|
-
subject.eql?(Object.new).should be_false
|
327
|
-
end
|
328
|
-
|
329
|
-
it "is aliased to ==" do
|
330
|
-
(subject == described_class.new(adapter)).should be_true
|
331
|
-
end
|
332
|
-
end
|
333
|
-
|
334
|
-
describe "#features" do
|
335
|
-
context "with no features enabled/disabled" do
|
336
|
-
it "defaults to empty set" do
|
337
|
-
subject.features.should eq(Set.new)
|
338
|
-
end
|
339
|
-
end
|
340
|
-
|
341
|
-
context "with features enabled and disabled" do
|
342
|
-
before do
|
343
|
-
subject.set_add(features_key, 'stats')
|
344
|
-
subject.set_add(features_key, 'cache')
|
345
|
-
subject.set_add(features_key, 'search')
|
346
|
-
end
|
347
|
-
|
348
|
-
it "returns set of feature names" do
|
349
|
-
subject.features.should be_instance_of(Set)
|
350
|
-
subject.features.sort.should eq(['cache', 'search', 'stats'])
|
351
|
-
end
|
352
|
-
end
|
353
|
-
end
|
354
|
-
|
355
|
-
describe "#feature_add" do
|
356
|
-
context "with string name" do
|
357
|
-
before do
|
358
|
-
subject.feature_add('search')
|
359
|
-
end
|
360
|
-
|
361
|
-
it "adds string to set" do
|
362
|
-
subject.set_members(features_key).should include('search')
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
|
-
context "with symbol name" do
|
367
|
-
before do
|
368
|
-
subject.feature_add(:search)
|
369
|
-
end
|
370
|
-
|
371
|
-
it "adds string to set" do
|
372
|
-
subject.set_members(features_key).should include('search')
|
373
|
-
end
|
374
|
-
end
|
375
|
-
end
|
376
|
-
|
377
|
-
describe "instrumentation" do
|
378
|
-
let(:instrumenter) { Flipper::Instrumenters::Memory.new }
|
379
|
-
|
380
|
-
subject {
|
381
|
-
described_class.new(adapter, :instrumenter => instrumenter)
|
382
|
-
}
|
383
|
-
|
384
|
-
it "is recorded for read" do
|
385
|
-
subject.read('foo')
|
386
|
-
|
387
|
-
event = instrumenter.events.last
|
388
|
-
event.should_not be_nil
|
389
|
-
event.name.should eq('adapter_operation.flipper')
|
390
|
-
event.payload[:key].should eq('foo')
|
391
|
-
event.payload[:operation].should eq(:read)
|
392
|
-
event.payload[:adapter_name].should eq(:memory)
|
393
|
-
event.payload[:result].should be_nil
|
394
|
-
end
|
395
|
-
|
396
|
-
it "is recorded for write" do
|
397
|
-
subject.write('foo', 'bar')
|
398
|
-
|
399
|
-
event = instrumenter.events.last
|
400
|
-
event.should_not be_nil
|
401
|
-
event.name.should eq('adapter_operation.flipper')
|
402
|
-
event.payload[:key].should eq('foo')
|
403
|
-
event.payload[:value].should eq('bar')
|
404
|
-
event.payload[:operation].should eq(:write)
|
405
|
-
event.payload[:adapter_name].should eq(:memory)
|
406
|
-
event.payload[:result].should eq('bar')
|
407
|
-
end
|
408
|
-
|
409
|
-
it "is recorded for delete" do
|
410
|
-
subject.delete('foo')
|
411
|
-
|
412
|
-
event = instrumenter.events.last
|
413
|
-
event.should_not be_nil
|
414
|
-
event.name.should eq('adapter_operation.flipper')
|
415
|
-
event.payload[:key].should eq('foo')
|
416
|
-
event.payload[:operation].should eq(:delete)
|
417
|
-
event.payload[:adapter_name].should eq(:memory)
|
418
|
-
event.payload[:result].should be_nil
|
419
|
-
end
|
420
|
-
|
421
|
-
it "is recorded for set_members" do
|
422
|
-
subject.set_members('foo')
|
423
|
-
|
424
|
-
event = instrumenter.events.last
|
425
|
-
event.should_not be_nil
|
426
|
-
event.name.should eq('adapter_operation.flipper')
|
427
|
-
event.payload[:key].should eq('foo')
|
428
|
-
event.payload[:operation].should eq(:set_members)
|
429
|
-
event.payload[:adapter_name].should eq(:memory)
|
430
|
-
event.payload[:result].should eq(Set.new)
|
431
|
-
end
|
432
|
-
|
433
|
-
it "is recorded for set_add" do
|
434
|
-
subject.set_add('foo', 'bar')
|
435
|
-
|
436
|
-
event = instrumenter.events.last
|
437
|
-
event.should_not be_nil
|
438
|
-
event.name.should eq('adapter_operation.flipper')
|
439
|
-
event.payload[:key].should eq('foo')
|
440
|
-
event.payload[:operation].should eq(:set_add)
|
441
|
-
event.payload[:adapter_name].should eq(:memory)
|
442
|
-
event.payload[:result].should eq(Set['bar'])
|
443
|
-
end
|
444
|
-
|
445
|
-
it "is recorded for set_delete" do
|
446
|
-
subject.set_delete('foo', 'bar')
|
447
|
-
|
448
|
-
event = instrumenter.events.last
|
449
|
-
event.should_not be_nil
|
450
|
-
event.name.should eq('adapter_operation.flipper')
|
451
|
-
event.payload[:key].should eq('foo')
|
452
|
-
event.payload[:operation].should eq(:set_delete)
|
453
|
-
event.payload[:adapter_name].should eq(:memory)
|
454
|
-
event.payload[:result].should eq(Set.new)
|
455
|
-
end
|
456
|
-
end
|
457
|
-
|
458
|
-
describe "#inspect" do
|
459
|
-
it "returns easy to read string representation" do
|
460
|
-
subject.inspect.should eq("#<Flipper::Adapter:#{subject.object_id} name=:memory, use_local_cache=nil>")
|
461
|
-
end
|
462
|
-
end
|
463
|
-
end
|