diff --git a/cmd/cgr-engine/cgr-engine.go b/cmd/cgr-engine/cgr-engine.go index bb280d6bb..ddb792d7c 100644 --- a/cmd/cgr-engine/cgr-engine.go +++ b/cmd/cgr-engine/cgr-engine.go @@ -128,6 +128,7 @@ func startCdrc(internalCdrSChan, internalRaterChan chan rpcclient.RpcClientConne if err := cdrc.Run(); err != nil { utils.Logger.Crit(fmt.Sprintf("Cdrc run error: %s", err.Error())) exitChan <- true // If run stopped, something is bad, stop the application + return } } @@ -435,6 +436,7 @@ func startHistoryServer(internalHistorySChan chan rpcclient.RpcClientConnection, if err != nil { utils.Logger.Crit(fmt.Sprintf(" Could not start, error: %s", err.Error())) exitChan <- true + return } server.RpcRegisterName("HistoryV1", scribeServer) internalHistorySChan <- scribeServer @@ -583,6 +585,7 @@ func main() { go func() { // Schedule shutdown time.Sleep(shutdownDur) exitChan <- true + return }() } // Init config diff --git a/engine/fscdr_test.go b/engine/fscdr_test.go index 9bf138a1a..64c90e303 100644 --- a/engine/fscdr_test.go +++ b/engine/fscdr_test.go @@ -19,7 +19,6 @@ package engine import ( "reflect" - "regexp" "testing" "time" @@ -97,9 +96,7 @@ func TestSearchExtraFieldInSlice(t *testing.T) { } func TestSearchReplaceInExtraFields(t *testing.T) { - fsCdrCfg.CDRSExtraFields = []*utils.RSRField{&utils.RSRField{Id: "read_codec"}, - &utils.RSRField{Id: "sip_user_agent", RSRules: []*utils.ReSearchReplace{&utils.ReSearchReplace{SearchRegexp: regexp.MustCompile(`([A-Za-z]*).+`), ReplaceTemplate: "$1"}}}, - &utils.RSRField{Id: "write_codec"}} + fsCdrCfg.CDRSExtraFields = utils.ParseRSRFieldsMustCompile(`read_codec;~sip_user_agent:s/([A-Za-z]*).+/$1/;write_codec`, utils.INFIELD_SEP) fsCdr, _ := NewFSCdr(body, fsCdrCfg) extraFields := fsCdr.getExtraFields() if len(extraFields) != 3 { @@ -147,11 +144,11 @@ func TestDDazRSRExtraFields(t *testing.T) { }`) var err error fsCdrCfg, err = config.NewCGRConfigFromJsonString(eFieldsCfg) + expCdrExtra := utils.ParseRSRFieldsMustCompile(`~effective_caller_id_number:s/(\d+)/+$1/`, utils.INFIELD_SEP) if err != nil { t.Error("Could not parse the config", err.Error()) - } else if !reflect.DeepEqual(fsCdrCfg.CDRSExtraFields, []*utils.RSRField{&utils.RSRField{Id: "effective_caller_id_number", - RSRules: []*utils.ReSearchReplace{&utils.ReSearchReplace{SearchRegexp: regexp.MustCompile(`(\d+)`), ReplaceTemplate: "+$1"}}}}) { - t.Errorf("Unexpected value for config CdrsExtraFields: %v", fsCdrCfg.CDRSExtraFields) + } else if !reflect.DeepEqual(expCdrExtra[0], fsCdrCfg.CDRSExtraFields[0]) { // Kinda deepEqual bug since without index does not match + t.Errorf("Expecting: %+v, received: %+v", expCdrExtra, fsCdrCfg.CDRSExtraFields) } fsCdr, err := NewFSCdr(simpleJsonCdr, fsCdrCfg) if err != nil { @@ -159,6 +156,6 @@ func TestDDazRSRExtraFields(t *testing.T) { } extraFields := fsCdr.getExtraFields() if extraFields["effective_caller_id_number"] != "+4986517174963" { - t.Error("Unexpected effective_caller_id_number received", extraFields["effective_caller_id_number"]) + t.Errorf("Unexpected effective_caller_id_number received: %+v", extraFields["effective_caller_id_number"]) } } diff --git a/utils/rsrfield.go b/utils/rsrfield.go index a30ffd253..a31465508 100644 --- a/utils/rsrfield.go +++ b/utils/rsrfield.go @@ -27,6 +27,7 @@ func NewRSRField(fldStr string) (*RSRField, error) { if len(fldStr) == 0 { return nil, nil } + rsrField := &RSRField{Rules: fldStr} var filters []*RSRFilter if strings.HasSuffix(fldStr, FILTER_VAL_END) { // Has filter, populate the var fltrStart := strings.LastIndex(fldStr, FILTER_VAL_START) @@ -43,7 +44,6 @@ func NewRSRField(fldStr string) (*RSRField, error) { fldStr = fldStr[:fltrStart] // Take the filter part out before compiling further } - if strings.HasPrefix(fldStr, STATIC_VALUE_PREFIX) { // Special case when RSR is defined as static header/value var staticHdr, staticVal string if splt := strings.Split(fldStr, STATIC_HDRVAL_SEP); len(splt) == 2 { // Using / as separator since ':' is often use in date/time fields @@ -56,17 +56,23 @@ func NewRSRField(fldStr string) (*RSRField, error) { } else { staticHdr, staticVal = splt[0][1:], splt[0][1:] // If no split, header will remain as original, value as header without the prefix } - return &RSRField{Id: staticHdr, staticValue: staticVal, filters: filters}, nil + rsrField.Id = staticHdr + rsrField.staticValue = staticVal + rsrField.filters = filters + return rsrField, nil } if !strings.HasPrefix(fldStr, REGEXP_PREFIX) { - return &RSRField{Id: fldStr, filters: filters}, nil + rsrField.Id = fldStr + rsrField.filters = filters + return rsrField, nil } spltRgxp := regexp.MustCompile(`:s\/`) spltRules := spltRgxp.Split(fldStr, -1) if len(spltRules) < 2 { return nil, fmt.Errorf("Invalid Split of Search&Replace field rule. %s", fldStr) } - rsrField := &RSRField{Id: spltRules[0][1:], filters: filters} // Original id in form ~hdr_name + rsrField.Id = spltRules[0][1:] + rsrField.filters = filters // Original id in form ~hdr_name rulesRgxp := regexp.MustCompile(`(?:(.+[^\\])\/(.*[^\\])*\/){1,}`) for _, ruleStr := range spltRules[1:] { // :s/ already removed through split allMatches := rulesRgxp.FindStringSubmatch(ruleStr) @@ -83,12 +89,30 @@ func NewRSRField(fldStr string) (*RSRField, error) { } type RSRField struct { - Id string // Identifier - RSRules []*ReSearchReplace // Rules to use when processing field value + Id string // Identifier + Rules string // Rules container holding the string rules to be able to restore it after DB staticValue string // If defined, enforces parsing always to this value + RSRules []*ReSearchReplace // Rules to use when processing field value filters []*RSRFilter // The value to compare when used as filter } +// IsParsed finds out whether this RSRField was already parsed or RAW state +func (rsrf *RSRField) IsParsed() bool { + return rsrf.staticValue != "" || rsrf.RSRules != nil || rsrf.filters != nil +} + +// Compile parses Rules string and repopulates other fields +func (rsrf *RSRField) ParseRules() error { + if newRSRFld, err := NewRSRField(rsrf.Rules); err != nil { + return err + } else { + rsrf.staticValue = newRSRFld.staticValue + rsrf.RSRules = newRSRFld.RSRules + rsrf.filters = newRSRFld.filters + } + return nil +} + // Parse the field value from a string func (rsrf *RSRField) ParseValue(value string) string { if len(rsrf.staticValue) != 0 { // Enforce parsing of static values @@ -218,17 +242,6 @@ func (fltrs RSRFilters) Pass(val string, allMustMatch bool) bool { return matched } -// Parses list of RSRFields, used for example as multiple filters in derived charging -func ParseRSRFields(fldsStr, sep string) (RSRFields, error) { - //rsrRlsPattern := regexp.MustCompile(`^(~\w+:s/.+/.*/)|(\^.+(/.+/)?)(;(~\w+:s/.+/.*/)|(\^.+(/.+/)?))*$`) //ToDo:Fix here rule able to confirm the content - if len(fldsStr) == 0 { - return nil, nil - } - rulesSplt := strings.Split(fldsStr, sep) - return ParseRSRFieldsFromSlice(rulesSplt) - -} - func ParseRSRFieldsFromSlice(flds []string) (RSRFields, error) { if len(flds) == 0 { return nil, nil @@ -247,6 +260,17 @@ func ParseRSRFieldsFromSlice(flds []string) (RSRFields, error) { } +// Parses list of RSRFields, used for example as multiple filters in derived charging +func ParseRSRFields(fldsStr, sep string) (RSRFields, error) { + //rsrRlsPattern := regexp.MustCompile(`^(~\w+:s/.+/.*/)|(\^.+(/.+/)?)(;(~\w+:s/.+/.*/)|(\^.+(/.+/)?))*$`) //ToDo:Fix here rule able to confirm the content + if len(fldsStr) == 0 { + return nil, nil + } + rulesSplt := strings.Split(fldsStr, sep) + return ParseRSRFieldsFromSlice(rulesSplt) + +} + func ParseRSRFieldsMustCompile(fldsStr, sep string) RSRFields { if flds, err := ParseRSRFields(fldsStr, sep); err != nil { return nil diff --git a/utils/rsrfield_test.go b/utils/rsrfield_test.go index 3932e72a7..414e4ad71 100644 --- a/utils/rsrfield_test.go +++ b/utils/rsrfield_test.go @@ -25,30 +25,34 @@ import ( func TestNewRSRField1(t *testing.T) { // Normal case - expRSRField1 := &RSRField{Id: "sip_redirected_to", + rulesStr := `~sip_redirected_to:s/sip:\+49(\d+)@/0$1/` + expRSRField1 := &RSRField{Id: "sip_redirected_to", Rules: rulesStr, RSRules: []*ReSearchReplace{&ReSearchReplace{SearchRegexp: regexp.MustCompile(`sip:\+49(\d+)@`), ReplaceTemplate: "0$1"}}} - if rsrField, err := NewRSRField(`~sip_redirected_to:s/sip:\+49(\d+)@/0$1/`); err != nil { + if rsrField, err := NewRSRField(rulesStr); err != nil { t.Error("Unexpected error: ", err.Error()) } else if !reflect.DeepEqual(expRSRField1, rsrField) { t.Errorf("Expecting: %v, received: %v", expRSRField1, rsrField) } // With filter + rulesStr = `~sip_redirected_to:s/sip:\+49(\d+)@/0$1/(086517174963)` filter, _ := NewRSRFilter("086517174963") - expRSRField2 := &RSRField{Id: "sip_redirected_to", filters: []*RSRFilter{filter}, + expRSRField2 := &RSRField{Id: "sip_redirected_to", Rules: rulesStr, filters: []*RSRFilter{filter}, RSRules: []*ReSearchReplace{&ReSearchReplace{SearchRegexp: regexp.MustCompile(`sip:\+49(\d+)@`), ReplaceTemplate: "0$1"}}} - if rsrField, err := NewRSRField(`~sip_redirected_to:s/sip:\+49(\d+)@/0$1/(086517174963)`); err != nil { + if rsrField, err := NewRSRField(rulesStr); err != nil { t.Error("Unexpected error: ", err.Error()) } else if !reflect.DeepEqual(expRSRField2, rsrField) { t.Errorf("Expecting: %v, received: %v", expRSRField2, rsrField) } // Separator escaped - if rsrField, err := NewRSRField(`~sip_redirected_to:s\/sip:\+49(\d+)@/0$1/`); err == nil { + rulesStr = `~sip_redirected_to:s\/sip:\+49(\d+)@/0$1/` + if rsrField, err := NewRSRField(rulesStr); err == nil { t.Errorf("Parse error, field rule does not contain correct number of separators, received: %v", rsrField) } // One extra separator but escaped - expRSRField3 := &RSRField{Id: "sip_redirected_to", + rulesStr = `~sip_redirected_to:s/sip:\+49(\d+)\/@/0$1/` + expRSRField3 := &RSRField{Id: "sip_redirected_to", Rules: rulesStr, RSRules: []*ReSearchReplace{&ReSearchReplace{SearchRegexp: regexp.MustCompile(`sip:\+49(\d+)\/@`), ReplaceTemplate: "0$1"}}} - if rsrField, err := NewRSRField(`~sip_redirected_to:s/sip:\+49(\d+)\/@/0$1/`); err != nil { + if rsrField, err := NewRSRField(rulesStr); err != nil { t.Error("Unexpected error: ", err.Error()) } else if !reflect.DeepEqual(expRSRField3, rsrField) { t.Errorf("Expecting: %v, received: %v", expRSRField3, rsrField) @@ -56,9 +60,10 @@ func TestNewRSRField1(t *testing.T) { } func TestNewRSRFieldDDz(t *testing.T) { - expectRSRField := &RSRField{Id: "effective_caller_id_number", + rulesStr := `~effective_caller_id_number:s/(\d+)/+$1/` + expectRSRField := &RSRField{Id: "effective_caller_id_number", Rules: rulesStr, RSRules: []*ReSearchReplace{&ReSearchReplace{SearchRegexp: regexp.MustCompile(`(\d+)`), ReplaceTemplate: "+$1"}}} - if rsrField, err := NewRSRField(`~effective_caller_id_number:s/(\d+)/+$1/`); err != nil { + if rsrField, err := NewRSRField(rulesStr); err != nil { t.Error(err) } else if !reflect.DeepEqual(rsrField, expectRSRField) { t.Errorf("Unexpected RSRField received: %v", rsrField) @@ -66,9 +71,10 @@ func TestNewRSRFieldDDz(t *testing.T) { } func TestNewRSRFieldIvo(t *testing.T) { - expectRSRField := &RSRField{Id: "cost_details", + rulesStr := `~cost_details:s/MatchedDestId":".+_(\s\s\s\s\s)"/$1/` + expectRSRField := &RSRField{Id: "cost_details", Rules: rulesStr, RSRules: []*ReSearchReplace{&ReSearchReplace{SearchRegexp: regexp.MustCompile(`MatchedDestId":".+_(\s\s\s\s\s)"`), ReplaceTemplate: "$1"}}} - if rsrField, err := NewRSRField(`~cost_details:s/MatchedDestId":".+_(\s\s\s\s\s)"/$1/`); err != nil { + if rsrField, err := NewRSRField(rulesStr); err != nil { t.Error(err) } else if !reflect.DeepEqual(rsrField, expectRSRField) { t.Errorf("Unexpected RSRField received: %v", rsrField) @@ -79,10 +85,12 @@ func TestNewRSRFieldIvo(t *testing.T) { } func TestConvertPlusNationalAnd00(t *testing.T) { - expectRSRField := &RSRField{Id: "effective_caller_id_number", RSRules: []*ReSearchReplace{ - &ReSearchReplace{SearchRegexp: regexp.MustCompile(`\+49(\d+)`), ReplaceTemplate: "0$1"}, - &ReSearchReplace{SearchRegexp: regexp.MustCompile(`\+(\d+)`), ReplaceTemplate: "00$1"}}} - rsrField, err := NewRSRField(`~effective_caller_id_number:s/\+49(\d+)/0$1/:s/\+(\d+)/00$1/`) + rulesStr := `~effective_caller_id_number:s/\+49(\d+)/0$1/:s/\+(\d+)/00$1/` + expectRSRField := &RSRField{Id: "effective_caller_id_number", Rules: rulesStr, + RSRules: []*ReSearchReplace{ + &ReSearchReplace{SearchRegexp: regexp.MustCompile(`\+49(\d+)`), ReplaceTemplate: "0$1"}, + &ReSearchReplace{SearchRegexp: regexp.MustCompile(`\+(\d+)`), ReplaceTemplate: "00$1"}}} + rsrField, err := NewRSRField(rulesStr) if err != nil { t.Error(err) } else if !reflect.DeepEqual(rsrField, expectRSRField) { @@ -97,16 +105,20 @@ func TestConvertPlusNationalAnd00(t *testing.T) { } func TestRSRParseStatic(t *testing.T) { - if rsrField, err := NewRSRField("^static_header::static_value/"); err != nil { + rulesStr := "^static_header::static_value/" + if rsrField, err := NewRSRField(rulesStr); err != nil { t.Error(err) - } else if !reflect.DeepEqual(rsrField, &RSRField{Id: "static_header", staticValue: "static_value"}) { + } else if !reflect.DeepEqual(rsrField, &RSRField{Id: "static_header", Rules: rulesStr, + staticValue: "static_value"}) { t.Errorf("Unexpected RSRField received: %v", rsrField) } else if parsed := rsrField.ParseValue("dynamic_value"); parsed != "static_value" { t.Errorf("Expected: %s, received: %s", "static_value", parsed) } - if rsrField, err := NewRSRField(`^static_hdrvalue`); err != nil { + rulesStr = `^static_hdrvalue` + if rsrField, err := NewRSRField(rulesStr); err != nil { t.Error(err) - } else if !reflect.DeepEqual(rsrField, &RSRField{Id: "static_hdrvalue", staticValue: "static_hdrvalue"}) { + } else if !reflect.DeepEqual(rsrField, &RSRField{Id: "static_hdrvalue", Rules: rulesStr, + staticValue: "static_hdrvalue"}) { t.Errorf("Unexpected RSRField received: %v", rsrField) } else if parsed := rsrField.ParseValue("dynamic_value"); parsed != "static_hdrvalue" { t.Errorf("Expected: %s, received: %s", "static_hdrvalue", parsed) @@ -114,9 +126,11 @@ func TestRSRParseStatic(t *testing.T) { } func TestConvertDurToSecs(t *testing.T) { - expectRSRField := &RSRField{Id: "9", RSRules: []*ReSearchReplace{ - &ReSearchReplace{SearchRegexp: regexp.MustCompile(`^(\d+)$`), ReplaceTemplate: "${1}s"}}} - rsrField, err := NewRSRField(`~9:s/^(\d+)$/${1}s/`) + rulesStr := `~9:s/^(\d+)$/${1}s/` + expectRSRField := &RSRField{Id: "9", Rules: rulesStr, + RSRules: []*ReSearchReplace{ + &ReSearchReplace{SearchRegexp: regexp.MustCompile(`^(\d+)$`), ReplaceTemplate: "${1}s"}}} + rsrField, err := NewRSRField(rulesStr) if err != nil { t.Error(err) } else if !reflect.DeepEqual(rsrField, expectRSRField) { @@ -128,9 +142,11 @@ func TestConvertDurToSecs(t *testing.T) { } func TestPrefix164(t *testing.T) { - expectRSRField := &RSRField{Id: "0", RSRules: []*ReSearchReplace{ - &ReSearchReplace{SearchRegexp: regexp.MustCompile(`^([1-9]\d+)$`), ReplaceTemplate: "+$1"}}} - rsrField, err := NewRSRField(`~0:s/^([1-9]\d+)$/+$1/`) + rulesStr := `~0:s/^([1-9]\d+)$/+$1/` + expectRSRField := &RSRField{Id: "0", Rules: rulesStr, + RSRules: []*ReSearchReplace{ + &ReSearchReplace{SearchRegexp: regexp.MustCompile(`^([1-9]\d+)$`), ReplaceTemplate: "+$1"}}} + rsrField, err := NewRSRField(rulesStr) if err != nil { t.Error(err) } else if !reflect.DeepEqual(rsrField, expectRSRField) { @@ -166,10 +182,10 @@ func TestParseRSRFields(t *testing.T) { } fields := `host,~sip_redirected_to:s/sip:\+49(\d+)@/0$1/,destination` expectParsedFields := RSRFields{ - &RSRField{Id: "host"}, - &RSRField{Id: "sip_redirected_to", + &RSRField{Id: "host", Rules: "host"}, + &RSRField{Id: "sip_redirected_to", Rules: `~sip_redirected_to:s/sip:\+49(\d+)@/0$1/`, RSRules: []*ReSearchReplace{&ReSearchReplace{SearchRegexp: regexp.MustCompile(`sip:\+49(\d+)@`), ReplaceTemplate: "0$1"}}}, - &RSRField{Id: "destination"}} + &RSRField{Id: "destination", Rules: "destination"}} if parsedFields, err := ParseRSRFields(fields, FIELDS_SEP); err != nil { t.Error("Unexpected error: ", err.Error()) } else if !reflect.DeepEqual(parsedFields, expectParsedFields) { @@ -390,3 +406,43 @@ func TestRSRFiltersPass(t *testing.T) { t.Error("Passing") } } + +func TestParseDifferentMethods(t *testing.T) { + rlStr := `~effective_caller_id_number:s/(\d+)/+$1/` + resParseStr, _ := ParseRSRFields(rlStr, INFIELD_SEP) + resParseSlc, _ := ParseRSRFieldsFromSlice([]string{rlStr}) + if !reflect.DeepEqual(resParseStr, resParseSlc) { + t.Errorf("Expecting: %+v, received: %+v", resParseStr, resParseSlc) + } +} + +func TestIsParsed(t *testing.T) { + rulesStr := `^static_hdrvalue` + if rsrField, err := NewRSRField(rulesStr); err != nil { + t.Error(err) + } else if !rsrField.IsParsed() { + t.Error("Not parsed") + } + rulesStr = `~effective_caller_id_number:s/(\d+)/+$1/` + if rsrField, err := NewRSRField(rulesStr); err != nil { + t.Error(err) + } else if !rsrField.IsParsed() { + t.Error("Not parsed") + } + rsrField := &RSRField{Rules: rulesStr} + if rsrField.IsParsed() { + t.Error("Is parsed") + } +} + +func TestParseRules(t *testing.T) { + rulesStr := `^static_hdrvalue` + rsrField := &RSRField{Rules: rulesStr} + if err := rsrField.ParseRules(); err != nil { + t.Error(err) + } + newRSRFld, _ := NewRSRField(rulesStr) + if reflect.DeepEqual(rsrField, newRSRFld) { + t.Errorf("Expecting: %+v, received: %+v", rsrField, newRSRFld) + } +}