-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(OptimizelyConfig): Add new fields to OptimizelyConfig #266
Conversation
var experimentMap = GetExperimentsMap(projectConfig); | ||
var featureMap = GetFeaturesMap(projectConfig, experimentMap); | ||
OptimizelyConfig = new OptimizelyConfig(projectConfig.Revision, | ||
projectConfig.SDKKey, | ||
projectConfig.EnvironmentKey, | ||
attributes, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
won't this break existing constructor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No actually attributes sdkKey and env key are all in the new constructor.
|
||
private Audience[] GetAudiences(ProjectConfig projectConfig) | ||
{ | ||
var audiencesArr = Array.FindAll(projectConfig.Audiences, aud => !aud.Id.Equals("$opt_dummy_audience")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
am just thinking, can't we avoid this condition? may be we should remove somewhere else.
var featureId = projectConfig.GetExperimentFeatureList(experimentId)?.FirstOrDefault(); | ||
var featureIdVariablesMap = GetFeatureIdVariablesMap(projectConfig); | ||
var variablesMap = new Dictionary<string, OptimizelyVariable>(); | ||
string featureIdRollout = null; | ||
if (rolloutId != null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lets discuss offline, need to discuss this logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you add rolloutId checking since "GetExperimentFeatureList" returns a map for experiment-to-feature map not for delivery-rule-to-feature map. What about extend "GetExperimentFeatureList" or similar to cover delivery-rules as well and removing "rolloutId" passing around.
if (item is JArray) | ||
{ | ||
subAudience = GetSerializedAudiences(((JArray)item).ToObject<List<object>>(), audienceIdMap); | ||
subAudience = "(" + subAudience + ")"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use StringBuilder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use append where you are concatenating strings.
OptimizelySDK.Tests/OptimizelyConfigTests/OptimizelyConfigTest.cs
Outdated
Show resolved
Hide resolved
public IDictionary<string, OptimizelyExperiment> ExperimentsMap { get; private set; } | ||
public IDictionary<string, OptimizelyFeature> FeaturesMap { get; private set; } | ||
|
||
private string _datafile; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we have auto formatted code, we won't have to make these kinds of fixes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few changes and more tests suggested
public Entity.Event[] Events { get; private set; } | ||
public OptimizelyAudience[] Audiences { get; private set; } | ||
public Attribute[] Attributes { get; private set; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't we add new public types OptimzelyEvent and OptimizelyAttribute? I understand content-wise they currently look identical, but those are types that we'll open to our customers.
OptimizelySDK.Tests/OptimizelyConfigTests/OptimizelyConfigTest.cs
Outdated
Show resolved
Hide resolved
{ | ||
Revision = revision; | ||
SDKKey = sdkKey; | ||
Attributes = attributes; | ||
Audiences = audiences; | ||
Events = events; | ||
EnvironmentKey = environmentKey; | ||
ExperimentsMap = experimentsMap; | ||
FeaturesMap = featuresMap; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to have these multiple constructors? This is for creating OptimizelyConfig internally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are publicly exposed classes, that's why we added another constructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's expected that clients use OptimizelyConfig object, not building it. Consider not exposing constructor to public if can be controlled.
var featureId = projectConfig.GetExperimentFeatureList(experimentId)?.FirstOrDefault(); | ||
var featureIdVariablesMap = GetFeatureIdVariablesMap(projectConfig); | ||
var variablesMap = new Dictionary<string, OptimizelyVariable>(); | ||
string featureIdRollout = null; | ||
if (rolloutId != null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you add rolloutId checking since "GetExperimentFeatureList" returns a map for experiment-to-feature map not for delivery-rule-to-feature map. What about extend "GetExperimentFeatureList" or similar to cover delivery-rules as well and removing "rolloutId" passing around.
|
||
featureId = featureId ?? featureIdRollout; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is to cover features which are mapped to delivery-rules. See my comments above.
@@ -189,6 +125,7 @@ public void TestGetOptimizelyConfigService() | |||
"audience_combinations_experiment", new OptimizelyExperiment ( | |||
id: "1323241598", | |||
key:"audience_combinations_experiment", | |||
audiences: "(\"exactString\" OR \"substringString\") AND (\"exists\" OR \"exactNumber\" OR \"gtNumber\" OR \"ltNumber\" OR \"exactBoolean\")", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add separate test cases to cover 13 cases for audience serialization in TDD?
new OptimizelyAudience("3468206647", "gtNumber", new object[] { "and", new object[] { "or", new object[] { "or", new Dictionary<string, object>() { { "name", "lasers" }, { "type", "custom_attribute" }, { "match", "gt" }, { "value", 70 } } } } }), | ||
new OptimizelyAudience("3468206644", "ltNumber", new object[] { "and", new object[] { "or", new object[] { "or", new Dictionary<string, object>() { { "name", "lasers" }, { "type", "custom_attribute" }, { "match", "lt" }, { "value", 1.0 } } } } }), | ||
new OptimizelyAudience("3468206643", "exactBoolean", new object[] { "and", new object[] { "or", new object[] { "or", new Dictionary<string, object>() { { "name", "should_do_it" }, { "type", "custom_attribute" }, { "match", "exact" }, { "value", true } } } } }), | ||
new OptimizelyAudience("3468206648", "notExist", new object[] { "not", new Dictionary<string, object>() { { "name", "input_value" }, { "type", "custom_attribute" }, { "match", "exists" } } }), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also need validate "$opt_dummy_audience" audience is filtered out. See TDD.
new OptimizelyAudience("3468206644", "$$dummyLtNumber", "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}"), | ||
new OptimizelyAudience("3468206643", "$$dummyExactBoolean", "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}"), | ||
new OptimizelyAudience("0", "$$dummy", "{\"type\": \"custom_attribute\", \"name\": \"$opt_dummy_attribute\", \"value\": \"impossible_value\"}"), | ||
new OptimizelyAudience("3988293898", "substringString", new object[] { "and", new object[] { "or", new object[] { "or", new Dictionary<string, string>() { { "name", "house" }, { "type", "custom_attribute" }, { "match", "substring" }, { "value", "Slytherin" } } } } }), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we modify tests to validate that typedAudiences and audiences filter out same "names"?
{ | ||
cond = string.IsNullOrEmpty(cond) ? "OR" : cond; | ||
sAudience = string.IsNullOrEmpty(sAudience.ToString()) ? new StringBuilder(cond + " \"" + audienceIdMap[itemStr]?.Name + "\"") : | ||
sAudience.Append(" " + cond + " \"" + audienceIdMap[itemStr]?.Name + "\""); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
append
} | ||
else | ||
{ | ||
sAudience = new StringBuilder("\"" + audienceIdMap[itemStr]?.Name + "\""); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
append
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
or use .format or use interpolation string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. Suggested to add 2 more test cases for audience serialization.
new List<object>() { "and", new JArray() { "or", "3468206642", "3988293898" }, "3468206646" }, | ||
new List<object>() { "and", new JArray() { "or", "3468206642", new JArray() { "and", "3988293898", "3468206646" } }, new JArray() { "and", "3988293899", new JArray() { "or", "3468206647", "3468206643" } } }, | ||
new List<object>() { "and", "and" }, | ||
new List<object>() { "not", new JArray() { "and", "3468206642", "3988293898" } } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add 2 more cases from TDD:
- empty audiences []
- not match id: ["or", "1", "999999999"]
Serialized condition of typedAudience for Optimizelyconfig if key of audience does not exist in map then use the given id as it is. Added unit test of audience as empty and audienceId does not exist
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Summary
The following new public properties are added to OptimizelyConfig:
Test plan
All FSC tests OPTIMIZELY_CONFIG_V2 tests should pass.
FSC OptimizelyConfig link