abstract_feature_branch 1.3.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/README.md +10 -7
  4. data/VERSION +1 -1
  5. data/abstract_feature_branch.gemspec +6 -40
  6. data/lib/abstract_feature_branch/configuration.rb +8 -2
  7. data/lib/abstract_feature_branch/redis/connection_pool_to_redis_adapter.rb +34 -0
  8. data/lib/abstract_feature_branch.rb +3 -1
  9. data/lib/generators/templates/config/initializers/abstract_feature_branch.rb +4 -1
  10. metadata +5 -39
  11. data/.coveralls.yml +0 -1
  12. data/.travis.yml +0 -30
  13. data/RELEASE_NOTES.md +0 -55
  14. data/TODO.md +0 -3
  15. data/config/features/admin.local.yml +0 -15
  16. data/config/features/admin.yml +0 -17
  17. data/config/features/internal/wiki.local.yml +0 -15
  18. data/config/features/internal/wiki.yml +0 -17
  19. data/config/features/public.local.yml +0 -15
  20. data/config/features/public.yml +0 -17
  21. data/img/BigAstronaut-Logo.png +0 -0
  22. data/img/EarlyShares-Logo.svg +0 -22
  23. data/img/Factor75-Logo.svg +0 -54
  24. data/ruby187.Gemfile +0 -13
  25. data/spec/abstract_feature_branch/file_beautifier_spec.rb +0 -384
  26. data/spec/ext/feature_branch__feature_branch_per_user_spec.rb +0 -122
  27. data/spec/ext/feature_branch__feature_branch_spec.rb +0 -148
  28. data/spec/ext/feature_branch__feature_enabled_spec.rb +0 -274
  29. data/spec/fixtures/application_development_config/config/features.reference.yml +0 -21
  30. data/spec/fixtures/application_no_config/no_config +0 -1
  31. data/spec/fixtures/application_rails_config/config/features.local.yml +0 -16
  32. data/spec/fixtures/application_rails_config/config/features.yml +0 -20
  33. data/spec/fixtures/application_ugly_config_reference/config/another_application_configuration.yml +0 -31
  34. data/spec/fixtures/application_ugly_config_reference/config/database.yml +0 -17
  35. data/spec/fixtures/application_ugly_config_reference/config/features/admin.local.yml +0 -44
  36. data/spec/fixtures/application_ugly_config_reference/config/features/admin.yml +0 -44
  37. data/spec/fixtures/application_ugly_config_reference/config/features/empty.local.yml +0 -0
  38. data/spec/fixtures/application_ugly_config_reference/config/features/feature_empty_config.local.yml +0 -13
  39. data/spec/fixtures/application_ugly_config_reference/config/features/including_comments.local.yml +0 -52
  40. data/spec/fixtures/application_ugly_config_reference/config/features/internal/wiki.local.yml +0 -44
  41. data/spec/fixtures/application_ugly_config_reference/config/features/internal/wiki.yml +0 -44
  42. data/spec/fixtures/application_ugly_config_reference/config/features/public.local.yml +0 -44
  43. data/spec/fixtures/application_ugly_config_reference/config/features/public.yml +0 -44
  44. data/spec/fixtures/application_ugly_config_reference/config/features.local.yml +0 -44
  45. data/spec/fixtures/application_ugly_config_reference/config/features.yml +0 -49
