|
1234 | 1234 | expect(config.send(:generate_feature_variation_map, config.feature_flags)).to eq(expected_feature_variation_map)
|
1235 | 1235 | end
|
1236 | 1236 | end
|
| 1237 | + |
| 1238 | + describe '#get_holdouts_for_flag' do |
| 1239 | + let(:config_with_holdouts) do |
| 1240 | + Optimizely::DatafileProjectConfig.new( |
| 1241 | + OptimizelySpec::CONFIG_BODY_WITH_HOLDOUTS_JSON, |
| 1242 | + logger, |
| 1243 | + error_handler |
| 1244 | + ) |
| 1245 | + end |
| 1246 | + |
| 1247 | + it 'should return empty array for non-existent flag' do |
| 1248 | + holdouts = config_with_holdouts.get_holdouts_for_flag('non_existent_flag') |
| 1249 | + expect(holdouts).to eq([]) |
| 1250 | + end |
| 1251 | + |
| 1252 | + it 'should return global holdouts that do not exclude the flag' do |
| 1253 | + holdouts = config_with_holdouts.get_holdouts_for_flag('multi_variate_feature') |
| 1254 | + expect(holdouts.length).to eq(2) |
| 1255 | + |
| 1256 | + global_holdout = holdouts.find { |h| h['key'] == 'global_holdout' } |
| 1257 | + expect(global_holdout).not_to be_nil |
| 1258 | + expect(global_holdout['id']).to eq('holdout_1') |
| 1259 | + |
| 1260 | + specific_holdout = holdouts.find { |h| h['key'] == 'specific_holdout' } |
| 1261 | + expect(specific_holdout).not_to be_nil |
| 1262 | + expect(specific_holdout['id']).to eq('holdout_2') |
| 1263 | + end |
| 1264 | + |
| 1265 | + it 'should not return global holdouts that exclude the flag' do |
| 1266 | + holdouts = config_with_holdouts.get_holdouts_for_flag('boolean_single_variable_feature') |
| 1267 | + expect(holdouts.length).to eq(0) |
| 1268 | + |
| 1269 | + global_holdout = holdouts.find { |h| h['key'] == 'global_holdout' } |
| 1270 | + expect(global_holdout).to be_nil |
| 1271 | + end |
| 1272 | + |
| 1273 | + it 'should cache results for subsequent calls' do |
| 1274 | + holdouts1 = config_with_holdouts.get_holdouts_for_flag('multi_variate_feature') |
| 1275 | + holdouts2 = config_with_holdouts.get_holdouts_for_flag('multi_variate_feature') |
| 1276 | + expect(holdouts1).to equal(holdouts2) |
| 1277 | + expect(holdouts1.length).to eq(2) |
| 1278 | + end |
| 1279 | + |
| 1280 | + it 'should return only global holdouts for flags not specifically targeted' do |
| 1281 | + holdouts = config_with_holdouts.get_holdouts_for_flag('string_single_variable_feature') |
| 1282 | + |
| 1283 | + # Should only include global holdout (not excluded and no specific targeting) |
| 1284 | + expect(holdouts.length).to eq(1) |
| 1285 | + expect(holdouts.first['key']).to eq('global_holdout') |
| 1286 | + end |
| 1287 | + end |
| 1288 | + |
| 1289 | + describe '#get_holdout' do |
| 1290 | + let(:config_with_holdouts) do |
| 1291 | + Optimizely::DatafileProjectConfig.new( |
| 1292 | + OptimizelySpec::CONFIG_BODY_WITH_HOLDOUTS_JSON, |
| 1293 | + logger, |
| 1294 | + error_handler |
| 1295 | + ) |
| 1296 | + end |
| 1297 | + |
| 1298 | + it 'should return holdout when valid ID is provided' do |
| 1299 | + holdout = config_with_holdouts.get_holdout('holdout_1') |
| 1300 | + expect(holdout).not_to be_nil |
| 1301 | + expect(holdout['id']).to eq('holdout_1') |
| 1302 | + expect(holdout['key']).to eq('global_holdout') |
| 1303 | + expect(holdout['status']).to eq('Running') |
| 1304 | + end |
| 1305 | + |
| 1306 | + it 'should return holdout regardless of status when valid ID is provided' do |
| 1307 | + holdout = config_with_holdouts.get_holdout('holdout_2') |
| 1308 | + expect(holdout).not_to be_nil |
| 1309 | + expect(holdout['id']).to eq('holdout_2') |
| 1310 | + expect(holdout['key']).to eq('specific_holdout') |
| 1311 | + expect(holdout['status']).to eq('Running') |
| 1312 | + end |
| 1313 | + |
| 1314 | + it 'should return nil for non-existent holdout ID' do |
| 1315 | + holdout = config_with_holdouts.get_holdout('non_existent_holdout') |
| 1316 | + expect(holdout).to be_nil |
| 1317 | + end |
| 1318 | + end |
| 1319 | + |
| 1320 | + describe '#get_holdout with logging' do |
| 1321 | + let(:spy_logger) { spy('logger') } |
| 1322 | + let(:config_with_holdouts) do |
| 1323 | + config_body_with_holdouts = config_body.dup |
| 1324 | + config_body_with_holdouts['holdouts'] = [ |
| 1325 | + { |
| 1326 | + 'id' => 'holdout_1', |
| 1327 | + 'key' => 'test_holdout', |
| 1328 | + 'status' => 'Running', |
| 1329 | + 'includedFlags' => [], |
| 1330 | + 'excludedFlags' => [] |
| 1331 | + } |
| 1332 | + ] |
| 1333 | + config_json = JSON.dump(config_body_with_holdouts) |
| 1334 | + Optimizely::DatafileProjectConfig.new(config_json, spy_logger, error_handler) |
| 1335 | + end |
| 1336 | + |
| 1337 | + it 'should log error when holdout is not found' do |
| 1338 | + result = config_with_holdouts.get_holdout('invalid_holdout_id') |
| 1339 | + |
| 1340 | + expect(result).to be_nil |
| 1341 | + expect(spy_logger).to have_received(:log).with( |
| 1342 | + Logger::ERROR, |
| 1343 | + "Holdout with ID 'invalid_holdout_id' not found." |
| 1344 | + ) |
| 1345 | + end |
| 1346 | + |
| 1347 | + it 'should not log when holdout is found' do |
| 1348 | + result = config_with_holdouts.get_holdout('holdout_1') |
| 1349 | + |
| 1350 | + expect(result).not_to be_nil |
| 1351 | + expect(spy_logger).not_to have_received(:log).with( |
| 1352 | + Logger::ERROR, |
| 1353 | + anything |
| 1354 | + ) |
| 1355 | + end |
| 1356 | + end |
| 1357 | + |
| 1358 | + describe 'holdout initialization' do |
| 1359 | + let(:config_with_complex_holdouts) do |
| 1360 | + config_body_with_holdouts = config_body.dup |
| 1361 | + |
| 1362 | + # Use the correct feature flag IDs from the debug output |
| 1363 | + boolean_feature_id = '155554' |
| 1364 | + multi_variate_feature_id = '155559' |
| 1365 | + empty_feature_id = '594032' |
| 1366 | + string_feature_id = '594060' |
| 1367 | + |
| 1368 | + config_body_with_holdouts['holdouts'] = [ |
| 1369 | + { |
| 1370 | + 'id' => 'global_holdout', |
| 1371 | + 'key' => 'global', |
| 1372 | + 'status' => 'Running', |
| 1373 | + 'includedFlags' => [], |
| 1374 | + 'excludedFlags' => [boolean_feature_id, string_feature_id] |
| 1375 | + }, |
| 1376 | + { |
| 1377 | + 'id' => 'specific_holdout', |
| 1378 | + 'key' => 'specific', |
| 1379 | + 'status' => 'Running', |
| 1380 | + 'includedFlags' => [multi_variate_feature_id, empty_feature_id], |
| 1381 | + 'excludedFlags' => [] |
| 1382 | + }, |
| 1383 | + { |
| 1384 | + 'id' => 'inactive_holdout', |
| 1385 | + 'key' => 'inactive', |
| 1386 | + 'status' => 'Inactive', |
| 1387 | + 'includedFlags' => [boolean_feature_id], |
| 1388 | + 'excludedFlags' => [] |
| 1389 | + } |
| 1390 | + ] |
| 1391 | + config_json = JSON.dump(config_body_with_holdouts) |
| 1392 | + Optimizely::DatafileProjectConfig.new(config_json, logger, error_handler) |
| 1393 | + end |
| 1394 | + |
| 1395 | + it 'should properly categorize holdouts during initialization' do |
| 1396 | + expect(config_with_complex_holdouts.holdout_id_map.keys).to contain_exactly('global_holdout', 'specific_holdout') |
| 1397 | + expect(config_with_complex_holdouts.global_holdouts.keys).to contain_exactly('global_holdout') |
| 1398 | + |
| 1399 | + # Use the correct feature flag IDs |
| 1400 | + boolean_feature_id = '155554' |
| 1401 | + multi_variate_feature_id = '155559' |
| 1402 | + empty_feature_id = '594032' |
| 1403 | + string_feature_id = '594060' |
| 1404 | + |
| 1405 | + expect(config_with_complex_holdouts.included_holdouts[multi_variate_feature_id]).not_to be_nil |
| 1406 | + expect(config_with_complex_holdouts.included_holdouts[multi_variate_feature_id]).not_to be_empty |
| 1407 | + expect(config_with_complex_holdouts.included_holdouts[empty_feature_id]).not_to be_nil |
| 1408 | + expect(config_with_complex_holdouts.included_holdouts[empty_feature_id]).not_to be_empty |
| 1409 | + expect(config_with_complex_holdouts.included_holdouts[boolean_feature_id]).to be_nil |
| 1410 | + |
| 1411 | + expect(config_with_complex_holdouts.excluded_holdouts[boolean_feature_id]).not_to be_nil |
| 1412 | + expect(config_with_complex_holdouts.excluded_holdouts[boolean_feature_id]).not_to be_empty |
| 1413 | + expect(config_with_complex_holdouts.excluded_holdouts[string_feature_id]).not_to be_nil |
| 1414 | + expect(config_with_complex_holdouts.excluded_holdouts[string_feature_id]).not_to be_empty |
| 1415 | + end |
| 1416 | + |
| 1417 | + it 'should only process running holdouts during initialization' do |
| 1418 | + expect(config_with_complex_holdouts.holdout_id_map['inactive_holdout']).to be_nil |
| 1419 | + expect(config_with_complex_holdouts.global_holdouts['inactive_holdout']).to be_nil |
| 1420 | + |
| 1421 | + boolean_feature_id = '155554' |
| 1422 | + included_for_boolean = config_with_complex_holdouts.included_holdouts[boolean_feature_id] |
| 1423 | + expect(included_for_boolean).to be_nil |
| 1424 | + end |
| 1425 | + end |
1237 | 1426 | end
|
0 commit comments