fix: missing/nil custom variables in fractional operator (#1295)
## This PR Fixes https://github.com/open-feature/flagd/issues/1285 Signed-off-by: Kavindu Dodanduwa <kavindudodanduwa@gmail.com>
This commit is contained in:
parent
281c8094ef
commit
418c5cd7c0
|
|
@ -56,6 +56,11 @@ func parseFractionalEvaluationData(values, data any) (string, []fractionalEvalua
|
||||||
if ok {
|
if ok {
|
||||||
valuesArray = valuesArray[1:]
|
valuesArray = valuesArray[1:]
|
||||||
} else {
|
} else {
|
||||||
|
// check for nil here as custom property could be nil/missing
|
||||||
|
if valuesArray[0] == nil {
|
||||||
|
valuesArray = valuesArray[1:]
|
||||||
|
}
|
||||||
|
|
||||||
targetingKey, ok := dataMap[targetingKeyKey].(string)
|
targetingKey, ok := dataMap[targetingKeyKey].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", nil, errors.New("bucketing value not supplied and no targetingKey in context")
|
return "", nil, errors.New("bucketing value not supplied and no targetingKey in context")
|
||||||
|
|
@ -78,7 +83,8 @@ func parseFractionalEvaluationDistributions(values []any) ([]fractionalEvaluatio
|
||||||
for i := 0; i < len(values); i++ {
|
for i := 0; i < len(values); i++ {
|
||||||
distributionArray, ok := values[i].([]any)
|
distributionArray, ok := values[i].([]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("distribution elements aren't of type []any")
|
return nil, errors.New("distribution elements aren't of type []any. " +
|
||||||
|
"please check your rule in flag definition")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(distributionArray) != 2 {
|
if len(distributionArray) != 2 {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import (
|
||||||
func TestFractionalEvaluation(t *testing.T) {
|
func TestFractionalEvaluation(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
flags := Flags{
|
commonFlags := Flags{
|
||||||
Flags: map[string]model.Flag{
|
Flags: map[string]model.Flag{
|
||||||
"headerColor": {
|
"headerColor": {
|
||||||
State: "ENABLED",
|
State: "ENABLED",
|
||||||
|
|
@ -95,7 +95,7 @@ func TestFractionalEvaluation(t *testing.T) {
|
||||||
expectedErrorCode string
|
expectedErrorCode string
|
||||||
}{
|
}{
|
||||||
"rachel@faas.com": {
|
"rachel@faas.com": {
|
||||||
flags: flags,
|
flags: commonFlags,
|
||||||
flagKey: "headerColor",
|
flagKey: "headerColor",
|
||||||
context: map[string]any{
|
context: map[string]any{
|
||||||
"email": "rachel@faas.com",
|
"email": "rachel@faas.com",
|
||||||
|
|
@ -105,7 +105,7 @@ func TestFractionalEvaluation(t *testing.T) {
|
||||||
expectedReason: model.TargetingMatchReason,
|
expectedReason: model.TargetingMatchReason,
|
||||||
},
|
},
|
||||||
"monica@faas.com": {
|
"monica@faas.com": {
|
||||||
flags: flags,
|
flags: commonFlags,
|
||||||
flagKey: "headerColor",
|
flagKey: "headerColor",
|
||||||
context: map[string]any{
|
context: map[string]any{
|
||||||
"email": "monica@faas.com",
|
"email": "monica@faas.com",
|
||||||
|
|
@ -115,7 +115,7 @@ func TestFractionalEvaluation(t *testing.T) {
|
||||||
expectedReason: model.TargetingMatchReason,
|
expectedReason: model.TargetingMatchReason,
|
||||||
},
|
},
|
||||||
"joey@faas.com": {
|
"joey@faas.com": {
|
||||||
flags: flags,
|
flags: commonFlags,
|
||||||
flagKey: "headerColor",
|
flagKey: "headerColor",
|
||||||
context: map[string]any{
|
context: map[string]any{
|
||||||
"email": "joey@faas.com",
|
"email": "joey@faas.com",
|
||||||
|
|
@ -125,7 +125,7 @@ func TestFractionalEvaluation(t *testing.T) {
|
||||||
expectedReason: model.TargetingMatchReason,
|
expectedReason: model.TargetingMatchReason,
|
||||||
},
|
},
|
||||||
"ross@faas.com": {
|
"ross@faas.com": {
|
||||||
flags: flags,
|
flags: commonFlags,
|
||||||
flagKey: "headerColor",
|
flagKey: "headerColor",
|
||||||
context: map[string]any{
|
context: map[string]any{
|
||||||
"email": "ross@faas.com",
|
"email": "ross@faas.com",
|
||||||
|
|
@ -135,7 +135,7 @@ func TestFractionalEvaluation(t *testing.T) {
|
||||||
expectedReason: model.TargetingMatchReason,
|
expectedReason: model.TargetingMatchReason,
|
||||||
},
|
},
|
||||||
"rachel@faas.com with custom seed": {
|
"rachel@faas.com with custom seed": {
|
||||||
flags: flags,
|
flags: commonFlags,
|
||||||
flagKey: "customSeededHeaderColor",
|
flagKey: "customSeededHeaderColor",
|
||||||
context: map[string]any{
|
context: map[string]any{
|
||||||
"email": "rachel@faas.com",
|
"email": "rachel@faas.com",
|
||||||
|
|
@ -145,7 +145,7 @@ func TestFractionalEvaluation(t *testing.T) {
|
||||||
expectedReason: model.TargetingMatchReason,
|
expectedReason: model.TargetingMatchReason,
|
||||||
},
|
},
|
||||||
"monica@faas.com with custom seed": {
|
"monica@faas.com with custom seed": {
|
||||||
flags: flags,
|
flags: commonFlags,
|
||||||
flagKey: "customSeededHeaderColor",
|
flagKey: "customSeededHeaderColor",
|
||||||
context: map[string]any{
|
context: map[string]any{
|
||||||
"email": "monica@faas.com",
|
"email": "monica@faas.com",
|
||||||
|
|
@ -155,7 +155,7 @@ func TestFractionalEvaluation(t *testing.T) {
|
||||||
expectedReason: model.TargetingMatchReason,
|
expectedReason: model.TargetingMatchReason,
|
||||||
},
|
},
|
||||||
"joey@faas.com with custom seed": {
|
"joey@faas.com with custom seed": {
|
||||||
flags: flags,
|
flags: commonFlags,
|
||||||
flagKey: "customSeededHeaderColor",
|
flagKey: "customSeededHeaderColor",
|
||||||
context: map[string]any{
|
context: map[string]any{
|
||||||
"email": "joey@faas.com",
|
"email": "joey@faas.com",
|
||||||
|
|
@ -165,7 +165,7 @@ func TestFractionalEvaluation(t *testing.T) {
|
||||||
expectedReason: model.TargetingMatchReason,
|
expectedReason: model.TargetingMatchReason,
|
||||||
},
|
},
|
||||||
"ross@faas.com with custom seed": {
|
"ross@faas.com with custom seed": {
|
||||||
flags: flags,
|
flags: commonFlags,
|
||||||
flagKey: "customSeededHeaderColor",
|
flagKey: "customSeededHeaderColor",
|
||||||
context: map[string]any{
|
context: map[string]any{
|
||||||
"email": "ross@faas.com",
|
"email": "ross@faas.com",
|
||||||
|
|
@ -389,6 +389,35 @@ func TestFractionalEvaluation(t *testing.T) {
|
||||||
expectedValue: "#0000FF",
|
expectedValue: "#0000FF",
|
||||||
expectedReason: model.TargetingMatchReason,
|
expectedReason: model.TargetingMatchReason,
|
||||||
},
|
},
|
||||||
|
"missing email - parser should ignore nil/missing custom variables and continue": {
|
||||||
|
flags: Flags{
|
||||||
|
Flags: map[string]model.Flag{
|
||||||
|
"headerColor": {
|
||||||
|
State: "ENABLED",
|
||||||
|
DefaultVariant: "red",
|
||||||
|
Variants: map[string]any{
|
||||||
|
"red": "#FF0000",
|
||||||
|
"blue": "#0000FF",
|
||||||
|
},
|
||||||
|
Targeting: []byte(
|
||||||
|
`{
|
||||||
|
"fractional": [
|
||||||
|
{"var": "email"},
|
||||||
|
["red",50],
|
||||||
|
["blue",50]
|
||||||
|
]
|
||||||
|
}`),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
flagKey: "headerColor",
|
||||||
|
context: map[string]any{
|
||||||
|
"targetingKey": "foo@foo.com",
|
||||||
|
},
|
||||||
|
expectedVariant: "red",
|
||||||
|
expectedValue: "#FF0000",
|
||||||
|
expectedReason: model.TargetingMatchReason,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
const reqID = "default"
|
const reqID = "default"
|
||||||
for name, tt := range tests {
|
for name, tt := range tests {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue