flipper-api 0.20.3 → 0.22.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/lib/flipper/api.rb +0 -3
- data/lib/flipper/api/middleware.rb +2 -1
- data/lib/flipper/api/v1/actions/percentage_of_actors_gate.rb +9 -1
- data/lib/flipper/api/v1/actions/percentage_of_time_gate.rb +9 -1
- data/lib/flipper/version.rb +1 -1
- data/spec/flipper/api/v1/actions/actors_gate_spec.rb +19 -1
- data/spec/flipper/api/v1/actions/percentage_of_actors_gate_spec.rb +47 -21
- data/spec/flipper/api/v1/actions/percentage_of_time_gate_spec.rb +67 -21
- data/spec/flipper/api_spec.rb +36 -0
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c9e87d4217900f7ce0ff46ea9fa6c145ec1d01e226395529e7ec8ab782bf8119
|
4
|
+
data.tar.gz: 8473cf20629a95691441912a1a8b0ed623b59f84865c2f45410d600fb9a342c1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d16c137e2541de6fa6d53f7e48296be6a17b98bed5c8393274af9766c041c1189bfa823934e694d46b3d041d34df4e132e3158f6a3f7cdba8a9ebc9e9b1b8b0a
|
7
|
+
data.tar.gz: 5979c36e18707e094941a0e12fae47a2203a6bd5b53218c574b63d100f9323109646bd7a429d8c89c4611e86e9a152642feefc74bdb8deea19ac07b6c9a306c2
|
data/lib/flipper/api.rb
CHANGED
@@ -9,14 +9,11 @@ module Flipper
|
|
9
9
|
|
10
10
|
def self.app(flipper = nil, options = {})
|
11
11
|
env_key = options.fetch(:env_key, 'flipper')
|
12
|
-
memoizer_options = options.fetch(:memoizer_options, {})
|
13
|
-
|
14
12
|
app = ->(_) { [404, { 'Content-Type'.freeze => CONTENT_TYPE }, ['{}'.freeze]] }
|
15
13
|
builder = Rack::Builder.new
|
16
14
|
yield builder if block_given?
|
17
15
|
builder.use Flipper::Api::JsonParams
|
18
16
|
builder.use Flipper::Middleware::SetupEnv, flipper, env_key: env_key
|
19
|
-
builder.use Flipper::Middleware::Memoizer, memoizer_options.merge(env_key: env_key)
|
20
17
|
builder.use Flipper::Api::Middleware, env_key: env_key
|
21
18
|
builder.run app
|
22
19
|
klass = self
|
@@ -32,10 +32,11 @@ module Flipper
|
|
32
32
|
def call!(env)
|
33
33
|
request = Rack::Request.new(env)
|
34
34
|
action_class = @action_collection.action_for_request(request)
|
35
|
+
|
35
36
|
if action_class.nil?
|
36
37
|
@app.call(env)
|
37
38
|
else
|
38
|
-
flipper = env.fetch(@env_key)
|
39
|
+
flipper = env.fetch(@env_key) { Flipper }
|
39
40
|
action_class.run(flipper, request)
|
40
41
|
end
|
41
42
|
end
|
@@ -30,9 +30,17 @@ module Flipper
|
|
30
30
|
|
31
31
|
private
|
32
32
|
|
33
|
+
def percentage_param
|
34
|
+
@percentage_param ||= params['percentage'].to_s
|
35
|
+
end
|
36
|
+
|
33
37
|
def percentage
|
34
38
|
@percentage ||= begin
|
35
|
-
|
39
|
+
unless percentage_param.match(/\d/)
|
40
|
+
raise ArgumentError, "invalid numeric value: #{percentage_param}"
|
41
|
+
end
|
42
|
+
|
43
|
+
Flipper::Types::Percentage.new(percentage_param).value
|
36
44
|
rescue ArgumentError, TypeError
|
37
45
|
-1
|
38
46
|
end
|
@@ -31,9 +31,17 @@ module Flipper
|
|
31
31
|
|
32
32
|
private
|
33
33
|
|
34
|
+
def percentage_param
|
35
|
+
@percentage_param ||= params['percentage'].to_s
|
36
|
+
end
|
37
|
+
|
34
38
|
def percentage
|
35
39
|
@percentage ||= begin
|
36
|
-
|
40
|
+
unless percentage_param.match(/\d/)
|
41
|
+
raise ArgumentError, "invalid numeric value: #{percentage_param}"
|
42
|
+
end
|
43
|
+
|
44
|
+
Flipper::Types::Percentage.new(percentage_param).value
|
37
45
|
rescue ArgumentError, TypeError
|
38
46
|
-1
|
39
47
|
end
|
data/lib/flipper/version.rb
CHANGED
@@ -44,7 +44,7 @@ RSpec.describe Flipper::Api::V1::Actions::ActorsGate do
|
|
44
44
|
|
45
45
|
describe 'enable feature with slash in name' do
|
46
46
|
before do
|
47
|
-
flipper[
|
47
|
+
flipper["my/feature"].disable_actor(actor)
|
48
48
|
post '/features/my/feature/actors', flipper_id: actor.flipper_id
|
49
49
|
end
|
50
50
|
|
@@ -60,6 +60,24 @@ RSpec.describe Flipper::Api::V1::Actions::ActorsGate do
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
+
describe 'enable feature with space in name' do
|
64
|
+
before do
|
65
|
+
flipper["sp ace"].disable_actor(actor)
|
66
|
+
post '/features/sp%20ace/actors', flipper_id: actor.flipper_id
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'enables feature for actor' do
|
70
|
+
expect(last_response.status).to eq(200)
|
71
|
+
expect(flipper["sp ace"].enabled?(actor)).to be_truthy
|
72
|
+
expect(flipper["sp ace"].enabled_gate_names).to eq([:actor])
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'returns decorated feature with actor enabled' do
|
76
|
+
gate = json_response['gates'].find { |gate| gate['key'] == 'actors' }
|
77
|
+
expect(gate['value']).to eq(['1'])
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
63
81
|
describe 'enable missing flipper_id parameter' do
|
64
82
|
before do
|
65
83
|
flipper[:my_feature].enable
|
@@ -4,53 +4,79 @@ RSpec.describe Flipper::Api::V1::Actions::PercentageOfActorsGate do
|
|
4
4
|
let(:app) { build_api(flipper) }
|
5
5
|
|
6
6
|
describe 'enable' do
|
7
|
+
shared_examples 'gates with percentage' do
|
8
|
+
it 'enables gate for feature' do
|
9
|
+
expect(flipper[path].enabled_gate_names).to include(:percentage_of_actors)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'returns decorated feature with gate enabled for a percent of actors' do
|
13
|
+
gate = json_response['gates'].find { |gate| gate['name'] == 'percentage_of_actors' }
|
14
|
+
expect(gate['value']).to eq(percentage)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
7
18
|
context 'for feature with slash in name' do
|
19
|
+
let(:path) { 'my/feature' }
|
20
|
+
|
8
21
|
before do
|
9
|
-
flipper[
|
10
|
-
post
|
22
|
+
flipper[path].disable
|
23
|
+
post "/features/#{path}/percentage_of_actors", percentage: percentage
|
11
24
|
end
|
12
25
|
|
13
|
-
|
14
|
-
|
26
|
+
context 'with integer percentage' do
|
27
|
+
let(:percentage) { '10' }
|
28
|
+
|
29
|
+
it_behaves_like 'gates with percentage'
|
15
30
|
end
|
16
31
|
|
17
|
-
|
18
|
-
|
19
|
-
|
32
|
+
context 'with decimal percentage' do
|
33
|
+
let(:percentage) { '0.05' }
|
34
|
+
|
35
|
+
it_behaves_like 'gates with percentage'
|
20
36
|
end
|
21
37
|
end
|
22
38
|
|
23
39
|
context 'url-encoded request' do
|
40
|
+
let(:path) { :my_feature }
|
41
|
+
|
24
42
|
before do
|
25
43
|
flipper[:my_feature].disable
|
26
|
-
post
|
44
|
+
post "/features/#{path}/percentage_of_actors", percentage: percentage
|
27
45
|
end
|
28
46
|
|
29
|
-
|
30
|
-
|
47
|
+
context 'with integer percentage' do
|
48
|
+
let(:percentage) { '10' }
|
49
|
+
|
50
|
+
it_behaves_like 'gates with percentage'
|
31
51
|
end
|
32
52
|
|
33
|
-
|
34
|
-
|
35
|
-
|
53
|
+
context 'with decimal percentage' do
|
54
|
+
let(:percentage) { '0.05' }
|
55
|
+
|
56
|
+
it_behaves_like 'gates with percentage'
|
36
57
|
end
|
37
58
|
end
|
38
59
|
|
39
60
|
context 'json request' do
|
61
|
+
let(:path) { :my_feature }
|
62
|
+
|
40
63
|
before do
|
41
64
|
flipper[:my_feature].disable
|
42
|
-
post
|
43
|
-
JSON.generate(percentage:
|
65
|
+
post "/features/#{path}/percentage_of_actors",
|
66
|
+
JSON.generate(percentage: percentage),
|
44
67
|
'CONTENT_TYPE' => 'application/json'
|
45
68
|
end
|
46
69
|
|
47
|
-
|
48
|
-
|
70
|
+
context 'with integer percentage' do
|
71
|
+
let(:percentage) { '10' }
|
72
|
+
|
73
|
+
it_behaves_like 'gates with percentage'
|
49
74
|
end
|
50
75
|
|
51
|
-
|
52
|
-
|
53
|
-
|
76
|
+
context 'with decimal percentage' do
|
77
|
+
let(:percentage) { '0.05' }
|
78
|
+
|
79
|
+
it_behaves_like 'gates with percentage'
|
54
80
|
end
|
55
81
|
end
|
56
82
|
end
|
@@ -113,7 +139,7 @@ RSpec.describe Flipper::Api::V1::Actions::PercentageOfActorsGate do
|
|
113
139
|
end
|
114
140
|
end
|
115
141
|
|
116
|
-
describe 'percentage parameter not
|
142
|
+
describe 'percentage parameter not a number' do
|
117
143
|
before do
|
118
144
|
flipper[:my_feature].disable
|
119
145
|
post '/features/my_feature/percentage_of_actors', percentage: 'foo'
|
@@ -4,34 +4,80 @@ RSpec.describe Flipper::Api::V1::Actions::PercentageOfTimeGate do
|
|
4
4
|
let(:app) { build_api(flipper) }
|
5
5
|
|
6
6
|
describe 'enable' do
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
shared_examples 'gates with percentage' do
|
8
|
+
it 'enables gate for feature' do
|
9
|
+
expect(flipper[path].enabled_gate_names).to include(:percentage_of_time)
|
10
|
+
end
|
11
11
|
|
12
|
-
|
13
|
-
|
12
|
+
it 'returns decorated feature with gate enabled for a percent of times' do
|
13
|
+
gate = json_response['gates'].find { |gate| gate['name'] == 'percentage_of_time' }
|
14
|
+
expect(gate['value']).to eq(percentage)
|
15
|
+
end
|
14
16
|
end
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
-
expect(gate['value']).to eq('10')
|
19
|
-
end
|
20
|
-
end
|
18
|
+
context 'for feature with slash in name' do
|
19
|
+
let(:path) { 'my/feature' }
|
21
20
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
before do
|
22
|
+
flipper[path].disable
|
23
|
+
post "/features/#{path}/percentage_of_time", percentage: percentage
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'with integer percentage' do
|
27
|
+
let(:percentage) { '10' }
|
28
|
+
|
29
|
+
it_behaves_like 'gates with percentage'
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'with decimal percentage' do
|
33
|
+
let(:percentage) { '0.05' }
|
34
|
+
|
35
|
+
it_behaves_like 'gates with percentage'
|
36
|
+
end
|
26
37
|
end
|
27
38
|
|
28
|
-
|
29
|
-
|
39
|
+
context 'url-encoded request' do
|
40
|
+
let(:path) { :my_feature }
|
41
|
+
|
42
|
+
before do
|
43
|
+
flipper[:my_feature].disable
|
44
|
+
post "/features/#{path}/percentage_of_time", percentage: percentage
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'with integer percentage' do
|
48
|
+
let(:percentage) { '10' }
|
49
|
+
|
50
|
+
it_behaves_like 'gates with percentage'
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'with decimal percentage' do
|
54
|
+
let(:percentage) { '0.05' }
|
55
|
+
|
56
|
+
it_behaves_like 'gates with percentage'
|
57
|
+
end
|
30
58
|
end
|
31
59
|
|
32
|
-
|
33
|
-
|
34
|
-
|
60
|
+
context 'json request' do
|
61
|
+
let(:path) { :my_feature }
|
62
|
+
|
63
|
+
before do
|
64
|
+
flipper[:my_feature].disable
|
65
|
+
post "/features/#{path}/percentage_of_time",
|
66
|
+
JSON.generate(percentage: percentage),
|
67
|
+
'CONTENT_TYPE' => 'application/json'
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'with integer percentage' do
|
71
|
+
let(:percentage) { '10' }
|
72
|
+
|
73
|
+
it_behaves_like 'gates with percentage'
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'with decimal percentage' do
|
77
|
+
let(:percentage) { '0.05' }
|
78
|
+
|
79
|
+
it_behaves_like 'gates with percentage'
|
80
|
+
end
|
35
81
|
end
|
36
82
|
end
|
37
83
|
|
@@ -93,7 +139,7 @@ RSpec.describe Flipper::Api::V1::Actions::PercentageOfTimeGate do
|
|
93
139
|
end
|
94
140
|
end
|
95
141
|
|
96
|
-
describe 'percentage parameter not an
|
142
|
+
describe 'percentage parameter not an number' do
|
97
143
|
before do
|
98
144
|
flipper[:my_feature].disable
|
99
145
|
post '/features/my_feature/percentage_of_time', percentage: 'foo'
|
data/spec/flipper/api_spec.rb
CHANGED
@@ -1,6 +1,36 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
RSpec.describe Flipper::Api do
|
4
|
+
describe 'Initializing middleware with flipper instance' do
|
5
|
+
let(:app) { build_api(flipper) }
|
6
|
+
|
7
|
+
it 'works' do
|
8
|
+
flipper.enable :a
|
9
|
+
flipper.disable :b
|
10
|
+
|
11
|
+
get '/features'
|
12
|
+
|
13
|
+
expect(last_response.status).to be(200)
|
14
|
+
feature_names = json_response.fetch('features').map { |feature| feature.fetch('key') }
|
15
|
+
expect(feature_names).to eq(%w(a b))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'Initializing middleware lazily with a block' do
|
20
|
+
let(:app) { build_api(-> { flipper }) }
|
21
|
+
|
22
|
+
it 'works' do
|
23
|
+
flipper.enable :a
|
24
|
+
flipper.disable :b
|
25
|
+
|
26
|
+
get '/features'
|
27
|
+
|
28
|
+
expect(last_response.status).to be(200)
|
29
|
+
feature_names = json_response.fetch('features').map { |feature| feature.fetch('key') }
|
30
|
+
expect(feature_names).to eq(%w(a b))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
4
34
|
context 'when initialized with flipper instance and flipper instance in env' do
|
5
35
|
let(:app) { build_api(flipper) }
|
6
36
|
|
@@ -76,4 +106,10 @@ RSpec.describe Flipper::Api do
|
|
76
106
|
expect(json_response).to eq({})
|
77
107
|
end
|
78
108
|
end
|
109
|
+
|
110
|
+
describe 'Inspecting the built Rack app' do
|
111
|
+
it 'returns a String' do
|
112
|
+
expect(build_api(flipper).inspect).to be_a(String)
|
113
|
+
end
|
114
|
+
end
|
79
115
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flipper-api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.22.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Nunemaker
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-07-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -36,14 +36,14 @@ dependencies:
|
|
36
36
|
requirements:
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: 0.
|
39
|
+
version: 0.22.0
|
40
40
|
type: :runtime
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
44
|
- - "~>"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: 0.
|
46
|
+
version: 0.22.0
|
47
47
|
description:
|
48
48
|
email:
|
49
49
|
- nunemaker@gmail.com
|