From 6694dde46dcdb59bd7c36ec1cc172a3276b95ae0 Mon Sep 17 00:00:00 2001 From: Yasir Ali Date: Mon, 11 May 2020 15:57:26 +0500 Subject: [PATCH 1/7] Updates for agent support. --- pkg/client/client.go | 65 +++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/pkg/client/client.go b/pkg/client/client.go index 75dbc1f75..2b143488f 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -422,37 +422,9 @@ func (o *OptimizelyClient) GetAllFeatureVariablesWithDecision(featureKey string, errs := new(multierror.Error) for _, v := range feature.VariableMap { - val := v.DefaultValue - - if enabled { - if variable, ok := featureDecision.Variation.Variables[v.ID]; ok { - val = variable.Value - } - } - - var out interface{} - out = val - switch varType := v.Type; varType { - case entities.Boolean: - out, err = strconv.ParseBool(val) - errs = multierror.Append(errs, err) - case entities.Double: - out, err = strconv.ParseFloat(val, 64) - errs = multierror.Append(errs, err) - case entities.Integer: - out, err = strconv.Atoi(val) - errs = multierror.Append(errs, err) - case entities.JSON: - var optlyJSON *optimizelyjson.OptimizelyJSON - optlyJSON, err = optimizelyjson.NewOptimizelyJSONfromString(val) - out = optlyJSON.ToMap() - errs = multierror.Append(errs, err) - case entities.String: - default: - o.logger.Warning(fmt.Sprintf(`type "%s" is unknown, returning string`, varType)) - } - - variableMap[v.Key] = out + value, err := o.GetTypedFeatureVariableValue(enabled, featureDecision, v) + errs = multierror.Append(errs, err) + variableMap[v.Key] = value } if o.notificationCenter != nil { @@ -467,6 +439,37 @@ func (o *OptimizelyClient) GetAllFeatureVariablesWithDecision(featureKey string, return enabled, variableMap, errs.ErrorOrNil() } +// GetTypedFeatureVariableValue returns type converted value for feature variable. +func (o *OptimizelyClient) GetTypedFeatureVariableValue(enabled bool, featureDecision decision.FeatureDecision, v entities.Variable) (value interface{}, err error) { + val := v.DefaultValue + + if enabled { + if variable, ok := featureDecision.Variation.Variables[v.ID]; ok { + val = variable.Value + } + } + + var out interface{} + out = val + switch varType := v.Type; varType { + case entities.Boolean: + out, err = strconv.ParseBool(val) + case entities.Double: + out, err = strconv.ParseFloat(val, 64) + case entities.Integer: + out, err = strconv.Atoi(val) + case entities.JSON: + var optlyJSON *optimizelyjson.OptimizelyJSON + optlyJSON, err = optimizelyjson.NewOptimizelyJSONfromString(val) + out = optlyJSON.ToMap() + case entities.String: + default: + o.logger.Warning(fmt.Sprintf(`type "%s" is unknown, returning string`, varType)) + } + + return out, err +} + // GetAllFeatureVariables returns all the variables as OptimizelyJSON object for a given feature. func (o *OptimizelyClient) GetAllFeatureVariables(featureKey string, userContext entities.UserContext) (optlyJSON *optimizelyjson.OptimizelyJSON, err error) { _, variableMap, err := o.GetAllFeatureVariablesWithDecision(featureKey, userContext) From e2da3a6eab18dc1a8b0cd89e8815887b34b2ac5b Mon Sep 17 00:00:00 2001 From: Yasir Ali Date: Mon, 11 May 2020 16:20:56 +0500 Subject: [PATCH 2/7] nit fixed. --- pkg/client/client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/client/client.go b/pkg/client/client.go index 2b143488f..a316c0b81 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -422,8 +422,8 @@ func (o *OptimizelyClient) GetAllFeatureVariablesWithDecision(featureKey string, errs := new(multierror.Error) for _, v := range feature.VariableMap { - value, err := o.GetTypedFeatureVariableValue(enabled, featureDecision, v) - errs = multierror.Append(errs, err) + value, e := o.GetTypedFeatureVariableValue(enabled, featureDecision, v) + errs = multierror.Append(errs, e) variableMap[v.Key] = value } From 9783bbf7351bdf05260a59bebf5c010f91d7c91e Mon Sep 17 00:00:00 2001 From: Yasir Ali Date: Tue, 12 May 2020 14:32:40 +0500 Subject: [PATCH 3/7] logic updated. --- pkg/client/client.go | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/pkg/client/client.go b/pkg/client/client.go index a316c0b81..5121414e7 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -422,9 +422,17 @@ func (o *OptimizelyClient) GetAllFeatureVariablesWithDecision(featureKey string, errs := new(multierror.Error) for _, v := range feature.VariableMap { - value, e := o.GetTypedFeatureVariableValue(enabled, featureDecision, v) - errs = multierror.Append(errs, e) - variableMap[v.Key] = value + val := v.DefaultValue + if enabled { + if variable, ok := featureDecision.Variation.Variables[v.ID]; ok { + val = variable.Value + } + } + + var out interface{} + out, err = o.GetTypedFeatureVariableValue(val, v) + errs = multierror.Append(errs, err) + variableMap[v.Key] = out } if o.notificationCenter != nil { @@ -440,18 +448,10 @@ func (o *OptimizelyClient) GetAllFeatureVariablesWithDecision(featureKey string, } // GetTypedFeatureVariableValue returns type converted value for feature variable. -func (o *OptimizelyClient) GetTypedFeatureVariableValue(enabled bool, featureDecision decision.FeatureDecision, v entities.Variable) (value interface{}, err error) { - val := v.DefaultValue - - if enabled { - if variable, ok := featureDecision.Variation.Variables[v.ID]; ok { - val = variable.Value - } - } - +func (o *OptimizelyClient) GetTypedFeatureVariableValue(val string, variable entities.Variable) (value interface{}, err error) { var out interface{} out = val - switch varType := v.Type; varType { + switch varType := variable.Type; varType { case entities.Boolean: out, err = strconv.ParseBool(val) case entities.Double: From 0c730e4db4b6f3380a31aebb522bbe765c860eba Mon Sep 17 00:00:00 2001 From: Yasir Ali Date: Tue, 12 May 2020 14:41:02 +0500 Subject: [PATCH 4/7] fixes. --- pkg/client/client.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pkg/client/client.go b/pkg/client/client.go index 5121414e7..21d35354e 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -429,10 +429,9 @@ func (o *OptimizelyClient) GetAllFeatureVariablesWithDecision(featureKey string, } } - var out interface{} - out, err = o.GetTypedFeatureVariableValue(val, v) - errs = multierror.Append(errs, err) - variableMap[v.Key] = out + value, e := o.GetTypedFeatureVariableValue(val, v) + errs = multierror.Append(errs, e) + variableMap[v.Key] = value } if o.notificationCenter != nil { From d00f2c41a14391ac894c50bac93dd09d960e4172 Mon Sep 17 00:00:00 2001 From: Yasir Ali Date: Fri, 15 May 2020 14:32:47 +0500 Subject: [PATCH 5/7] Fixes. --- pkg/client/client.go | 73 ++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/pkg/client/client.go b/pkg/client/client.go index 21d35354e..20af9b48b 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -399,24 +399,27 @@ func (o *OptimizelyClient) GetFeatureVariable(featureKey, variableKey string, us return stringValue, variableType, err } -// GetAllFeatureVariablesWithDecision returns all the variables for a given feature along with the enabled state. -func (o *OptimizelyClient) GetAllFeatureVariablesWithDecision(featureKey string, userContext entities.UserContext) (enabled bool, variableMap map[string]interface{}, err error) { +// GetAllFeatureVariablesWithDecisionAndTracking returns all the variables for a given feature along with the enabled state +// and triggers impression event if disableTracking is false. +func (o *OptimizelyClient) GetAllFeatureVariablesWithDecisionAndTracking(featureKey string, userContext entities.UserContext, disableTracking bool) (experimentKey, variationKey string, enabled bool, variableMap map[string]interface{}, err error) { variableMap = make(map[string]interface{}) decisionContext, featureDecision, err := o.getFeatureDecision(featureKey, "", userContext) if err != nil { o.logger.Error("Optimizely SDK tracking error", err) - return enabled, variableMap, err + return experimentKey, variationKey, enabled, variableMap, err } if featureDecision.Variation != nil { enabled = featureDecision.Variation.FeatureEnabled + experimentKey = featureDecision.Experiment.Key + variationKey = featureDecision.Variation.Key } feature := decisionContext.Feature if feature == nil { o.logger.Warning(fmt.Sprintf(`feature "%s" does not exist`, featureKey)) - return enabled, variableMap, nil + return experimentKey, variationKey, enabled, variableMap, nil } errs := new(multierror.Error) @@ -429,9 +432,29 @@ func (o *OptimizelyClient) GetAllFeatureVariablesWithDecision(featureKey string, } } - value, e := o.GetTypedFeatureVariableValue(val, v) - errs = multierror.Append(errs, e) - variableMap[v.Key] = value + var out interface{} + out = val + switch varType := v.Type; varType { + case entities.Boolean: + out, err = strconv.ParseBool(val) + errs = multierror.Append(errs, err) + case entities.Double: + out, err = strconv.ParseFloat(val, 64) + errs = multierror.Append(errs, err) + case entities.Integer: + out, err = strconv.Atoi(val) + errs = multierror.Append(errs, err) + case entities.JSON: + var optlyJSON *optimizelyjson.OptimizelyJSON + optlyJSON, err = optimizelyjson.NewOptimizelyJSONfromString(val) + out = optlyJSON.ToMap() + errs = multierror.Append(errs, err) + case entities.String: + default: + o.logger.Warning(fmt.Sprintf(`type "%s" is unknown, returning string`, varType)) + } + + variableMap[v.Key] = out } if o.notificationCenter != nil { @@ -443,30 +466,22 @@ func (o *OptimizelyClient) GetAllFeatureVariablesWithDecision(featureKey string, o.logger.Warning("Problem with sending notification") } } - return enabled, variableMap, errs.ErrorOrNil() + + err = errs.ErrorOrNil() + if err == nil { + if featureDecision.Source == decision.FeatureTest && !disableTracking { + // send impression event for feature tests + impressionEvent := event.CreateImpressionUserEvent(decisionContext.ProjectConfig, featureDecision.Experiment, *featureDecision.Variation, userContext) + o.EventProcessor.ProcessEvent(impressionEvent) + } + } + return experimentKey, variationKey, enabled, variableMap, err } -// GetTypedFeatureVariableValue returns type converted value for feature variable. -func (o *OptimizelyClient) GetTypedFeatureVariableValue(val string, variable entities.Variable) (value interface{}, err error) { - var out interface{} - out = val - switch varType := variable.Type; varType { - case entities.Boolean: - out, err = strconv.ParseBool(val) - case entities.Double: - out, err = strconv.ParseFloat(val, 64) - case entities.Integer: - out, err = strconv.Atoi(val) - case entities.JSON: - var optlyJSON *optimizelyjson.OptimizelyJSON - optlyJSON, err = optimizelyjson.NewOptimizelyJSONfromString(val) - out = optlyJSON.ToMap() - case entities.String: - default: - o.logger.Warning(fmt.Sprintf(`type "%s" is unknown, returning string`, varType)) - } - - return out, err +// GetAllFeatureVariablesWithDecision returns all the variables for a given feature along with the enabled state. +func (o *OptimizelyClient) GetAllFeatureVariablesWithDecision(featureKey string, userContext entities.UserContext) (enabled bool, variableMap map[string]interface{}, err error) { + _, _, enabled, variableMap, err = o.GetAllFeatureVariablesWithDecisionAndTracking(featureKey, userContext, true) + return enabled, variableMap, err } // GetAllFeatureVariables returns all the variables as OptimizelyJSON object for a given feature. From 5942f760bd8cd744a8372f5365763ce0757770bc Mon Sep 17 00:00:00 2001 From: Yasir Ali Date: Fri, 15 May 2020 14:45:17 +0500 Subject: [PATCH 6/7] fixing cyclomatic complexity. --- pkg/client/client.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pkg/client/client.go b/pkg/client/client.go index 20af9b48b..2e7aad699 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -468,12 +468,10 @@ func (o *OptimizelyClient) GetAllFeatureVariablesWithDecisionAndTracking(feature } err = errs.ErrorOrNil() - if err == nil { - if featureDecision.Source == decision.FeatureTest && !disableTracking { - // send impression event for feature tests - impressionEvent := event.CreateImpressionUserEvent(decisionContext.ProjectConfig, featureDecision.Experiment, *featureDecision.Variation, userContext) - o.EventProcessor.ProcessEvent(impressionEvent) - } + if err == nil && featureDecision.Source == decision.FeatureTest && !disableTracking { + // send impression event for feature tests + impressionEvent := event.CreateImpressionUserEvent(decisionContext.ProjectConfig, featureDecision.Experiment, *featureDecision.Variation, userContext) + o.EventProcessor.ProcessEvent(impressionEvent) } return experimentKey, variationKey, enabled, variableMap, err } From bfcdb0f9a79c807b21b2f385efe2d53a1da272d2 Mon Sep 17 00:00:00 2001 From: Yasir Ali Date: Fri, 15 May 2020 15:00:17 +0500 Subject: [PATCH 7/7] reducing cyclomatic complexity. --- pkg/client/client.go | 45 ++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/pkg/client/client.go b/pkg/client/client.go index 2e7aad699..8cda5dd42 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -432,28 +432,9 @@ func (o *OptimizelyClient) GetAllFeatureVariablesWithDecisionAndTracking(feature } } - var out interface{} - out = val - switch varType := v.Type; varType { - case entities.Boolean: - out, err = strconv.ParseBool(val) - errs = multierror.Append(errs, err) - case entities.Double: - out, err = strconv.ParseFloat(val, 64) - errs = multierror.Append(errs, err) - case entities.Integer: - out, err = strconv.Atoi(val) - errs = multierror.Append(errs, err) - case entities.JSON: - var optlyJSON *optimizelyjson.OptimizelyJSON - optlyJSON, err = optimizelyjson.NewOptimizelyJSONfromString(val) - out = optlyJSON.ToMap() - errs = multierror.Append(errs, err) - case entities.String: - default: - o.logger.Warning(fmt.Sprintf(`type "%s" is unknown, returning string`, varType)) - } - + // Sub function to reduce cyclomatic complexity + out, e := o.getTypedVariableValue(v, val) + errs = multierror.Append(errs, e) variableMap[v.Key] = out } @@ -728,3 +709,23 @@ func (o *OptimizelyClient) Close() { func isNil(v interface{}) bool { return v == nil || (reflect.ValueOf(v).Kind() == reflect.Ptr && reflect.ValueOf(v).IsNil()) } + +func (o *OptimizelyClient) getTypedVariableValue(v entities.Variable, val string) (out interface{}, err error) { + out = val + switch varType := v.Type; varType { + case entities.Boolean: + out, err = strconv.ParseBool(val) + case entities.Double: + out, err = strconv.ParseFloat(val, 64) + case entities.Integer: + out, err = strconv.Atoi(val) + case entities.JSON: + var optlyJSON *optimizelyjson.OptimizelyJSON + optlyJSON, err = optimizelyjson.NewOptimizelyJSONfromString(val) + out = optlyJSON.ToMap() + case entities.String: + default: + o.logger.Warning(fmt.Sprintf(`type "%s" is unknown, returning string`, varType)) + } + return out, err +}