From 5a8f3075051323c85cf7ebba9dc5fb5966885d7e Mon Sep 17 00:00:00 2001 From: FarhanAnjum-opti Date: Fri, 3 Apr 2026 21:30:40 +0600 Subject: [PATCH] [AI-FSSDK] [FSSDK-12418] Remove experiment type validation from config parsing --- .../parser/DatafileGsonDeserializer.java | 22 ----------------- .../parser/DatafileJacksonDeserializer.java | 22 ----------------- .../ab/config/parser/JsonConfigParser.java | 24 ------------------- .../config/parser/JsonSimpleConfigParser.java | 24 ------------------- .../ab/config/FeatureRolloutConfigTest.java | 17 ++++++++++++- .../config/feature-rollout-config.json | 22 +++++++++++++++++ 6 files changed, 38 insertions(+), 93 deletions(-) diff --git a/core-api/src/main/java/com/optimizely/ab/config/parser/DatafileGsonDeserializer.java b/core-api/src/main/java/com/optimizely/ab/config/parser/DatafileGsonDeserializer.java index 767fe428b..12ad20808 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/parser/DatafileGsonDeserializer.java +++ b/core-api/src/main/java/com/optimizely/ab/config/parser/DatafileGsonDeserializer.java @@ -126,28 +126,6 @@ public ProjectConfig deserialize(JsonElement json, Type typeOfT, JsonDeserializa region = jsonObject.get("region").getAsString(); } - // Validate experiment types - Set validExperimentTypes = new HashSet<>(Arrays.asList( - Experiment.TYPE_AB, Experiment.TYPE_MAB, Experiment.TYPE_CMAB, - Experiment.TYPE_TD, Experiment.TYPE_FR - )); - for (Experiment experiment : experiments) { - if (experiment.getType() != null && !validExperimentTypes.contains(experiment.getType())) { - throw new JsonParseException( - String.format("Experiment \"%s\" has invalid type \"%s\". Valid types: %s.", - experiment.getKey(), experiment.getType(), validExperimentTypes)); - } - } - for (Group group : groups) { - for (Experiment experiment : group.getExperiments()) { - if (experiment.getType() != null && !validExperimentTypes.contains(experiment.getType())) { - throw new JsonParseException( - String.format("Experiment \"%s\" has invalid type \"%s\". Valid types: %s.", - experiment.getKey(), experiment.getType(), validExperimentTypes)); - } - } - } - return new DatafileProjectConfig( accountId, anonymizeIP, diff --git a/core-api/src/main/java/com/optimizely/ab/config/parser/DatafileJacksonDeserializer.java b/core-api/src/main/java/com/optimizely/ab/config/parser/DatafileJacksonDeserializer.java index 4cdbbb483..5c94a444f 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/parser/DatafileJacksonDeserializer.java +++ b/core-api/src/main/java/com/optimizely/ab/config/parser/DatafileJacksonDeserializer.java @@ -100,28 +100,6 @@ public DatafileProjectConfig deserialize(JsonParser parser, DeserializationConte region = node.get("region").textValue(); } - // Validate experiment types - Set validExperimentTypes = new HashSet<>(Arrays.asList( - Experiment.TYPE_AB, Experiment.TYPE_MAB, Experiment.TYPE_CMAB, - Experiment.TYPE_TD, Experiment.TYPE_FR - )); - for (Experiment experiment : experiments) { - if (experiment.getType() != null && !validExperimentTypes.contains(experiment.getType())) { - throw new IOException( - String.format("Experiment \"%s\" has invalid type \"%s\". Valid types: %s.", - experiment.getKey(), experiment.getType(), validExperimentTypes)); - } - } - for (Group group : groups) { - for (Experiment experiment : group.getExperiments()) { - if (experiment.getType() != null && !validExperimentTypes.contains(experiment.getType())) { - throw new IOException( - String.format("Experiment \"%s\" has invalid type \"%s\". Valid types: %s.", - experiment.getKey(), experiment.getType(), validExperimentTypes)); - } - } - } - return new DatafileProjectConfig( accountId, anonymizeIP, diff --git a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java index 96a5d1c58..8d2c005b5 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java +++ b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonConfigParser.java @@ -105,28 +105,6 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse String regionString = rootObject.getString("region"); } - // Validate experiment types - Set validExperimentTypes = new HashSet<>(Arrays.asList( - Experiment.TYPE_AB, Experiment.TYPE_MAB, Experiment.TYPE_CMAB, - Experiment.TYPE_TD, Experiment.TYPE_FR - )); - for (Experiment experiment : experiments) { - if (experiment.getType() != null && !validExperimentTypes.contains(experiment.getType())) { - throw new ConfigParseException( - String.format("Experiment \"%s\" has invalid type \"%s\". Valid types: %s.", - experiment.getKey(), experiment.getType(), validExperimentTypes)); - } - } - for (Group group : groups) { - for (Experiment experiment : group.getExperiments()) { - if (experiment.getType() != null && !validExperimentTypes.contains(experiment.getType())) { - throw new ConfigParseException( - String.format("Experiment \"%s\" has invalid type \"%s\". Valid types: %s.", - experiment.getKey(), experiment.getType(), validExperimentTypes)); - } - } - } - return new DatafileProjectConfig( accountId, anonymizeIP, @@ -149,8 +127,6 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse rollouts, integrations ); - } catch (ConfigParseException e) { - throw e; } catch (RuntimeException e) { throw new ConfigParseException("Unable to parse datafile: " + json, e); } catch (Exception e) { diff --git a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java index 2fda0344a..2accb9813 100644 --- a/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java +++ b/core-api/src/main/java/com/optimizely/ab/config/parser/JsonSimpleConfigParser.java @@ -108,28 +108,6 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse String regionString = (String) rootObject.get("region"); } - // Validate experiment types - Set validExperimentTypes = new HashSet<>(Arrays.asList( - Experiment.TYPE_AB, Experiment.TYPE_MAB, Experiment.TYPE_CMAB, - Experiment.TYPE_TD, Experiment.TYPE_FR - )); - for (Experiment experiment : experiments) { - if (experiment.getType() != null && !validExperimentTypes.contains(experiment.getType())) { - throw new ConfigParseException( - String.format("Experiment \"%s\" has invalid type \"%s\". Valid types: %s.", - experiment.getKey(), experiment.getType(), validExperimentTypes)); - } - } - for (Group group : groups) { - for (Experiment experiment : group.getExperiments()) { - if (experiment.getType() != null && !validExperimentTypes.contains(experiment.getType())) { - throw new ConfigParseException( - String.format("Experiment \"%s\" has invalid type \"%s\". Valid types: %s.", - experiment.getKey(), experiment.getType(), validExperimentTypes)); - } - } - } - return new DatafileProjectConfig( accountId, anonymizeIP, @@ -152,8 +130,6 @@ public ProjectConfig parseProjectConfig(@Nonnull String json) throws ConfigParse rollouts, integrations ); - } catch (ConfigParseException e) { - throw e; } catch (RuntimeException ex) { throw new ConfigParseException("Unable to parse datafile: " + json, ex); } catch (Exception e) { diff --git a/core-api/src/test/java/com/optimizely/ab/config/FeatureRolloutConfigTest.java b/core-api/src/test/java/com/optimizely/ab/config/FeatureRolloutConfigTest.java index fbbda6410..1cc124c4d 100644 --- a/core-api/src/test/java/com/optimizely/ab/config/FeatureRolloutConfigTest.java +++ b/core-api/src/test/java/com/optimizely/ab/config/FeatureRolloutConfigTest.java @@ -135,7 +135,22 @@ public void featureRolloutWithEmptyRolloutIdDoesNotCrash() { } /** - * Test 6: Type field parsed - experiments with type field in the datafile + * Test 6: Unknown type accepted - experiment with type "new_unknown_type" + * does NOT cause error or rejection, and config parsing succeeds. + */ + @Test + public void unknownExperimentTypeAccepted() { + Experiment experiment = projectConfig.getExperimentKeyMapping().get("unknown_type_experiment"); + assertNotNull("Experiment with unknown type should be parsed successfully", experiment); + assertEquals("new_unknown_type", experiment.getType()); + assertEquals("exp_unknown_type", experiment.getId()); + assertEquals("unknown_type_experiment", experiment.getKey()); + assertEquals(1, experiment.getVariations().size()); + assertEquals("unknown_variation", experiment.getVariations().get(0).getKey()); + } + + /** + * Test 7: Type field parsed - experiments with type field in the datafile * have the value correctly preserved after config parsing. */ @Test diff --git a/core-api/src/test/resources/config/feature-rollout-config.json b/core-api/src/test/resources/config/feature-rollout-config.json index bbe396516..0489e4950 100644 --- a/core-api/src/test/resources/config/feature-rollout-config.json +++ b/core-api/src/test/resources/config/feature-rollout-config.json @@ -110,6 +110,28 @@ "endOfRange": 5000 } ] + }, + { + "id": "exp_unknown_type", + "key": "unknown_type_experiment", + "status": "Running", + "layerId": "layer_5", + "audienceIds": [], + "forcedVariations": {}, + "type": "new_unknown_type", + "variations": [ + { + "id": "var_unknown_1", + "key": "unknown_variation", + "featureEnabled": true + } + ], + "trafficAllocation": [ + { + "entityId": "var_unknown_1", + "endOfRange": 10000 + } + ] } ], "featureFlags": [