flipper-api 0.10.2 → 0.11.0.beta1

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 (30) hide show
  1. checksums.yaml +4 -4
  2. data/flipper-api.gemspec +12 -12
  3. data/lib/flipper/api/action.rb +12 -10
  4. data/lib/flipper/api/action_collection.rb +2 -2
  5. data/lib/flipper/api/error_response.rb +9 -8
  6. data/lib/flipper/api/json_params.rb +45 -0
  7. data/lib/flipper/api/middleware.rb +3 -28
  8. data/lib/flipper/api/v1/actions/actors_gate.rb +1 -9
  9. data/lib/flipper/api/v1/actions/boolean_gate.rb +1 -1
  10. data/lib/flipper/api/v1/actions/clear_feature.rb +21 -0
  11. data/lib/flipper/api/v1/actions/feature.rb +8 -16
  12. data/lib/flipper/api/v1/actions/features.rb +26 -8
  13. data/lib/flipper/api/v1/actions/groups_gate.rb +18 -7
  14. data/lib/flipper/api/v1/actions/percentage_of_actors_gate.rb +6 -24
  15. data/lib/flipper/api/v1/actions/percentage_of_time_gate.rb +6 -23
  16. data/lib/flipper/api/v1/decorators/feature.rb +3 -4
  17. data/lib/flipper/api.rb +11 -27
  18. data/lib/flipper/version.rb +1 -1
  19. data/spec/flipper/api/action_spec.rb +30 -36
  20. data/spec/flipper/api/json_params_spec.rb +81 -0
  21. data/spec/flipper/api/v1/actions/actors_gate_spec.rb +33 -22
  22. data/spec/flipper/api/v1/actions/boolean_gate_spec.rb +2 -2
  23. data/spec/flipper/api/v1/actions/clear_feature_spec.rb +27 -0
  24. data/spec/flipper/api/v1/actions/feature_spec.rb +28 -30
  25. data/spec/flipper/api/v1/actions/features_spec.rb +79 -44
  26. data/spec/flipper/api/v1/actions/groups_gate_spec.rb +92 -10
  27. data/spec/flipper/api/v1/actions/percentage_of_actors_gate_spec.rb +62 -24
  28. data/spec/flipper/api/v1/actions/percentage_of_time_gate_spec.rb +34 -15
  29. data/spec/flipper/api_spec.rb +55 -0
  30. metadata +15 -7
@@ -10,58 +10,88 @@ RSpec.describe Flipper::Api::V1::Actions::Features do
10
10
  before do
11
11
  flipper[:my_feature].enable
12
12
  flipper[:my_feature].enable(admin)
13
- get 'api/v1/features'
13
+ get '/features'
14
14
  end
15
15
 
16
16
  it 'responds with correct attributes' do
