flaviostutz / ruller-dsl-feature-flag

A feature flag engine that can be used to enable, change or rollout features of a system dynamically based on system or user attributes
MIT License
2 stars 6 forks source link

Broken Go rules code when condition have inputs that are prefixes of one another #19

Closed eabili0 closed 4 years ago

eabili0 commented 4 years ago

Hello,

We have the following json rules file:

{
  "label" : "Rules",
  "_config" : {
    "seed" : 1234,
    "default_contition" : true
  },
  "_groups" : {
    "102_203_ag" : [ "ag", "ag1" ],
    "102_205_ag_state" : [ "AM", "DF" ],
    "102_204_customerid_1" : "/rules/teste_id_restritivo.txt",
    "1_53_ag" : [ "0123", "0456", "0789" ],
    "102_202_state" : [ "AL", "BA" ],
    "102_204_customerid_0" : "/rules/teste_id.txt",
    "1_52_state" : [ "SP", "DF" ],
    "1_102_customerid_0" : "/rules/teste_id_3.txt"
  },
  "_items" : [ {
    "label" : "testeregramob",
    "fromuri" : "http://teste1.com.br",
    "touri" : "http://teste.redirect.com.br",
    "_condition" : "contains(group:1_52_state,input:state) and contains(group:1_53_ag,input:ag) and (contains(group:1_102_customerid_0,input:customerid)) and randomPerc(50,input:customerid)"
  }, {
    "label" : "Novo Teste - Piloto",
    "fromuri" : "http://localhost:8080",
    "touri" : "http://localhost:8089",
    "_condition" : "contains(group:102_202_state,input:state) and contains(group:102_203_ag,input:ag) and !contains(group:102_204_customerid_0,input:customerid) and !contains(group:102_204_customerid_1,input:customerid) and !contains(group:102_205_ag_state,input:ag_state) and randomPerc(38,input:customerid)"
  } ]
}

Ruller-DSL generates the following code for the condition of rule Novo Teste - Piloto:

condition := groupContains("mobpf","102_202_state",ctx.Input["state"].(string)) && groupContains("mobpf","102_203_ag",ctx.Input["ag"].(string)) && !groupContains("mobpf","102_204_customerid_0",ctx.Input["customerid"].(string)) && !groupContains("mobpf","102_204_customerid_1",ctx.Input["customerid"].(string)) && !groupContains("mobpf","102_205_ag_state",ctx.Input["ag"].(string)_state) && randomPerc(38,ctx.Input["customerid"].(string),1234)

This code breaks on build because the groupContains on ag_state is matching on ctx.Input["ag"] and _state is being weirdly appended to ctx.Input["ag"].(string):

image

Could you please help me verify what is causing this behaviour? Thank you!

eabili0 commented 4 years ago

Ok. I have pinned down the error is in the cast all other attributes to string code section from ruller-dsl's conditionCode.

CONDITION AFTER REGEX FUNC: contains(group:102_202_state,input:state) and contains(group:102_203_ag,input:ag) and !contains(group:102_204_customerid_0,input:customerid) and !contains(group:102_204_customerid_1,input:customerid) and !contains(group:102_205_ag_state,input:ag_state) and randomPerc(38,input:customerid)
CONDITION AFTER CONCAT: contains(group:102_202_state,input:state) and contains(group:102_203_ag,input:ag) and !contains(group:102_204_customerid_0,input:customerid) and !contains(group:102_204_customerid_1,input:customerid) and !contains(group:102_205_ag_state,input:ag_state) and randomPerc(38,input:customerid)
CONDITION AFTER GROUP_REFERENCES TO STRING: groupContains("mobpf","102_202_state",input:state) and groupContains("mobpf","102_203_ag",input:ag) and !groupContains("mobpf","102_204_customerid_0",input:customerid) and !groupContains("mobpf","102_204_customerid_1",input:customerid) and !groupContains("mobpf","102_205_ag_state",input:ag_state) and randomPerc(38,input:customerid)
CONDITION AFTER RANDOM PERC: groupContains("mobpf","102_202_state",input:state) and groupContains("mobpf","102_203_ag",input:ag) and !groupContains("mobpf","102_204_customerid_0",input:customerid) and !groupContains("mobpf","102_204_customerid_1",input:customerid) and !groupContains("mobpf","102_205_ag_state",input:ag_state) and randomPerc(38,input:customerid,1234)
CONDITION AFTER NUMERIC COMPARISONS: groupContains("mobpf","102_202_state",input:state) and groupContains("mobpf","102_203_ag",input:ag) and !groupContains("mobpf","102_204_customerid_0",input:customerid) and !groupContains("mobpf","102_204_customerid_1",input:customerid) and !groupContains("mobpf","102_205_ag_state",input:ag_state) and randomPerc(38,input:customerid,1234)
CONDITION AFTER CAST STRING: groupContains("mobpf","102_202_state",input:state.(string)) and groupContains("mobpf","102_203_ag",input:ag.(string)) and !groupContains("mobpf","102_204_customerid_0",input:customerid.(string)) and !groupContains("mobpf","102_204_customerid_1",input:customerid.(string)) and !groupContains("mobpf","102_205_ag_state",input:ag.(string)_state) and randomPerc(38,input:customerid.(string),1234)
eabili0 commented 4 years ago

Ok. Found the error.

On line condition = strings.Replace(condition, "input:"+sm, fmt.Sprintf("input:%s.(string)", sm), -1), if sm is also a prefix to any of other fields, it breaks them replacing the prefix with .(string).

milhomens commented 4 years ago

@abilioesteves, what if you change the match regex to include , ) and \s? Something like: inputNameRegex2 := regexp.MustCompile("input:([a-z0-9-_\.]+)[,)\s]") Can you test it locally?

eabili0 commented 4 years ago

makes sense. will give it a try

eabili0 commented 4 years ago

@milhomens it worked! Had to change a little bit more than that, but it is now working!

PR #20

milhomens commented 4 years ago

We got a little biased, so we forgot simple conditions like input:ag=='1234'. You probably need to add "=" to the regex.

eabili0 commented 4 years ago

@milhomens, == and != have now been added to the regex

eabili0 commented 4 years ago

any opinions on this @flaviostutz ?