data/ruby187.Gemfile DELETED
@@ -1,13 +0,0 @@
1
- source 'http://rubygems.org'
2
-
3
- gem 'deep_merge', '1.0.0', :require => false #avoid loading to use only if Rails is unavailable
4
- gem 'redis', '~> 3.0.0', :require => false
5
-
6
- group :development do
7
- gem 'jeweler', '1.8.8'
8
- gem 'rspec', '2.14.1'
9
-
10
- #Ruby 1.8.7 compatible versions
11
- gem "nokogiri", "~> 1.5.0"
12
- gem "highline", "~> 1.6.21"
13
- end
@@ -1,384 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe AbstractFeatureBranch::FileBeautifier do
4
- describe '#process' do
5
- before do
6
- @ugly_config_application_root = File.expand_path(File.join(__FILE__, '..', '..', 'fixtures', 'application_ugly_config'))
7
- @ugly_config_application_reference_root = File.expand_path(File.join(__FILE__, '..', '..', 'fixtures', 'application_ugly_config_reference'))
8
- FileUtils.rm_rf( @ugly_config_application_root)
9
- FileUtils.cp_r(@ugly_config_application_reference_root, @ugly_config_application_root)
10
- end
11
- after do
12
- FileUtils.rm_rf( @ugly_config_application_root)
13
- end
14
-
15
- context "a file is specified" do
16
- it 'gets rid of extra empty lines' do
17
- feature_file_path = File.expand_path(File.join(__FILE__, '..', '..', 'fixtures', 'application_ugly_config', 'config', 'features.yml'))
18
- AbstractFeatureBranch::FileBeautifier.process(feature_file_path)
19
- File.open(feature_file_path, 'r') do |file|
20
- file.readlines.join.should == <<-EXPECTED_FILE_CONTENT
21
- defaults: &defaults
22
- FEATURE1: true
23
- Feature2: true
24
- feature3: false
25
- feature4: true
26
- feature4a: true
27
-
28
- development:
29
- <<: *defaults
30
- FEATURE1: true
31
- Feature2: true
32
- feature3: false
33
- feature4: true
34
- feature4a: true
35
-
36
- test:
37
- <<: *defaults
38
- FEATURE1: true
39
- Feature2: true
40
- feature3: false
41
- feature4: true
42
- feature4a: true
43
-
44
- staging:
45
- <<: *defaults
46
- FEATURE1: true
47
- Feature2: true
48
- feature3: false
49
- feature4: true
50
- feature4a: true
51
-
52
- production:
53
- <<: *defaults
54
- FEATURE1: true
55
- Feature2: true
56
- feature3: false
57
- feature4: true
58
- feature4a: true
59
-
60
- EXPECTED_FILE_CONTENT
61
- end
62
- end
63
-
64
- it 'sorts features by name under each section (e.g. environment)' do
65
- local_feature_file_path = File.expand_path(File.join(__FILE__, '..', '..', 'fixtures', 'application_ugly_config', 'config', 'features.local.yml'))
66
- AbstractFeatureBranch::FileBeautifier.process(local_feature_file_path)
67
- File.open(local_feature_file_path, 'r') do |file|
68
- file.readlines.join.should == <<-EXPECTED_FILE_CONTENT
69
- defaults: &defaults
70
- FEATURE1: true
71
- Feature2: true
72
- feature3: false
73
- feature4: true
74
- feature4a: true
75
-
76
- development:
77
- <<: *defaults
78
- FEATURE1: true
79
- Feature2: true
80
- feature3: false
81
- feature4: true
82
- feature4a: true
83
-
84
- test:
85
- <<: *defaults
86
- FEATURE1: true
87
- Feature2: true
88
- feature3: false
89
- feature4: true
90
- feature4a: true
91
-
92
- staging:
93
- <<: *defaults
94
- FEATURE1: true
95
- Feature2: true
96
- feature3: false
97
- feature4: true
98
- feature4a: true
99
-
100
- production:
101
- <<: *defaults
102
- FEATURE1: true
103
- Feature2: true
104
- feature3: false
105
- feature4: true
106
- feature4a: true
107
-
108
- EXPECTED_FILE_CONTENT
109
- end
110
- end
111
-
112
- it 'handles comments by ignoring comments on top and deleting comments in the middle' do
113
- feature_file_path = File.expand_path(File.join(__FILE__, '..', '..', 'fixtures', 'application_ugly_config', 'config', 'features', 'including_comments.local.yml'))
114
- AbstractFeatureBranch::FileBeautifier.process(feature_file_path)
115
- File.open(feature_file_path, 'r') do |file|
116
- file.readlines.join.should == <<-EXPECTED_FILE_CONTENT
117
- # This file allows you to override any feature configuration locally without it being committed to git
118
- # It is recommended to use this file only for temporary overrides. Once done, make final change in main .yml
119
- defaults: &defaults
120
- FEATURE1: true
121
- Feature2: true
122
- feature3: false
123
- feature4: true
124
- feature4a: true
125
-
126
- development:
127
- <<: *defaults
128
- FEATURE1: true
129
- Feature2: true
130
- feature3: false
131
- feature4: true
132
- feature4a: true
133
-
134
- test:
135
- <<: *defaults
136
- FEATURE1: true
137
- Feature2: true
138
- feature3: false
139
- feature4: true
140
- feature4a: true
141
-
142
- staging:
143
- <<: *defaults
144
- FEATURE1: true
145
- Feature2: true
146
- feature3: false
147
- feature4: true
148
- feature4a: true
149
-
150
- production:
151
- <<: *defaults
152
- FEATURE1: true
153
- Feature2: true
154
- feature3: false
155
- feature4: true
156
- feature4a: true
157
-
158
- EXPECTED_FILE_CONTENT
159
- end
160
- end
161
-
162
- it 'processes a feature empty config file' do
163
- feature_file_path = File.expand_path(File.join(__FILE__, '..', '..', 'fixtures', 'application_ugly_config', 'config', 'features', 'feature_empty_config.local.yml'))
164
- AbstractFeatureBranch::FileBeautifier.process(feature_file_path)
165
- File.open(feature_file_path, 'r') do |file|
166
- file.readlines.join.should == <<-EXPECTED_FILE_CONTENT
167
- defaults: &defaults
168
-
169
-
170
- development:
171
- <<: *defaults
172
-
173
- test:
174
- <<: *defaults
175
-
176
- staging:
177
- <<: *defaults
178
-
179
- production:
180
- <<: *defaults
181
-
182
- EXPECTED_FILE_CONTENT
183
- end
184
- end
185
-
186
- it 'processes an empty file without change or exceptions' do
187
- feature_file_path = File.expand_path(File.join(__FILE__, '..', '..', 'fixtures', 'application_ugly_config', 'config', 'features', 'empty.local.yml'))
188
- AbstractFeatureBranch::FileBeautifier.process(feature_file_path)
189
- File.open(feature_file_path, 'r') do |file|
190
- file.readlines.join.should be_empty
191
- end
192
- end
193
-
194
- end
195
-
196
- context "a directory is specified" do
197
- it 'beautifies all YAML files under specified directory recursively' do
198
- feature_directory_path = File.expand_path(File.join(__FILE__, '..', '..', 'fixtures', 'application_ugly_config', 'config', 'features'))
199
- AbstractFeatureBranch::FileBeautifier.process(feature_directory_path)
200
-
201
- ['public.yml', 'public.local.yml', 'admin.yml', 'admin.local.yml', 'internal/wiki.yml', 'internal/wiki.local.yml'].each do |file_path_suffix|
202
- file_path = File.join(feature_directory_path, file_path_suffix)
203
- File.open(file_path, 'r') do |file|
204
- file.readlines.join.should == <<-EXPECTED_FILE_CONTENT
205
- defaults: &defaults
206
- FEATURE1: true
207
- Feature2: true
208
- feature3: false
209
- feature4: true
210
- feature4a: true
211
-
212
- development:
213
- <<: *defaults
214
- FEATURE1: true
215
- Feature2: true
216
- feature3: false
217
- feature4: true
218
- feature4a: true
219
-
220
- test:
221
- <<: *defaults
222
- FEATURE1: true
223
- Feature2: true
224
- feature3: false
225
- feature4: true
226
- feature4a: true
227
-
228
- staging:
229
- <<: *defaults
230
- FEATURE1: true
231
- Feature2: true
232
- feature3: false
233
- feature4: true
234
- feature4a: true
235
-
236
- production:
237
- <<: *defaults
238
- FEATURE1: true
239
- Feature2: true
240
- feature3: false
241
- feature4: true
242
- feature4a: true
243
-
244
- EXPECTED_FILE_CONTENT
245
- end
246
- end
247
- end
248
-
249
- context "no file or directory is specified (process all feature files)" do
250
- after do
251
- AbstractFeatureBranch.initialize_application_root
252
- AbstractFeatureBranch.load_application_features
253
- end
254
- it 'beautifies all feature files in the application' do
255
- AbstractFeatureBranch.application_root = File.expand_path(File.join(__FILE__, '..', '..', 'fixtures', 'application_ugly_config'))
256
- AbstractFeatureBranch.load_application_features
257
- AbstractFeatureBranch::FileBeautifier.process
258
-
259
- [
260
- 'features.yml',
261
- 'features.local.yml',
262
- 'features/public.yml',
263
- 'features/public.local.yml',
264
- 'features/admin.yml',
265
- 'features/admin.local.yml',
266
- 'features/internal/wiki.yml',
267
- 'features/internal/wiki.local.yml'
268
- ].each do |file_path_suffix|
269
- file_path = File.join(AbstractFeatureBranch.application_root, 'config', file_path_suffix)
270
- File.open(file_path, 'r') do |file|
271
- file.readlines.join.should == <<-EXPECTED_FILE_CONTENT
272
- defaults: &defaults
273
- FEATURE1: true
274
- Feature2: true
275
- feature3: false
276
- feature4: true
277
- feature4a: true
278
-
279
- development:
280
- <<: *defaults
281
- FEATURE1: true
282
- Feature2: true
283
- feature3: false
284
- feature4: true
285
- feature4a: true
286
-
287
- test:
288
- <<: *defaults
289
- FEATURE1: true
290
- Feature2: true
291
- feature3: false
292
- feature4: true
293
- feature4a: true
294
-
295
- staging:
296
- <<: *defaults
297
- FEATURE1: true
298
- Feature2: true
299
- feature3: false
300
- feature4: true
301
- feature4a: true
302
-
303
- production:
304
- <<: *defaults
305
- FEATURE1: true
306
- Feature2: true
307
- feature3: false
308
- feature4: true
309
- feature4a: true
310
-
311
- EXPECTED_FILE_CONTENT
312
- end
313
- end
314
- end
315
-
316
- it 'does not beautify non-feature files in the application' do
317
- AbstractFeatureBranch.application_root = File.expand_path(File.join(__FILE__, '..', '..', 'fixtures', 'application_ugly_config'))
318
- AbstractFeatureBranch.load_application_features
319
- AbstractFeatureBranch::FileBeautifier.process
320
-
321
- file_path = File.join(AbstractFeatureBranch.application_root, 'config', 'another_application_configuration.yml')
322
- File.open(file_path, 'r') do |file|
323
- file.readlines.join.should == <<-ANOTHER_APPLICATION_CONFIGURATION_CONTENT
324
- common: &default_settings
325
- license_key: <%= ENV["LICENSE_KEY"] %>
326
- app_name: <%= ENV["APP_NAME"] %>
327
- monitor_mode: true
328
- developer_mode: false
329
- log_level: info
330
-
331
- browser_monitoring:
332
- auto_instrument: true
333
-
334
- audit_log:
335
- enabled: false
336
-
337
-
338
- development:
339
- <<: *default_settings
340
- monitor_mode: false
341
- developer_mode: true
342
-
343
- test:
344
- <<: *default_settings
345
- monitor_mode: false
346
-
347
- production:
348
- <<: *default_settings
349
- monitor_mode: true
350
-
351
- staging:
352
- <<: *default_settings
353
- monitor_mode: true
354
- app_name: <%= ENV["APP_NAME"] %> (Staging)
355
- ANOTHER_APPLICATION_CONFIGURATION_CONTENT
356
- end
357
-
358
- file_path = File.join(AbstractFeatureBranch.application_root, 'config', 'database.yml')
359
- File.open(file_path, 'r') do |file|
360
- file.readlines.join.should == <<-DATABASE_CONFIGURATION_CONTENT
361
- development:
362
- adapter: sqlite3
363
- database: db/development.sqlite3
364
- pool: 5
365
- timeout: 5000
366
-
367
- test:
368
- adapter: sqlite3
369
- database: db/test.sqlite3
370
- pool: 5
371
- timeout: 5000
372
-
373
- production:
374
- adapter: sqlite3
375
- database: db/production.sqlite3
376
- pool: 5
377
- timeout: 5000
378
- DATABASE_CONFIGURATION_CONTENT
379
- end
380
- end
381
- end
382
- end
383
- end
384
- end
@@ -1,122 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'feature_branch object extensions' do
4
- before do
5
- @app_env_backup = AbstractFeatureBranch.application_environment
6
- @app_root_backup = AbstractFeatureBranch.application_root
7
- AbstractFeatureBranch.logger.warn 'Environment variable ABSTRACT_FEATURE_BRANCH_FEATURE1 already set, potentially conflicting with another test' if ENV.keys.include?('ABSTRACT_FEATURE_BRANCH_FEATURE1')
8
- AbstractFeatureBranch.logger.warn 'Environment variable Abstract_Feature_Branch_Feature2 already set, potentially conflicting with another test' if ENV.keys.include?('Abstract_Feature_Branch_Feature2')
9
- AbstractFeatureBranch.logger.warn 'Environment variable abstract_feature_branch_feature3 already set, potentially conflicting with another test' if ENV.keys.include?('abstract_feature_branch_feature3')
10
- begin
11
- AbstractFeatureBranch.user_features_storage.flushall
12
- rescue => e
13
- #noop
14
- end
15
- end
16
- after do
17
- ENV.delete('ABSTRACT_FEATURE_BRANCH_FEATURE1')
18
- ENV.delete('Abstract_Feature_Branch_Feature2')
19
- ENV.delete('abstract_feature_branch_feature3')
20
- AbstractFeatureBranch.application_root = @app_root_backup
21
- AbstractFeatureBranch.application_environment = @app_env_backup
22
- AbstractFeatureBranch.unload_application_features
23
- begin
24
- AbstractFeatureBranch.user_features_storage.flushall
25
- rescue => e
26
- #noop
27
- end
28
- AbstractFeatureBranch.user_features_storage.keys.each do |key|
29
- AbstractFeatureBranch.user_features_storage.del(key)
30
- end
31
- end
32
- describe '#feature_branch' do
33
- context 'per user' do
34
- it 'feature branches correctly after storing feature configuration per user in a separate process (ensuring persistence)' do
35
- user_id = 'email1@example.com'
36
- ruby_code = <<-RUBY_CODE
37
- $:.unshift('.')
38
- require 'redis'
39
- require 'lib/abstract_feature_branch'
40
- AbstractFeatureBranch.initialize_user_features_storage
41
- AbstractFeatureBranch.toggle_features_for_user('#{user_id}', :feature1 => false, :feature3 => true, :feature6 => true, :feature7 => false)
42
- RUBY_CODE
43
- system "ruby -e \"#{ruby_code}\""
44
- features_enabled = []
45
- feature_branch :feature1, user_id do
46
- features_enabled << :feature1
47
- end
48
- feature_branch :feature3, user_id do
49
- features_enabled << :feature3
50
- end
51
- feature_branch :feature6, user_id do
52
- features_enabled << :feature6
53
- end
54
- feature_branch :feature6, 'otheruser@example.com' do
55
- features_enabled << :feature6_otheruser
56
- end
57
- feature_branch :feature6 do
58
- features_enabled << :feature6_nouserspecified
59
- end
60
- feature_branch :feature7, user_id do
61
- features_enabled << :feature7
62
- end
63
- features_enabled.should include(:feature1) #remains like features.yml
64
- features_enabled.should_not include(:feature3) #remains like features.yml
65
- features_enabled.should include(:feature6) #per user honored as true
66
- features_enabled.should_not include(:feature6_otheruser) #per user honored as false
67
- features_enabled.should_not include(:feature6_nouserspecified) #per user requires user id or it returns false
68
- features_enabled.should_not include(:feature7) #per user honored as false
69
- end
70
- it 'update feature branching (disabling some features) after having stored feature configuration per user in a separate process (ensuring persistence)' do
71
- user_id = 'email1@example.com'
72
- ruby_code = <<-RUBY_CODE
73
- $:.unshift('.')
74
- require 'redis'
75
- require 'lib/abstract_feature_branch'
76
- AbstractFeatureBranch.initialize_user_features_storage
77
- AbstractFeatureBranch.toggle_features_for_user('#{user_id}', :feature6 => true, :feature7 => false)
78
- AbstractFeatureBranch.toggle_features_for_user('#{user_id}', :feature6 => false, :feature7 => true)
79
- RUBY_CODE
80
- system "ruby -e \"#{ruby_code}\""
81
- features_enabled = []
82
- feature_branch :feature6, user_id do
83
- features_enabled << :feature6
84
- end
85
- feature_branch :feature7, user_id do
86
- features_enabled << :feature7
87
- end
88
- features_enabled.should_not include(:feature6)
89
- features_enabled.should include(:feature7)
90
- end
91
-
92
- end
93
- end
94
- describe 'self#feature_branch' do
95
- after do
96
- Object.send(:remove_const, :TestObject)
97
- end
98
- # No need to retest all instance test cases, just a spot check due to implementation reuse
99
- it 'feature branches instance level behavior (case-insensitive feature names)' do
100
- class TestObject
101
- def self.features_enabled
102
- @features_enabled ||= []
103
- end
104
- def self.hit_me
105
- feature_branch :feature1 do
106
- self.features_enabled << :feature1
107
- end
108
- feature_branch :feature2 do
109
- self.features_enabled << :feature2
110
- end
111
- feature_branch :feature3 do
112
- self.features_enabled << :feature3
113
- end
114
- end
115
- end
116
- TestObject.hit_me
117
- TestObject.features_enabled.should include(:feature1)
118
- TestObject.features_enabled.should include(:feature2)
119
- TestObject.features_enabled.should_not include(:feature3)
120
- end
121
- end
122
- end
@@ -1,148 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe 'feature_branch object extensions' do
4
- before do
5
- @app_env_backup = AbstractFeatureBranch.application_environment
6
- @app_root_backup = AbstractFeatureBranch.application_root
7
- AbstractFeatureBranch.logger.warn 'Environment variable ABSTRACT_FEATURE_BRANCH_FEATURE1 already set, potentially conflicting with another test' if ENV.keys.include?('ABSTRACT_FEATURE_BRANCH_FEATURE1')
8
- AbstractFeatureBranch.logger.warn 'Environment variable Abstract_Feature_Branch_Feature2 already set, potentially conflicting with another test' if ENV.keys.include?('Abstract_Feature_Branch_Feature2')
9
- AbstractFeatureBranch.logger.warn 'Environment variable abstract_feature_branch_feature3 already set, potentially conflicting with another test' if ENV.keys.include?('abstract_feature_branch_feature3')
10
- end
11
- after do
12
- ENV.delete('ABSTRACT_FEATURE_BRANCH_FEATURE1')
13
- ENV.delete('Abstract_Feature_Branch_Feature2')
14
- ENV.delete('abstract_feature_branch_feature3')
15
- AbstractFeatureBranch.application_root = @app_root_backup
16
- AbstractFeatureBranch.application_environment = @app_env_backup
17
- AbstractFeatureBranch.unload_application_features
18
- AbstractFeatureBranch.user_features_storage.keys.each do |key|
19
- AbstractFeatureBranch.user_features_storage.del(key)
20
- end
21
- end
22
- describe '#feature_branch' do
23
- context 'class level behavior (case-insensitive string or symbol feature names)' do
24
- {
25
- 'Feature1' => true,
26
- :FEATURE2 => true,
27
- :feature3 => false,
28
- :admin_feature1 => true,
29
- :admin_feature2 => false,
30
- :public_feature1 => true,
31
- :public_feature2 => false,
32
- :wiki_feature1 => true,
33
- :wiki_feature2 => false,
34
- }.each do |feature_name, expected_branch_run|
35
- it "feature branches correctly for feature #{feature_name} with expected branch run #{expected_branch_run}" do
36
- feature_branch_run = false
37
- feature_branch feature_name do
38
- feature_branch_run = true
39
- end
40
- feature_branch_run.should == expected_branch_run
41
- end
42
- end
43
- end
44
- it 'returns nil and does not execute block for an invalid feature name' do
45
- return_value = feature_branch :invalid_feature_that_does_not_exist do
46
- fail 'feature branch block must not execute, but did.'
47
- end
48
- return_value.should be_nil
49
- end
50
- it 'allows environment variables (case-insensitive booleans) to override configuration file' do
51
- ENV['ABSTRACT_FEATURE_BRANCH_FEATURE1'] = 'FALSE'
52
- ENV['Abstract_Feature_Branch_Feature2'] = 'False'
53
- ENV['abstract_feature_branch_feature3'] = 'true'
54
- AbstractFeatureBranch.load_application_features
55
- features_enabled = []
56
- feature_branch :feature1 do
57
- features_enabled << :feature1
58
- end
59
- feature_branch :feature2 do
60
- features_enabled << :feature2
61
- end
62
- feature_branch :feature3 do
63
- features_enabled << :feature3
64
- end
65
- features_enabled.should_not include(:feature1)
66
- features_enabled.should_not include(:feature2)
67
- features_enabled.should include(:feature3)
68
- end
69
- it 'allows redis variables (case-insensitive booleans) to override configuration file' do
70
- AbstractFeatureBranch.unload_application_features
71
- AbstractFeatureBranch.user_features_storage.hset('abstract_feature_branch', 'FEATURE1', 'FALSE')
72
- AbstractFeatureBranch.user_features_storage.hset('abstract_feature_branch', 'Feature2', 'False')
73
- AbstractFeatureBranch.user_features_storage.hset('abstract_feature_branch', 'feature3', 'true')
74
- AbstractFeatureBranch.load_application_features
75
- features_enabled = []
76
- feature_branch :feature1 do
77
- features_enabled << :feature1
78
- end
79
- feature_branch :feature2 do
80
- features_enabled << :feature2
81
- end
82
- feature_branch :feature3 do
83
- features_enabled << :feature3
84
- end
85
- features_enabled.should_not include(:feature1)
86
- features_enabled.should_not include(:feature2)
87
- features_enabled.should include(:feature3)
88
- end
89
- it 'allows local configuration file to override main configuration file' do
90
- features_enabled = []
91
- feature_branch :feature4 do
92
- features_enabled << :feature4
93
- end
94
- feature_branch :feature5 do
95
- features_enabled << :feature5
96
- end
97
- feature_branch :admin_feature3 do
98
- features_enabled << :admin_feature3
99
- end
100
- feature_branch :public_feature3 do
101
- features_enabled << :public_feature3
102
- end
103
- feature_branch :wiki_feature3 do
104
- features_enabled << :wiki_feature3
105
- end
106
- features_enabled.should_not include(:feature4)
107
- features_enabled.should include(:feature5)
108
- features_enabled.should include(:admin_feature3)
109
- features_enabled.should include(:public_feature3)
110
- features_enabled.should include(:wiki_feature3)
111
- end
112
- it 'works with an application that has no configuration files' do
113
- AbstractFeatureBranch.application_root = File.join(__FILE__, '..', '..', 'fixtures', 'application_no_config')
114
- AbstractFeatureBranch.load_application_features
115
- feature_branch :feature1 do
116
- fail 'feature branch block must not execute, but did.'
117
- end
118
- end
119
- end
120
- describe 'self#feature_branch' do
121
- after do
122
- Object.send(:remove_const, :TestObject)
123
- end
124
- # No need to retest all instance test cases, just a spot check due to implementation reuse
125
- it 'feature branches instance level behavior (case-insensitive feature names)' do
126
- class TestObject
127
- def self.features_enabled
128
- @features_enabled ||= []
129
- end
130
- def self.hit_me
131
- feature_branch :feature1 do
132
- self.features_enabled << :feature1
133
- end
134
- feature_branch :feature2 do
135
- self.features_enabled << :feature2
136
- end
137
- feature_branch :feature3 do
138
- self.features_enabled << :feature3
139
- end
140
- end
141
- end
142
- TestObject.hit_me
143
- TestObject.features_enabled.should include(:feature1)
144
- TestObject.features_enabled.should include(:feature2)
145
- TestObject.features_enabled.should_not include(:feature3)
146
- end
147
- end
148
- end