17
17
  expected_response = {
18
- "features" => [
18
+ 'features' => [
19
19
  {
20
- "key" => "my_feature",
21
- "state" => "on",
22
- "gates" => [
20
+ 'key' => 'my_feature',
21
+ 'state' => 'on',
22
+ 'gates' => [
23
23
  {
24
- "key"=> "boolean",
25
- "name"=> "boolean",
26
- "value" => true
24
+ 'key' => 'boolean',
25
+ 'name' => 'boolean',
26
+ 'value' => 'true',
27
27
  },
28
28
  {
29
- "key" => "groups",
30
- "name" => "group",
31
- "value" => [],
29
+ 'key' => 'groups',
30
+ 'name' => 'group',
31
+ 'value' => [],
32
32
  },
33
33
  {
34
- "key" => "actors",
35
- "name" => "actor",
36
- "value" => ["10"],
34
+ 'key' => 'actors',
35
+ 'name' => 'actor',
36
+ 'value' => ['10'],
37
37
  },
38
38
  {
39
- "key" => "percentage_of_actors",
40
- "name" => "percentage_of_actors",
41
- "value" => 0,
39
+ 'key' => 'percentage_of_actors',
40
+ 'name' => 'percentage_of_actors',
41
+ 'value' => nil,
42
42
  },
43
43
  {
44
- "key"=> "percentage_of_time",
45
- "name"=> "percentage_of_time",
46
- "value"=> 0,
44
+ 'key' => 'percentage_of_time',
45
+ 'name' => 'percentage_of_time',
46
+ 'value' => nil,
47
47
  },
48
48
  ],
49
49
  },
50
- ]
50
+ ],
51
51
  }
52
52
  expect(last_response.status).to eq(200)
53
53
  expect(json_response).to eq(expected_response)
54
54
  end
55
55
  end
56
56
 
57
+ context 'with keys specified' do
58
+ before do
59
+ flipper[:audit_log].enable
60
+ flipper[:issues].enable
61
+ flipper[:search].enable
62
+ flipper[:stats].disable
63
+ get '/features', 'keys' => 'search,stats'
64
+ end
65
+
66
+ it 'responds with correct attributes' do
67
+ expect(last_response.status).to eq(200)
68
+ keys = json_response.fetch('features').map { |feature| feature.fetch('key') }.sort
69
+ expect(keys).to eq(%w(search stats))
70
+ end
71
+ end
72
+
73
+ context 'with keys that are not existing features' do
74
+ before do
75
+ flipper[:search].disable
76
+ flipper[:stats].disable
77
+ get '/features', 'keys' => 'search,stats,not_a_feature,another_feature_that_does_not_exist'
78
+ end
79
+
80
+ it 'only returns features that exist' do
81
+ expect(last_response.status).to eq(200)
82
+ keys = json_response.fetch('features').map { |feature| feature.fetch('key') }.sort
83
+ expect(keys).to eq(%w(search stats))
84
+ end
85
+ end
86
+
57
87
  context 'with no flipper features' do
58
88
  before do
59
- get 'api/v1/features'
89
+ get '/features'
60
90
  end
61
91
 
62
92
  it 'returns empty array for features key' do
63
93
  expected_response = {
64
- "features" => []
94
+ 'features' => [],
65
95
  }
66
96
  expect(last_response.status).to eq(200)
67
97
  expect(json_response).to eq(expected_response)
@@ -72,7 +102,7 @@ RSpec.describe Flipper::Api::V1::Actions::Features do
72
102
  describe 'post' do
73
103
  context 'succesful request' do
74
104
  before do
75
- post 'api/v1/features', { name: 'my_feature' }
105
+ post '/features', name: 'my_feature'
76
106
  end
77
107
 
78
108
  it 'responds 200 ' do
@@ -82,33 +112,33 @@ RSpec.describe Flipper::Api::V1::Actions::Features do
82
112
  it 'returns decorated feature' do
83
113
  expected_response = {
84
114
 
85
- "key" => "my_feature",
86
- "state" => "off",
87
- "gates" => [
115
+ 'key' => 'my_feature',
116
+ 'state' => 'off',
117
+ 'gates' => [
88
118
  {
89
- "key"=> "boolean",
90
- "name"=> "boolean",
91
- "value" => false,
119
+ 'key' => 'boolean',
120
+ 'name' => 'boolean',
121
+ 'value' => nil,
92
122
  },
93
123
  {
94
- "key" => "groups",
95
- "name" => "group",
96
- "value" => [],
124
+ 'key' => 'groups',
125
+ 'name' => 'group',
126
+ 'value' => [],
97
127
  },
98
128
  {
99
- "key" => "actors",
100
- "name" => "actor",
101
- "value" => [],
129
+ 'key' => 'actors',
130
+ 'name' => 'actor',
131
+ 'value' => [],
102
132
  },
103
133
  {
104
- "key" => "percentage_of_actors",
105
- "name" => "percentage_of_actors",
106
- "value" => 0,
134
+ 'key' => 'percentage_of_actors',
135
+ 'name' => 'percentage_of_actors',
136
+ 'value' => nil,
107
137
  },
108
138
  {
109
- "key"=> "percentage_of_time",
110
- "name"=> "percentage_of_time",
111
- "value"=> 0,
139
+ 'key' => 'percentage_of_time',
140
+ 'name' => 'percentage_of_time',
141
+ 'value' => nil,
112
142
  },
113
143
  ],
114
144
  }
@@ -126,7 +156,7 @@ RSpec.describe Flipper::Api::V1::Actions::Features do
126
156
 
127
157
  context 'bad request' do
128
158
  before do
129
- post 'api/v1/features'
159
+ post '/features'
130
160
  end
131
161
 
132
162
  it 'returns correct status code' do
@@ -134,7 +164,12 @@ RSpec.describe Flipper::Api::V1::Actions::Features do
134
164
  end
135
165
 
136
166
  it 'returns formatted error' do
137
- expect(json_response).to eq({ 'code' => 5, 'message' => 'Required parameter name is missing.', 'more_info' => 'https://github.com/jnunemaker/flipper/tree/master/docs/api#error-code-reference' })
167
+ expected = {
168
+ 'code' => 5,
169
+ 'message' => 'Required parameter name is missing.',
170
+ 'more_info' => api_error_code_reference_url,
171
+ }
172
+ expect(json_response).to eq(expected)
138
173
  end
139
174
  end
140
175
  end
@@ -9,7 +9,7 @@ RSpec.describe Flipper::Api::V1::Actions::GroupsGate do
9
9
  Flipper.register(:admins) do |actor|
10
10
  actor.respond_to?(:admin?) && actor.admin?
11
11
  end
12
- post '/api/v1/features/my_feature/groups', { name: 'admins' }
12
+ post '/features/my_feature/groups', name: 'admins'
13
13
  end
14
14
 
15
15
  it 'enables feature for group' do
@@ -26,6 +26,29 @@ RSpec.describe Flipper::Api::V1::Actions::GroupsGate do
26
26
  end
27
27
  end
28
28
 
29
+ describe 'enable without name params' do
30
+ before do
31
+ flipper[:my_feature].disable
32
+ Flipper.register(:admins) do |actor|
33
+ actor.respond_to?(:admin?) && actor.admin?
34
+ end
35
+ post '/features/my_feature/groups'
36
+ end
37
+
38
+ it 'returns correct status code' do
39
+ expect(last_response.status).to eq(422)
40
+ end
41
+
42
+ it 'returns formatted error' do
43
+ expected = {
44
+ 'code' => 5,
45
+ 'message' => 'Required parameter name is missing.',
46
+ 'more_info' => api_error_code_reference_url,
47
+ }
48
+ expect(json_response).to eq(expected)
49
+ end
50
+ end
51
+
29
52
  describe 'disable' do
30
53
  before do
31
54
  flipper[:my_feature].disable
@@ -33,7 +56,7 @@ RSpec.describe Flipper::Api::V1::Actions::GroupsGate do
33
56
  actor.respond_to?(:admin?) && actor.admin?
34
57
  end
35
58
  flipper[:my_feature].enable_group(:admins)
36
- delete '/api/v1/features/my_feature/groups', { name: 'admins' }
59
+ delete '/features/my_feature/groups', name: 'admins'
37
60
  end
38
61
 
39
62
  it 'disables feature for group' do
@@ -50,26 +73,85 @@ RSpec.describe Flipper::Api::V1::Actions::GroupsGate do
50
73
  end
51
74
  end
52
75
 
53
- describe 'non-existent feature' do
76
+ describe 'disable for non-existent feature' do
54
77
  before do
55
- delete '/api/v1/features/my_feature/groups', { name: 'admins' }
78
+ Flipper.register(:admins) do |actor|
79
+ actor.respond_to?(:admin?) && actor.admin?
80
+ end
81
+ delete '/features/my_feature/groups', name: 'admins'
56
82
  end
57
83
 
58
- it '404s with correct error response when feature does not exist' do
59
- expect(last_response.status).to eq(404)
60
- expect(json_response).to eq({ 'code' => 1, 'message' => 'Feature not found.', 'more_info' => 'https://github.com/jnunemaker/flipper/tree/master/docs/api#error-code-reference' })
84
+ it 'disables feature for group' do
85
+ person = double
86
+ allow(person).to receive(:flipper_id).and_return(1)
87
+ allow(person).to receive(:admin?).and_return(true)
88
+ expect(last_response.status).to eq(200)
89
+ expect(flipper[:my_feature].enabled?(person)).to be_falsey
90
+ end
91
+
92
+ it 'returns decorated feature with group disabled' do
93
+ group_gate = json_response['gates'].find { |m| m['name'] == 'group' }
94
+ expect(group_gate['value']).to eq([])
61
95
  end
62
96
  end
63
97
 
64
- describe 'group not registered' do
98
+ describe 'disable for group not registered' do
65
99
  before do
66
100
  flipper[:my_feature].disable
67
- delete '/api/v1/features/my_feature/groups', { name: 'admins' }
101
+ delete '/features/my_feature/groups', name: 'admins'
68
102
  end
69
103
 
70
104
  it '404s with correct error response when group not registered' do
71
105
  expect(last_response.status).to eq(404)
72
- expect(json_response).to eq({ 'code' => 2, 'message' => 'Group not registered.', 'more_info' => 'https://github.com/jnunemaker/flipper/tree/master/docs/api#error-code-reference' })
106
+ expected = {
107
+ 'code' => 2,
108
+ 'message' => 'Group not registered.',
109
+ 'more_info' => api_error_code_reference_url,
110
+ }
111
+ expect(json_response).to eq(expected)
112
+ end
113
+ end
114
+
115
+ describe 'enable for group not registered when allow_unregistered_groups is true' do
116
+ before do
117
+ Flipper.unregister_groups
118
+ flipper[:my_feature].disable
119
+ post '/features/my_feature/groups', name: 'admins', allow_unregistered_groups: 'true'
120
+ end
121
+
122
+ it 'responds successfully' do
123
+ expect(last_response.status).to eq(200)
124
+ end
125
+
126
+ it 'returns decorated feature with group in groups set' do
127
+ group_gate = json_response['gates'].find { |m| m['name'] == 'group' }
128
+ expect(group_gate['value']).to eq(['admins'])
129
+ end
130
+
131
+ it 'enables group' do
132
+ expect(flipper[:my_feature].groups_value).to eq(Set["admins"])
133
+ end
134
+ end
135
+
136
+ describe 'disable for group not registered when allow_unregistered_groups is true' do
137
+ before do
138
+ Flipper.unregister_groups
139
+ flipper[:my_feature].disable
140
+ flipper[:my_feature].enable_group(:admins)
141
+ delete '/features/my_feature/groups', name: 'admins', allow_unregistered_groups: 'true'
142
+ end
143
+
144
+ it 'responds successfully' do
145
+ expect(last_response.status).to eq(200)
146
+ end
147
+
148
+ it 'returns decorated feature with group not in groups set' do
149
+ group_gate = json_response['gates'].find { |m| m['name'] == 'group' }
150
+ expect(group_gate['value']).to eq([])
151
+ end
152
+
153
+ it 'disables group' do
154
+ expect(flipper[:my_feature].groups_value).to be_empty
73
155
  end
74
156
  end
75
157
  end
@@ -4,26 +4,45 @@ RSpec.describe Flipper::Api::V1::Actions::PercentageOfActorsGate do
4
4
  let(:app) { build_api(flipper) }
5
5
 
6
6
  describe 'enable' do
7
- before do
8
- flipper[:my_feature].disable
9
- post '/api/v1/features/my_feature/percentage_of_actors', { percentage: '10' }
7
+ context 'url-encoded request' do
8
+ before do
9
+ flipper[:my_feature].disable
10
+ post '/features/my_feature/percentage_of_actors', percentage: '10'
11
+ end
12
+
13
+ it 'enables gate for feature' do
14
+ expect(flipper[:my_feature].enabled_gate_names).to include(:percentage_of_actors)
15
+ end
16
+
17
+ it 'returns decorated feature with gate enabled for 10 percent of actors' do
18
+ gate = json_response['gates'].find { |gate| gate['name'] == 'percentage_of_actors' }
19
+ expect(gate['value']).to eq('10')
20
+ end
10
21
  end
11
22
 
12
- it 'enables gate for feature' do
13
- expect(flipper[:my_feature].enabled_gate_names).to include(:percentage_of_actors)
14
- end
15
-
16
- it 'returns decorated feature with gate enabled for 10 percent of actors' do
17
- gate = json_response['gates'].find { |gate| gate['name'] == 'percentage_of_actors' }
18
- expect(gate['value']).to eq(10)
23
+ context 'json request' do
24
+ before do
25
+ flipper[:my_feature].disable
26
+ post '/features/my_feature/percentage_of_actors',
27
+ JSON.generate(percentage: '10'),
28
+ 'CONTENT_TYPE' => 'application/json'
29
+ end
30
+
31
+ it 'enables gate for feature' do
32
+ expect(flipper[:my_feature].enabled_gate_names).to include(:percentage_of_actors)
33
+ end
34
+
35
+ it 'returns decorated feature with gate enabled for 10 percent of actors' do
36
+ gate = json_response['gates'].find { |gate| gate['name'] == 'percentage_of_actors' }
37
+ expect(gate['value']).to eq('10')
38
+ end
19
39
  end
20
-
21
40
  end
22
41
 
23
- describe 'disable' do
42
+ describe 'disable without percentage' do
24
43
  before do
25
44
  flipper[:my_feature].enable_percentage_of_actors(10)
26
- delete '/api/v1/features/my_feature/percentage_of_actors'
45
+ delete '/features/my_feature/percentage_of_actors'
27
46
  end
28
47
 
29
48
  it 'disables gate for feature' do
@@ -32,54 +51,73 @@ RSpec.describe Flipper::Api::V1::Actions::PercentageOfActorsGate do
32
51
 
33
52
  it 'returns decorated feature with gate disabled' do
34
53
  gate = json_response['gates'].find { |gate| gate['name'] == 'percentage_of_actors' }
35
- expect(gate['value']).to eq(0)
54
+ expect(gate['value']).to eq('0')
55
+ end
56
+ end
57
+
58
+ describe 'disable with percentage' do
59
+ before do
60
+ flipper[:my_feature].enable_percentage_of_actors(10)
61
+ delete '/features/my_feature/percentage_of_actors',
62
+ JSON.generate(percentage: '5'),
63
+ 'CONTENT_TYPE' => 'application/json'
64
+ end
65
+
66
+ it 'returns decorated feature with gate value set to 0 regardless of percentage requested' do
67
+ gate = json_response['gates'].find { |gate| gate['name'] == 'percentage_of_actors' }
68
+ expect(gate['value']).to eq('0')
36
69
  end
37
70
  end
38
71
 
39
72
  describe 'non-existent feature' do
40
73
  before do
41
- delete '/api/v1/features/my_feature/percentage_of_actors'
74
+ delete '/features/my_feature/percentage_of_actors'
75
+ end
76
+
77
+ it 'disables gate for feature' do
78
+ expect(flipper[:my_feature].enabled_gates).to be_empty
42
79
  end
43
80
 
44
- it '404s with correct error response when feature does not exist' do
45
- expect(last_response.status).to eq(404)
46
- expect(json_response).to eq({ 'code' => 1, 'message' => 'Feature not found.', 'more_info' => 'https://github.com/jnunemaker/flipper/tree/master/docs/api#error-code-reference' })
81
+ it 'returns decorated feature with gate disabled' do
82
+ expect(last_response.status).to eq(200)
83
+ gate = json_response['gates'].find { |gate| gate['name'] == 'percentage_of_actors' }
84
+ expect(gate['value']).to eq('0')
47
85
  end
48
86
  end
49
87
 
50
88
  describe 'out of range parameter percentage parameter' do
51
89
  before do
52
90
  flipper[:my_feature].disable
53
- post '/api/v1/features/my_feature/percentage_of_actors', { percentage: '300' }
91
+ post '/features/my_feature/percentage_of_actors', percentage: '300'
54
92
  end
55
93
 
56
94
  it '422s with correct error response when percentage parameter is invalid' do
57
95
  expect(last_response.status).to eq(422)
58
- expect(json_response).to eq({ 'code' => 3, 'message' => 'Percentage must be a positive number less than or equal to 100.', 'more_info' => 'https://github.com/jnunemaker/flipper/tree/master/docs/api#error-code-reference' })
96
+ expect(json_response).to eq(api_positive_percentage_error_response)
59
97
  end
60
98
  end
61
99
 
62
100
  describe 'percentage parameter not an integer' do
63
101
  before do
64
102
  flipper[:my_feature].disable
65
- post '/api/v1/features/my_feature/percentage_of_actors', { percentage: 'foo' }
103
+ post '/features/my_feature/percentage_of_actors', percentage: 'foo'
66
104
  end
67
105
 
68
106
  it '422s with correct error response when percentage parameter is invalid' do
69
107
  expect(last_response.status).to eq(422)
70
- expect(json_response).to eq({ 'code' => 3, 'message' => 'Percentage must be a positive number less than or equal to 100.', 'more_info' => 'https://github.com/jnunemaker/flipper/tree/master/docs/api#error-code-reference' })
108
+ expect(json_response).to eq(api_positive_percentage_error_response)
71
109
  end
72
110
  end
73
111
 
74
112
  describe 'missing percentage parameter' do
75
113
  before do
76
114
  flipper[:my_feature].disable
77
- post '/api/v1/features/my_feature/percentage_of_actors'
115
+ post '/features/my_feature/percentage_of_actors'
78
116
  end
79
117
 
80
118
  it '422s with correct error response when percentage parameter is missing' do
81
119
  expect(last_response.status).to eq(422)
82
- expect(json_response).to eq({ 'code' => 3, 'message' => 'Percentage must be a positive number less than or equal to 100.', 'more_info' => 'https://github.com/jnunemaker/flipper/tree/master/docs/api#error-code-reference' })
120
+ expect(json_response).to eq(api_positive_percentage_error_response)
83
121
  end
84
122
  end
85
123
  end
@@ -6,7 +6,7 @@ RSpec.describe Flipper::Api::V1::Actions::PercentageOfTimeGate do
6
6
  describe 'enable' do
7
7
  before do
8
8
  flipper[:my_feature].disable
9
- post '/api/v1/features/my_feature/percentage_of_time', { percentage: '10' }
9
+ post '/features/my_feature/percentage_of_time', percentage: '10'
10
10
  end
11
11
 
12
12
  it 'enables gate for feature' do
@@ -15,14 +15,14 @@ RSpec.describe Flipper::Api::V1::Actions::PercentageOfTimeGate do
15
15
 
16
16
  it 'returns decorated feature with gate enabled for 5% of time' do
17
17
  gate = json_response['gates'].find { |gate| gate['name'] == 'percentage_of_time' }
18
- expect(gate['value']).to eq(10)
18
+ expect(gate['value']).to eq('10')
19
19
  end
20
20
  end
21
21
 
22
- describe 'disable' do
22
+ describe 'disable without percentage' do
23
23
  before do
24
24
  flipper[:my_feature].enable_percentage_of_time(10)
25
- delete '/api/v1/features/my_feature/percentage_of_time'
25
+ delete '/features/my_feature/percentage_of_time'
26
26
  end
27
27
 
28
28
  it 'disables gate for feature' do
@@ -31,54 +31,73 @@ RSpec.describe Flipper::Api::V1::Actions::PercentageOfTimeGate do
31
31
 
32
32
  it 'returns decorated feature with gate disabled' do
33
33
  gate = json_response['gates'].find { |gate| gate['name'] == 'percentage_of_time' }
34
- expect(gate['value']).to eq(0)
34
+ expect(gate['value']).to eq('0')
35
+ end
36
+ end
37
+
38
+ describe 'disable with percentage' do
39
+ before do
40
+ flipper[:my_feature].enable_percentage_of_time(10)
41
+ delete '/features/my_feature/percentage_of_time',
42
+ JSON.generate(percentage: '5'),
43
+ 'CONTENT_TYPE' => 'application/json'
44
+ end
45
+
46
+ it 'returns decorated feature with gate value set to 0 regardless of percentage requested' do
47
+ expect(last_response.status).to eq(200)
48
+ gate = json_response['gates'].find { |gate| gate['name'] == 'percentage_of_time' }
49
+ expect(gate['value']).to eq('0')
35
50
  end
36
51
  end
37
52
 
38
53
  describe 'non-existent feature' do
39
54
  before do
40
- delete '/api/v1/features/my_feature/percentage_of_time'
55
+ delete '/features/my_feature/percentage_of_time'
41
56
  end
42
57
 
43
- it '404s with correct error response when feature does not exist' do
44
- expect(last_response.status).to eq(404)
45
- expect(json_response).to eq({ 'code' => 1, 'message' => 'Feature not found.', 'more_info' => 'https://github.com/jnunemaker/flipper/tree/master/docs/api#error-code-reference' })
58
+ it 'disables gate for feature' do
59
+ expect(flipper[:my_feature].enabled_gates).to be_empty
60
+ end
61
+
62
+ it 'returns decorated feature with gate disabled' do
63
+ gate = json_response['gates'].find { |gate| gate['name'] == 'percentage_of_time' }
64
+ expect(gate['value']).to eq('0')
46
65
  end
47
66
  end
48
67
 
49
68
  describe 'out of range parameter percentage parameter' do
50
69
  before do
51
70
  flipper[:my_feature].disable
52
- post '/api/v1/features/my_feature/percentage_of_time', { percentage: '300' }
71
+ post '/features/my_feature/percentage_of_time', percentage: '300'
53
72
  end
54
73
 
55
74
  it '422s with correct error response when percentage parameter is invalid' do
56
75
  expect(last_response.status).to eq(422)
57
- expect(json_response).to eq({ 'code' => 3, 'message' => 'Percentage must be a positive number less than or equal to 100.', 'more_info' => 'https://github.com/jnunemaker/flipper/tree/master/docs/api#error-code-reference' })
76
+ expect(json_response).to eq(api_positive_percentage_error_response)
58
77
  end
59
78
  end
60
79
 
61
80
  describe 'percentage parameter not an integer' do
62
81
  before do
63
82
  flipper[:my_feature].disable
64
- post '/api/v1/features/my_feature/percentage_of_time', { percentage: 'foo' }
83
+ post '/features/my_feature/percentage_of_time', percentage: 'foo'
65
84
  end
66
85
 
67
86
  it '422s with correct error response when percentage parameter is invalid' do
68
87
  expect(last_response.status).to eq(422)
69
- expect(json_response).to eq({ 'code' => 3, 'message' => 'Percentage must be a positive number less than or equal to 100.', 'more_info' => 'https://github.com/jnunemaker/flipper/tree/master/docs/api#error-code-reference' })
88
+ expect(json_response).to eq(api_positive_percentage_error_response)
70
89
  end
71
90
  end
72
91
 
73
92
  describe 'missing percentage parameter' do
74
93
  before do
75
94
  flipper[:my_feature].disable
76
- post '/api/v1/features/my_feature/percentage_of_time'
95
+ post '/features/my_feature/percentage_of_time'
77
96
  end
78
97
 
79
98
  it '422s with correct error response when percentage parameter is missing' do
80
99
  expect(last_response.status).to eq(422)
81
- expect(json_response).to eq({ 'code' => 3, 'message' => 'Percentage must be a positive number less than or equal to 100.', 'more_info' => 'https://github.com/jnunemaker/flipper/tree/master/docs/api#error-code-reference' })
100
+ expect(json_response).to eq(api_positive_percentage_error_response)
82
101
  end
83
102
  end
84
103
  end
@@ -0,0 +1,55 @@
1
+ require 'helper'
2
+
3
+ RSpec.describe Flipper::Api do
4
+ context 'when initialized with flipper instance and flipper instance in env' do
5
+ let(:app) { build_api(flipper) }
6
+
7
+ it 'uses env instance over initialized instance' do
8
+ flipper[:built_a].enable
9
+ flipper[:built_b].disable
10
+
11
+ env_flipper = build_flipper
12
+ env_flipper[:env_a].enable
13
+ env_flipper[:env_b].disable
14
+
15
+ params = {}
16
+ env = {
17
+ 'flipper' => env_flipper,
18
+ }
19
+ get '/features', params, env
20
+
21
+ expect(last_response.status).to eq(200)
22
+ feature_names = json_response.fetch('features').map { |feature| feature.fetch('key') }
23
+ expect(feature_names).to eq(%w(env_a env_b))
24
+ end
25
+ end
26
+
27
+ context 'when initialized without flipper instance but flipper instance in env' do
28
+ let(:app) { described_class.app }
29
+
30
+ it 'uses env instance' do
31
+ flipper[:a].enable
32
+ flipper[:b].disable
33
+
34
+ params = {}
35
+ env = {
36
+ 'flipper' => flipper,
37
+ }
38
+ get '/features', params, env
39
+
40
+ expect(last_response.status).to eq(200)
41
+ feature_names = json_response.fetch('features').map { |feature| feature.fetch('key') }
42
+ expect(feature_names).to eq(%w(a b))
43
+ end
44
+ end
45
+
46
+ context "when request does not match any api routes" do
47
+ let(:app) { build_api(flipper) }
48
+
49
+ it "returns 404" do
50
+ get '/gibberish'
51
+ expect(last_response.status).to eq(404)
52
+ expect(json_response).to eq({})
53
+ end
54
+ end
55
+ end