mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-15 05:09:54 +05:00
RunFilter in DerivedChargers, ParseEventValue accepting RSRField in FreeSWITCH event
This commit is contained in:
@@ -250,7 +250,7 @@ func TestConfigFromFile(t *testing.T) {
|
||||
eCfg.FreeswitchServer = "test"
|
||||
eCfg.FreeswitchPass = "test"
|
||||
eCfg.FreeswitchReconnects = 99
|
||||
eCfg.DerivedChargers = utils.DerivedChargers{&utils.DerivedCharger{RunId: "test", ReqTypeField: "test", DirectionField: "test", TenantField: "test",
|
||||
eCfg.DerivedChargers = utils.DerivedChargers{&utils.DerivedCharger{RunId: "test", RunFilter: "", ReqTypeField: "test", DirectionField: "test", TenantField: "test",
|
||||
CategoryField: "test", AccountField: "test", SubjectField: "test", DestinationField: "test", SetupTimeField: "test", AnswerTimeField: "test", UsageField: "test"}}
|
||||
eCfg.CombinedDerivedChargers = true
|
||||
eCfg.HistoryAgentEnabled = true
|
||||
@@ -264,7 +264,13 @@ func TestConfigFromFile(t *testing.T) {
|
||||
eCfg.MailerFromAddr = "test"
|
||||
if !reflect.DeepEqual(cfg, eCfg) {
|
||||
t.Log(eCfg)
|
||||
for _, eDC := range eCfg.DerivedChargers {
|
||||
fmt.Printf("ExpectDerivedChargers: %+v\n", eDC)
|
||||
}
|
||||
t.Log(cfg)
|
||||
for _, eDC := range cfg.DerivedChargers {
|
||||
fmt.Printf("DerivedChargers: %+v\n", eDC)
|
||||
}
|
||||
t.Error("Loading of configuration from file failed!")
|
||||
}
|
||||
}
|
||||
@@ -288,12 +294,6 @@ extra_fields = ~effective_caller_id_number:s/(\d+)/+$1/
|
||||
t.Errorf("Unexpected value for config CdrsExtraFields: %v", cfg.CDRSExtraFields)
|
||||
}
|
||||
eFieldsCfg = []byte(`[cdrs]
|
||||
extra_fields = extr1,extr2,
|
||||
`)
|
||||
if _, err := NewCGRConfigFromBytes(eFieldsCfg); err == nil {
|
||||
t.Error("Failed to detect empty field in the end of extra fields defition")
|
||||
}
|
||||
eFieldsCfg = []byte(`[cdrs]
|
||||
extra_fields = extr1,~extr2:s/x.+/
|
||||
`)
|
||||
if _, err := NewCGRConfigFromBytes(eFieldsCfg); err == nil {
|
||||
|
||||
@@ -29,15 +29,11 @@ import (
|
||||
|
||||
// Adds support for slice values in config
|
||||
func ConfigSlice(cfgVal string) ([]string, error) {
|
||||
cfgValStrs := strings.Split(cfgVal, ",") // If need arrises, we can make the separator configurable
|
||||
if len(cfgValStrs) == 1 && cfgValStrs[0] == "" { // Prevents returning iterable with empty value
|
||||
return []string{}, nil
|
||||
}
|
||||
cfgValStrs := strings.Split(cfgVal, ",") // If need arrises, we can make the separator configurable
|
||||
for idx, elm := range cfgValStrs {
|
||||
if elm == "" { //One empty element is presented when splitting empty string
|
||||
return nil, errors.New("Empty values in config slice")
|
||||
|
||||
}
|
||||
//if elm == "" { //One empty element is presented when splitting empty string
|
||||
// return nil, errors.New("Empty values in config slice")
|
||||
//}
|
||||
cfgValStrs[idx] = strings.TrimSpace(elm) // By default spaces are not removed so we do it here to avoid unpredicted results in config
|
||||
}
|
||||
return cfgValStrs, nil
|
||||
@@ -50,10 +46,6 @@ func ParseRSRFields(configVal string) ([]*utils.RSRField, error) {
|
||||
}
|
||||
rsrFields := make([]*utils.RSRField, len(cfgValStrs))
|
||||
for idx, cfgValStr := range cfgValStrs {
|
||||
if len(cfgValStr) == 0 { //One empty element is presented when splitting empty string
|
||||
return nil, errors.New("Empty values in config slice")
|
||||
|
||||
}
|
||||
if rsrField, err := utils.NewRSRField(cfgValStr); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
@@ -65,11 +57,15 @@ func ParseRSRFields(configVal string) ([]*utils.RSRField, error) {
|
||||
|
||||
// Parse the configuration file and returns utils.DerivedChargers instance if no errors
|
||||
func ParseCfgDerivedCharging(c *conf.ConfigFile) (dcs utils.DerivedChargers, err error) {
|
||||
var runIds, reqTypeFlds, directionFlds, tenantFlds, torFlds, acntFlds, subjFlds, dstFlds, sTimeFlds, aTimeFlds, durFlds []string
|
||||
var runIds, runFilters, reqTypeFlds, directionFlds, tenantFlds, torFlds, acntFlds, subjFlds, dstFlds, sTimeFlds, aTimeFlds, durFlds []string
|
||||
cfgVal, _ := c.GetString("derived_charging", "run_ids")
|
||||
if runIds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgVal, _ = c.GetString("derived_charging", "run_filters")
|
||||
if runFilters, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfgVal, _ = c.GetString("derived_charging", "reqtype_fields")
|
||||
if reqTypeFlds, err = ConfigSlice(cfgVal); err != nil {
|
||||
return nil, err
|
||||
@@ -111,7 +107,8 @@ func ParseCfgDerivedCharging(c *conf.ConfigFile) (dcs utils.DerivedChargers, err
|
||||
return nil, err
|
||||
}
|
||||
// We need all to be the same length
|
||||
if len(reqTypeFlds) != len(runIds) ||
|
||||
if len(runFilters) != len(runIds) ||
|
||||
len(reqTypeFlds) != len(runIds) ||
|
||||
len(directionFlds) != len(runIds) ||
|
||||
len(tenantFlds) != len(runIds) ||
|
||||
len(torFlds) != len(runIds) ||
|
||||
@@ -125,8 +122,11 @@ func ParseCfgDerivedCharging(c *conf.ConfigFile) (dcs utils.DerivedChargers, err
|
||||
}
|
||||
// Create the individual chargers and append them to the final instance
|
||||
dcs = make(utils.DerivedChargers, 0)
|
||||
if len(runIds) == 1 && len(runIds[0]) == 0 { // Avoid iterating on empty runid
|
||||
return dcs, nil
|
||||
}
|
||||
for runIdx, runId := range runIds {
|
||||
dc, err := utils.NewDerivedCharger(runId, reqTypeFlds[runIdx], directionFlds[runIdx], tenantFlds[runIdx], torFlds[runIdx],
|
||||
dc, err := utils.NewDerivedCharger(runId, runFilters[runIdx], reqTypeFlds[runIdx], directionFlds[runIdx], tenantFlds[runIdx], torFlds[runIdx],
|
||||
acntFlds[runIdx], subjFlds[runIdx], dstFlds[runIdx], sTimeFlds[runIdx], aTimeFlds[runIdx], durFlds[runIdx])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -26,6 +26,15 @@ import (
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
func TestConfigSlice(t *testing.T) {
|
||||
eCS := []string{"", ""}
|
||||
if cs, err := ConfigSlice(" , "); err != nil {
|
||||
t.Error("Unexpected error: ", err)
|
||||
} else if !reflect.DeepEqual(eCS, cs) {
|
||||
t.Errorf("Expecting: %v, received: %v", eCS, cs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseRSRFields(t *testing.T) {
|
||||
fields := `host,~sip_redirected_to:s/sip:\+49(\d+)@/0$1/,destination`
|
||||
expectParsedFields := []*utils.RSRField{&utils.RSRField{Id: "host"},
|
||||
@@ -41,6 +50,7 @@ func TestParseRSRFields(t *testing.T) {
|
||||
func TestParseCfgDerivedCharging(t *testing.T) {
|
||||
eFieldsCfg := []byte(`[derived_charging]
|
||||
run_ids = run1, run2
|
||||
run_filters =,
|
||||
reqtype_fields = test1, test2
|
||||
direction_fields = test1, test2
|
||||
tenant_fields = test1, test2
|
||||
|
||||
@@ -100,6 +100,7 @@ reconnects = 99 # Number of attempts on connect failure.
|
||||
|
||||
[derived_charging]
|
||||
run_ids = test # Identifiers of additional sessions control.
|
||||
run_filters = # No filters applied
|
||||
reqtype_fields = test # Name of request type fields to be used during additional sessions control <""|*default|field_name>.
|
||||
direction_fields = test # Name of direction fields to be used during additional sessions control <""|*default|field_name>.
|
||||
tenant_fields = test # Name of tenant fields to be used during additional sessions control <""|*default|field_name>.
|
||||
|
||||
@@ -104,6 +104,7 @@
|
||||
|
||||
[derived_charging]
|
||||
# run_ids = # Identifiers of additional sessions control.
|
||||
# run_filters = # List of cdr field filters for each run.
|
||||
# reqtype_fields = # Name of request type fields to be used during additional sessions control <""|*default|field_name>.
|
||||
# direction_fields = # Name of direction fields to be used during additional sessions control <""|*default|field_name>.
|
||||
# tenant_fields = # Name of tenant fields to be used during additional sessions control <""|*default|field_name>.
|
||||
|
||||
@@ -120,6 +120,11 @@ func (self *Mediator) RateCdr(storedCdr *utils.StoredCdr) error {
|
||||
return errors.New(errText)
|
||||
}
|
||||
for _, dc := range dcs {
|
||||
dcRunFilter, _ := utils.NewRSRField(dc.RunFilter)
|
||||
if dcRunFilter != nil && storedCdr.FieldAsString(&utils.RSRField{Id: dcRunFilter.Id}) != storedCdr.FieldAsString(dcRunFilter) {
|
||||
engine.Logger.Info(fmt.Sprintf("Ignoring DerivedCharger with id %s due to non matching filter", dc.RunId))
|
||||
continue
|
||||
}
|
||||
dcReqTypeFld, _ := utils.NewRSRField(dc.ReqTypeField)
|
||||
dcDirFld, _ := utils.NewRSRField(dc.DirectionField)
|
||||
dcTenantFld, _ := utils.NewRSRField(dc.TenantField)
|
||||
|
||||
@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package sessionmanager
|
||||
|
||||
import (
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -40,4 +41,5 @@ type Event interface {
|
||||
GetEndTime() (time.Time, error)
|
||||
GetDuration(string) (time.Duration, error)
|
||||
MissingParameter() bool
|
||||
ParseEventValue(*utils.RSRField) string
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package sessionmanager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -203,3 +204,48 @@ func (fsev FSEvent) GetDuration(fieldName string) (dur time.Duration, err error)
|
||||
}
|
||||
return utils.ParseDurationWithSecs(durStr)
|
||||
}
|
||||
|
||||
// Used in derived charging and sittuations when we need to run regexp on fields
|
||||
func (fsev FSEvent) ParseEventValue(rsrFld *utils.RSRField) string {
|
||||
switch rsrFld.Id {
|
||||
case utils.CGRID:
|
||||
return rsrFld.ParseValue(fsev.GetCgrId())
|
||||
case utils.TOR:
|
||||
return rsrFld.ParseValue(utils.VOICE)
|
||||
case utils.ACCID:
|
||||
return rsrFld.ParseValue(fsev.GetUUID())
|
||||
case utils.CDRHOST:
|
||||
return rsrFld.ParseValue(fsev["FreeSWITCH-IPv4"])
|
||||
case utils.CDRSOURCE:
|
||||
return rsrFld.ParseValue("FS_EVENT")
|
||||
case utils.REQTYPE:
|
||||
return rsrFld.ParseValue(fsev.GetReqType(""))
|
||||
case utils.DIRECTION:
|
||||
return rsrFld.ParseValue(fsev.GetDirection(""))
|
||||
case utils.TENANT:
|
||||
return rsrFld.ParseValue(fsev.GetTenant(""))
|
||||
case utils.CATEGORY:
|
||||
return rsrFld.ParseValue(fsev.GetCategory(""))
|
||||
case utils.ACCOUNT:
|
||||
return rsrFld.ParseValue(fsev.GetAccount(""))
|
||||
case utils.SUBJECT:
|
||||
return rsrFld.ParseValue(fsev.GetSubject(""))
|
||||
case utils.DESTINATION:
|
||||
return rsrFld.ParseValue(fsev.GetDestination(""))
|
||||
case utils.SETUP_TIME:
|
||||
st, _ := fsev.GetSetupTime("")
|
||||
return rsrFld.ParseValue(st.String())
|
||||
case utils.ANSWER_TIME:
|
||||
at, _ := fsev.GetAnswerTime("")
|
||||
return rsrFld.ParseValue(at.String())
|
||||
case utils.USAGE:
|
||||
dur, _ := fsev.GetDuration("")
|
||||
return rsrFld.ParseValue(strconv.FormatInt(dur.Nanoseconds(), 10))
|
||||
case utils.MEDI_RUNID:
|
||||
return rsrFld.ParseValue(utils.DEFAULT_RUNID)
|
||||
case utils.COST:
|
||||
return rsrFld.ParseValue(strconv.FormatFloat(-1, 'f', -1, 64)) // Recommended to use FormatCost
|
||||
default:
|
||||
return rsrFld.ParseValue(fsev[rsrFld.Id])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,138 +26,7 @@ import (
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
func TestEventCreation(t *testing.T) {
|
||||
body := `Event-Name: RE_SCHEDULE
|
||||
Core-UUID: 792e181c-b6e6-499c-82a1-52a778e7d82d
|
||||
FreeSWITCH-Hostname: h1.ip-switch.net
|
||||
FreeSWITCH-Switchname: h1.ip-switch.net
|
||||
FreeSWITCH-IPv4: 88.198.12.156
|
||||
FreeSWITCH-IPv6: %3A%3A1
|
||||
Event-Date-Local: 2012-10-05%2013%3A41%3A38
|
||||
Event-Date-GMT: Fri,%2005%20Oct%202012%2011%3A41%3A38%20GMT
|
||||
Event-Date-Timestamp: 1349437298012866
|
||||
Event-Calling-File: switch_scheduler.c
|
||||
Event-Calling-Function: switch_scheduler_execute
|
||||
Event-Calling-Line-Number: 65
|
||||
Event-Sequence: 34263
|
||||
Task-ID: 2
|
||||
Task-Desc: heartbeat
|
||||
Task-Group: core
|
||||
Task-Runtime: 1349437318`
|
||||
ev := new(FSEvent).New(body)
|
||||
if ev.GetName() != "RE_SCHEDULE" {
|
||||
t.Error("Event not parsed correctly: ", ev)
|
||||
}
|
||||
l := len(ev.(FSEvent))
|
||||
if l != 17 {
|
||||
t.Error("Incorrect number of event fields: ", l)
|
||||
}
|
||||
}
|
||||
|
||||
// Detects if any of the parsers do not return static values
|
||||
func TestEventParseStatic(t *testing.T) {
|
||||
ev := new(FSEvent).New("")
|
||||
setupTime, _ := ev.GetSetupTime("^2013-12-07 08:42:24")
|
||||
answerTime, _ := ev.GetAnswerTime("^2013-12-07 08:42:24")
|
||||
dur, _ := ev.GetDuration("^60s")
|
||||
if ev.GetReqType("^test") != "test" ||
|
||||
ev.GetDirection("^test") != "test" ||
|
||||
ev.GetTenant("^test") != "test" ||
|
||||
ev.GetCategory("^test") != "test" ||
|
||||
ev.GetAccount("^test") != "test" ||
|
||||
ev.GetSubject("^test") != "test" ||
|
||||
ev.GetDestination("^test") != "test" ||
|
||||
setupTime != time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC) ||
|
||||
answerTime != time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC) ||
|
||||
dur != time.Duration(60)*time.Second {
|
||||
t.Error("Values out of static not matching",
|
||||
ev.GetReqType("^test") != "test",
|
||||
ev.GetDirection("^test") != "test",
|
||||
ev.GetTenant("^test") != "test",
|
||||
ev.GetCategory("^test") != "test",
|
||||
ev.GetAccount("^test") != "test",
|
||||
ev.GetSubject("^test") != "test",
|
||||
ev.GetDestination("^test") != "test",
|
||||
setupTime != time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC),
|
||||
answerTime != time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC),
|
||||
dur != time.Duration(60)*time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
// Test here if the answer is selected out of headers we specify, even if not default defined
|
||||
func TestEventSelectiveHeaders(t *testing.T) {
|
||||
body := `Event-Name: RE_SCHEDULE
|
||||
Core-UUID: 792e181c-b6e6-499c-82a1-52a778e7d82d
|
||||
FreeSWITCH-Hostname: h1.ip-switch.net
|
||||
FreeSWITCH-Switchname: h1.ip-switch.net
|
||||
FreeSWITCH-IPv4: 88.198.12.156
|
||||
FreeSWITCH-IPv6: %3A%3A1
|
||||
Event-Date-Local: 2012-10-05%2013%3A41%3A38
|
||||
Event-Date-GMT: Fri,%2005%20Oct%202012%2011%3A41%3A38%20GMT
|
||||
Event-Date-Timestamp: 1349437298012866
|
||||
Event-Calling-File: switch_scheduler.c
|
||||
Event-Calling-Function: switch_scheduler_execute
|
||||
Event-Calling-Line-Number: 65
|
||||
Event-Sequence: 34263
|
||||
Task-ID: 2
|
||||
Task-Desc: heartbeat
|
||||
Task-Group: core
|
||||
Task-Runtime: 1349437318`
|
||||
cfg, _ = config.NewDefaultCGRConfig()
|
||||
config.SetCgrConfig(cfg)
|
||||
ev := new(FSEvent).New(body)
|
||||
setupTime, _ := ev.GetSetupTime("Event-Date-Local")
|
||||
answerTime, _ := ev.GetAnswerTime("Event-Date-Local")
|
||||
dur, _ := ev.GetDuration("Event-Calling-Line-Number")
|
||||
if ev.GetReqType("FreeSWITCH-Hostname") != "h1.ip-switch.net" ||
|
||||
ev.GetDirection("FreeSWITCH-Hostname") != "*out" ||
|
||||
ev.GetTenant("FreeSWITCH-Hostname") != "h1.ip-switch.net" ||
|
||||
ev.GetCategory("FreeSWITCH-Hostname") != "h1.ip-switch.net" ||
|
||||
ev.GetAccount("FreeSWITCH-Hostname") != "h1.ip-switch.net" ||
|
||||
ev.GetSubject("FreeSWITCH-Hostname") != "h1.ip-switch.net" ||
|
||||
ev.GetDestination("FreeSWITCH-Hostname") != "h1.ip-switch.net" ||
|
||||
setupTime != time.Date(2012, 10, 5, 13, 41, 38, 0, time.UTC) ||
|
||||
answerTime != time.Date(2012, 10, 5, 13, 41, 38, 0, time.UTC) ||
|
||||
dur != time.Duration(65)*time.Second {
|
||||
t.Error("Values out of static not matching",
|
||||
ev.GetReqType("FreeSWITCH-Hostname") != "h1.ip-switch.net",
|
||||
ev.GetDirection("FreeSWITCH-Hostname") != "*out",
|
||||
ev.GetTenant("FreeSWITCH-Hostname") != "h1.ip-switch.net",
|
||||
ev.GetCategory("FreeSWITCH-Hostname") != "h1.ip-switch.net",
|
||||
ev.GetAccount("FreeSWITCH-Hostname") != "h1.ip-switch.net",
|
||||
ev.GetSubject("FreeSWITCH-Hostname") != "h1.ip-switch.net",
|
||||
ev.GetDestination("FreeSWITCH-Hostname") != "h1.ip-switch.net",
|
||||
setupTime != time.Date(2012, 10, 5, 13, 41, 38, 0, time.UTC),
|
||||
answerTime != time.Date(2012, 10, 5, 13, 41, 38, 0, time.UTC),
|
||||
dur != time.Duration(65)*time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDDazEmptyTime(t *testing.T) {
|
||||
body := `Event-Name: RE_SCHEDULE
|
||||
Core-UUID: 792e181c-b6e6-499c-82a1-52a778e7d82d
|
||||
FreeSWITCH-Hostname: h1.ip-switch.net
|
||||
FreeSWITCH-Switchname: h1.ip-switch.net
|
||||
FreeSWITCH-IPv4: 88.198.12.156
|
||||
Caller-Channel-Created-Time: 0
|
||||
Caller-Channel-Answered-Time
|
||||
Task-Runtime: 1349437318`
|
||||
var nilTime time.Time
|
||||
ev := new(FSEvent).New(body)
|
||||
if setupTime, err := ev.GetSetupTime(""); err != nil {
|
||||
t.Error("Error when parsing empty setupTime")
|
||||
} else if setupTime != nilTime {
|
||||
t.Error("Expecting nil time, got: ", setupTime)
|
||||
}
|
||||
if answerTime, err := ev.GetAnswerTime(""); err != nil {
|
||||
t.Error("Error when parsing empty setupTime")
|
||||
} else if answerTime != nilTime {
|
||||
t.Error("Expecting nil time, got: ", answerTime)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseFsHangup(t *testing.T) {
|
||||
hangupEv := `Event-Name: CHANNEL_HANGUP_COMPLETE
|
||||
var hangupEv string = `Event-Name: CHANNEL_HANGUP_COMPLETE
|
||||
Core-UUID: bb890f9e-0aae-476d-8292-91b434eb4f73
|
||||
FreeSWITCH-Hostname: iPBXDev
|
||||
FreeSWITCH-Switchname: iPBXDev
|
||||
@@ -469,6 +338,138 @@ variable_rtp_audio_out_cng_packet_count: 0
|
||||
variable_rtp_audio_rtcp_packet_count: 0
|
||||
variable_rtp_audio_rtcp_octet_count: 0
|
||||
`
|
||||
|
||||
func TestEventCreation(t *testing.T) {
|
||||
body := `Event-Name: RE_SCHEDULE
|
||||
Core-UUID: 792e181c-b6e6-499c-82a1-52a778e7d82d
|
||||
FreeSWITCH-Hostname: h1.ip-switch.net
|
||||
FreeSWITCH-Switchname: h1.ip-switch.net
|
||||
FreeSWITCH-IPv4: 88.198.12.156
|
||||
FreeSWITCH-IPv6: %3A%3A1
|
||||
Event-Date-Local: 2012-10-05%2013%3A41%3A38
|
||||
Event-Date-GMT: Fri,%2005%20Oct%202012%2011%3A41%3A38%20GMT
|
||||
Event-Date-Timestamp: 1349437298012866
|
||||
Event-Calling-File: switch_scheduler.c
|
||||
Event-Calling-Function: switch_scheduler_execute
|
||||
Event-Calling-Line-Number: 65
|
||||
Event-Sequence: 34263
|
||||
Task-ID: 2
|
||||
Task-Desc: heartbeat
|
||||
Task-Group: core
|
||||
Task-Runtime: 1349437318`
|
||||
ev := new(FSEvent).New(body)
|
||||
if ev.GetName() != "RE_SCHEDULE" {
|
||||
t.Error("Event not parsed correctly: ", ev)
|
||||
}
|
||||
l := len(ev.(FSEvent))
|
||||
if l != 17 {
|
||||
t.Error("Incorrect number of event fields: ", l)
|
||||
}
|
||||
}
|
||||
|
||||
// Detects if any of the parsers do not return static values
|
||||
func TestEventParseStatic(t *testing.T) {
|
||||
ev := new(FSEvent).New("")
|
||||
setupTime, _ := ev.GetSetupTime("^2013-12-07 08:42:24")
|
||||
answerTime, _ := ev.GetAnswerTime("^2013-12-07 08:42:24")
|
||||
dur, _ := ev.GetDuration("^60s")
|
||||
if ev.GetReqType("^test") != "test" ||
|
||||
ev.GetDirection("^test") != "test" ||
|
||||
ev.GetTenant("^test") != "test" ||
|
||||
ev.GetCategory("^test") != "test" ||
|
||||
ev.GetAccount("^test") != "test" ||
|
||||
ev.GetSubject("^test") != "test" ||
|
||||
ev.GetDestination("^test") != "test" ||
|
||||
setupTime != time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC) ||
|
||||
answerTime != time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC) ||
|
||||
dur != time.Duration(60)*time.Second {
|
||||
t.Error("Values out of static not matching",
|
||||
ev.GetReqType("^test") != "test",
|
||||
ev.GetDirection("^test") != "test",
|
||||
ev.GetTenant("^test") != "test",
|
||||
ev.GetCategory("^test") != "test",
|
||||
ev.GetAccount("^test") != "test",
|
||||
ev.GetSubject("^test") != "test",
|
||||
ev.GetDestination("^test") != "test",
|
||||
setupTime != time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC),
|
||||
answerTime != time.Date(2013, 12, 7, 8, 42, 24, 0, time.UTC),
|
||||
dur != time.Duration(60)*time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
// Test here if the answer is selected out of headers we specify, even if not default defined
|
||||
func TestEventSelectiveHeaders(t *testing.T) {
|
||||
body := `Event-Name: RE_SCHEDULE
|
||||
Core-UUID: 792e181c-b6e6-499c-82a1-52a778e7d82d
|
||||
FreeSWITCH-Hostname: h1.ip-switch.net
|
||||
FreeSWITCH-Switchname: h1.ip-switch.net
|
||||
FreeSWITCH-IPv4: 88.198.12.156
|
||||
FreeSWITCH-IPv6: %3A%3A1
|
||||
Event-Date-Local: 2012-10-05%2013%3A41%3A38
|
||||
Event-Date-GMT: Fri,%2005%20Oct%202012%2011%3A41%3A38%20GMT
|
||||
Event-Date-Timestamp: 1349437298012866
|
||||
Event-Calling-File: switch_scheduler.c
|
||||
Event-Calling-Function: switch_scheduler_execute
|
||||
Event-Calling-Line-Number: 65
|
||||
Event-Sequence: 34263
|
||||
Task-ID: 2
|
||||
Task-Desc: heartbeat
|
||||
Task-Group: core
|
||||
Task-Runtime: 1349437318`
|
||||
cfg, _ = config.NewDefaultCGRConfig()
|
||||
config.SetCgrConfig(cfg)
|
||||
ev := new(FSEvent).New(body)
|
||||
setupTime, _ := ev.GetSetupTime("Event-Date-Local")
|
||||
answerTime, _ := ev.GetAnswerTime("Event-Date-Local")
|
||||
dur, _ := ev.GetDuration("Event-Calling-Line-Number")
|
||||
if ev.GetReqType("FreeSWITCH-Hostname") != "h1.ip-switch.net" ||
|
||||
ev.GetDirection("FreeSWITCH-Hostname") != "*out" ||
|
||||
ev.GetTenant("FreeSWITCH-Hostname") != "h1.ip-switch.net" ||
|
||||
ev.GetCategory("FreeSWITCH-Hostname") != "h1.ip-switch.net" ||
|
||||
ev.GetAccount("FreeSWITCH-Hostname") != "h1.ip-switch.net" ||
|
||||
ev.GetSubject("FreeSWITCH-Hostname") != "h1.ip-switch.net" ||
|
||||
ev.GetDestination("FreeSWITCH-Hostname") != "h1.ip-switch.net" ||
|
||||
setupTime != time.Date(2012, 10, 5, 13, 41, 38, 0, time.UTC) ||
|
||||
answerTime != time.Date(2012, 10, 5, 13, 41, 38, 0, time.UTC) ||
|
||||
dur != time.Duration(65)*time.Second {
|
||||
t.Error("Values out of static not matching",
|
||||
ev.GetReqType("FreeSWITCH-Hostname") != "h1.ip-switch.net",
|
||||
ev.GetDirection("FreeSWITCH-Hostname") != "*out",
|
||||
ev.GetTenant("FreeSWITCH-Hostname") != "h1.ip-switch.net",
|
||||
ev.GetCategory("FreeSWITCH-Hostname") != "h1.ip-switch.net",
|
||||
ev.GetAccount("FreeSWITCH-Hostname") != "h1.ip-switch.net",
|
||||
ev.GetSubject("FreeSWITCH-Hostname") != "h1.ip-switch.net",
|
||||
ev.GetDestination("FreeSWITCH-Hostname") != "h1.ip-switch.net",
|
||||
setupTime != time.Date(2012, 10, 5, 13, 41, 38, 0, time.UTC),
|
||||
answerTime != time.Date(2012, 10, 5, 13, 41, 38, 0, time.UTC),
|
||||
dur != time.Duration(65)*time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDDazEmptyTime(t *testing.T) {
|
||||
body := `Event-Name: RE_SCHEDULE
|
||||
Core-UUID: 792e181c-b6e6-499c-82a1-52a778e7d82d
|
||||
FreeSWITCH-Hostname: h1.ip-switch.net
|
||||
FreeSWITCH-Switchname: h1.ip-switch.net
|
||||
FreeSWITCH-IPv4: 88.198.12.156
|
||||
Caller-Channel-Created-Time: 0
|
||||
Caller-Channel-Answered-Time
|
||||
Task-Runtime: 1349437318`
|
||||
var nilTime time.Time
|
||||
ev := new(FSEvent).New(body)
|
||||
if setupTime, err := ev.GetSetupTime(""); err != nil {
|
||||
t.Error("Error when parsing empty setupTime")
|
||||
} else if setupTime != nilTime {
|
||||
t.Error("Expecting nil time, got: ", setupTime)
|
||||
}
|
||||
if answerTime, err := ev.GetAnswerTime(""); err != nil {
|
||||
t.Error("Error when parsing empty setupTime")
|
||||
} else if answerTime != nilTime {
|
||||
t.Error("Expecting nil time, got: ", answerTime)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseFsHangup(t *testing.T) {
|
||||
cfg, _ = config.NewDefaultCGRConfig()
|
||||
config.SetCgrConfig(cfg)
|
||||
ev := new(FSEvent).New(hangupEv)
|
||||
@@ -498,3 +499,63 @@ variable_rtp_audio_rtcp_octet_count: 0
|
||||
dur != time.Duration(5)*time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseEventValue(t *testing.T) {
|
||||
cfg, _ = config.NewDefaultCGRConfig()
|
||||
config.SetCgrConfig(cfg)
|
||||
ev := new(FSEvent).New(hangupEv)
|
||||
if cgrid := ev.ParseEventValue(&utils.RSRField{Id: utils.CGRID}); cgrid != "8b1ca78a9bbaa42c811e60b974188197c425dbe7" {
|
||||
t.Error("Unexpected cgrid parsed", cgrid)
|
||||
}
|
||||
if tor := ev.ParseEventValue(&utils.RSRField{Id: utils.TOR}); tor != utils.VOICE {
|
||||
t.Error("Unexpected tor parsed", tor)
|
||||
}
|
||||
if accid := ev.ParseEventValue(&utils.RSRField{Id: utils.ACCID}); accid != "37e9b766-5256-4e4b-b1ed-3767b930fec8" {
|
||||
t.Error("Unexpected result parsed", accid)
|
||||
}
|
||||
if parsed := ev.ParseEventValue(&utils.RSRField{Id: utils.CDRHOST}); parsed != "10.0.2.15" {
|
||||
t.Error("Unexpected result parsed", parsed)
|
||||
}
|
||||
if parsed := ev.ParseEventValue(&utils.RSRField{Id: utils.CDRSOURCE}); parsed != "FS_EVENT" {
|
||||
t.Error("Unexpected result parsed", parsed)
|
||||
}
|
||||
if parsed := ev.ParseEventValue(&utils.RSRField{Id: utils.REQTYPE}); parsed != utils.PSEUDOPREPAID {
|
||||
t.Error("Unexpected result parsed", parsed)
|
||||
}
|
||||
if parsed := ev.ParseEventValue(&utils.RSRField{Id: utils.DIRECTION}); parsed != utils.OUT {
|
||||
t.Error("Unexpected result parsed", parsed)
|
||||
}
|
||||
if parsed := ev.ParseEventValue(&utils.RSRField{Id: utils.TENANT}); parsed != "cgrates.org" {
|
||||
t.Error("Unexpected result parsed", parsed)
|
||||
}
|
||||
if parsed := ev.ParseEventValue(&utils.RSRField{Id: utils.CATEGORY}); parsed != "call" {
|
||||
t.Error("Unexpected result parsed", parsed)
|
||||
}
|
||||
if parsed := ev.ParseEventValue(&utils.RSRField{Id: utils.ACCOUNT}); parsed != "1003" {
|
||||
t.Error("Unexpected result parsed", parsed)
|
||||
}
|
||||
if parsed := ev.ParseEventValue(&utils.RSRField{Id: utils.SUBJECT}); parsed != "1003" {
|
||||
t.Error("Unexpected result parsed", parsed)
|
||||
}
|
||||
if parsed := ev.ParseEventValue(&utils.RSRField{Id: utils.DESTINATION}); parsed != "1002" {
|
||||
t.Error("Unexpected result parsed", parsed)
|
||||
}
|
||||
if parsed := ev.ParseEventValue(&utils.RSRField{Id: utils.SETUP_TIME}); parsed != "2014-04-25 18:08:27 +0200 CEST" {
|
||||
t.Error("Unexpected result parsed", parsed)
|
||||
}
|
||||
if parsed := ev.ParseEventValue(&utils.RSRField{Id: utils.ANSWER_TIME}); parsed != "2014-04-25 18:08:40 +0200 CEST" {
|
||||
t.Error("Unexpected result parsed", parsed)
|
||||
}
|
||||
if parsed := ev.ParseEventValue(&utils.RSRField{Id: utils.USAGE}); parsed != "5000000000" {
|
||||
t.Error("Unexpected result parsed", parsed)
|
||||
}
|
||||
if parsed := ev.ParseEventValue(&utils.RSRField{Id: utils.MEDI_RUNID}); parsed != utils.DEFAULT_RUNID {
|
||||
t.Error("Unexpected result parsed", parsed)
|
||||
}
|
||||
if parsed := ev.ParseEventValue(&utils.RSRField{Id: utils.COST}); parsed != "-1" {
|
||||
t.Error("Unexpected result parsed", parsed)
|
||||
}
|
||||
if parsed := ev.ParseEventValue(&utils.RSRField{Id: "Hangup-Cause"}); parsed != "NORMAL_CLEARING" {
|
||||
t.Error("Unexpected result parsed", parsed)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,6 +161,10 @@ func (sm *FSSessionManager) OnChannelPark(ev Event) {
|
||||
}
|
||||
dcs, _ = dcs.AppendDefaultRun()
|
||||
for _, dc := range dcs {
|
||||
dcRunFilter, _ := utils.NewRSRField(dc.RunFilter)
|
||||
if dcRunFilter != nil && ev.ParseEventValue(&utils.RSRField{Id: dcRunFilter.Id}) != ev.ParseEventValue(dcRunFilter) {
|
||||
engine.Logger.Info(fmt.Sprintf("Ignoring DerivedCharger with id %s due to non matching filter", dc.RunId))
|
||||
}
|
||||
startTime, err := ev.GetAnswerTime(PARK_TIME)
|
||||
if err != nil {
|
||||
engine.Logger.Err("Error parsing answer event start time, using time.Now!")
|
||||
|
||||
@@ -24,67 +24,75 @@ import (
|
||||
)
|
||||
|
||||
// Wraps regexp compiling in case of rsr fields
|
||||
func NewDerivedCharger(runId, reqTypeFld, dirFld, tenantFld, catFld, acntFld, subjFld, dstFld, sTimeFld, aTimeFld, durFld string) (dc *DerivedCharger, err error) {
|
||||
func NewDerivedCharger(runId, runFilter, reqTypeFld, dirFld, tenantFld, catFld, acntFld, subjFld, dstFld, sTimeFld, aTimeFld, durFld string) (dc *DerivedCharger, err error) {
|
||||
if len(runId) == 0 {
|
||||
return nil, errors.New("Empty run id field")
|
||||
}
|
||||
dc = &DerivedCharger{RunId: runId}
|
||||
dc.RunFilter = runFilter
|
||||
if strings.HasPrefix(dc.RunFilter, REGEXP_PREFIX) || strings.HasPrefix(dc.RunFilter, STATIC_VALUE_PREFIX) {
|
||||
if dc.rsrRunFilter, err = NewRSRField(dc.RunFilter); err != nil {
|
||||
return nil, err
|
||||
} else if len(dc.rsrRunFilter.Id) == 0 {
|
||||
return nil, errors.New("Empty filter header.")
|
||||
}
|
||||
}
|
||||
dc.ReqTypeField = reqTypeFld
|
||||
if strings.HasPrefix(dc.ReqTypeField, REGEXP_PREFIX) {
|
||||
if strings.HasPrefix(dc.ReqTypeField, REGEXP_PREFIX) || strings.HasPrefix(dc.RunFilter, STATIC_VALUE_PREFIX) {
|
||||
if dc.rsrReqTypeField, err = NewRSRField(dc.ReqTypeField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.DirectionField = dirFld
|
||||
if strings.HasPrefix(dc.DirectionField, REGEXP_PREFIX) {
|
||||
if strings.HasPrefix(dc.DirectionField, REGEXP_PREFIX) || strings.HasPrefix(dc.RunFilter, STATIC_VALUE_PREFIX) {
|
||||
if dc.rsrDirectionField, err = NewRSRField(dc.DirectionField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.TenantField = tenantFld
|
||||
if strings.HasPrefix(dc.TenantField, REGEXP_PREFIX) {
|
||||
if strings.HasPrefix(dc.TenantField, REGEXP_PREFIX) || strings.HasPrefix(dc.RunFilter, STATIC_VALUE_PREFIX) {
|
||||
if dc.rsrTenantField, err = NewRSRField(dc.TenantField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.CategoryField = catFld
|
||||
if strings.HasPrefix(dc.CategoryField, REGEXP_PREFIX) {
|
||||
if strings.HasPrefix(dc.CategoryField, REGEXP_PREFIX) || strings.HasPrefix(dc.RunFilter, STATIC_VALUE_PREFIX) {
|
||||
if dc.rsrCategoryField, err = NewRSRField(dc.CategoryField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.AccountField = acntFld
|
||||
if strings.HasPrefix(dc.AccountField, REGEXP_PREFIX) {
|
||||
if strings.HasPrefix(dc.AccountField, REGEXP_PREFIX) || strings.HasPrefix(dc.RunFilter, STATIC_VALUE_PREFIX) {
|
||||
if dc.rsrAccountField, err = NewRSRField(dc.AccountField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.SubjectField = subjFld
|
||||
if strings.HasPrefix(dc.SubjectField, REGEXP_PREFIX) {
|
||||
if strings.HasPrefix(dc.SubjectField, REGEXP_PREFIX) || strings.HasPrefix(dc.RunFilter, STATIC_VALUE_PREFIX) {
|
||||
if dc.rsrSubjectField, err = NewRSRField(dc.SubjectField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.DestinationField = dstFld
|
||||
if strings.HasPrefix(dc.DestinationField, REGEXP_PREFIX) {
|
||||
if strings.HasPrefix(dc.DestinationField, REGEXP_PREFIX) || strings.HasPrefix(dc.RunFilter, STATIC_VALUE_PREFIX) {
|
||||
if dc.rsrDestinationField, err = NewRSRField(dc.DestinationField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.SetupTimeField = sTimeFld
|
||||
if strings.HasPrefix(dc.SetupTimeField, REGEXP_PREFIX) {
|
||||
if strings.HasPrefix(dc.SetupTimeField, REGEXP_PREFIX) || strings.HasPrefix(dc.RunFilter, STATIC_VALUE_PREFIX) {
|
||||
if dc.rsrSetupTimeField, err = NewRSRField(dc.SetupTimeField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.AnswerTimeField = aTimeFld
|
||||
if strings.HasPrefix(dc.AnswerTimeField, REGEXP_PREFIX) {
|
||||
if strings.HasPrefix(dc.AnswerTimeField, REGEXP_PREFIX) || strings.HasPrefix(dc.RunFilter, STATIC_VALUE_PREFIX) {
|
||||
if dc.rsrAnswerTimeField, err = NewRSRField(dc.AnswerTimeField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dc.UsageField = durFld
|
||||
if strings.HasPrefix(dc.UsageField, REGEXP_PREFIX) {
|
||||
if strings.HasPrefix(dc.UsageField, REGEXP_PREFIX) || strings.HasPrefix(dc.RunFilter, STATIC_VALUE_PREFIX) {
|
||||
if dc.rsrUsageField, err = NewRSRField(dc.UsageField); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -94,6 +102,7 @@ func NewDerivedCharger(runId, reqTypeFld, dirFld, tenantFld, catFld, acntFld, su
|
||||
|
||||
type DerivedCharger struct {
|
||||
RunId string // Unique runId in the chain
|
||||
RunFilter string // Only run the charger if the filter matches
|
||||
ReqTypeField string // Field containing request type info, number in case of csv source, '^' as prefix in case of static values
|
||||
DirectionField string // Field containing direction info
|
||||
TenantField string // Field containing tenant info
|
||||
@@ -104,7 +113,8 @@ type DerivedCharger struct {
|
||||
SetupTimeField string // Field containing setup time information
|
||||
AnswerTimeField string // Field containing answer time information
|
||||
UsageField string // Field containing usage information
|
||||
rsrReqTypeField *RSRField // Storage for compiled Regexp in case of RSRFields
|
||||
rsrRunFilter *RSRField // Storage for compiled Regexp in case of RSRFields
|
||||
rsrReqTypeField *RSRField
|
||||
rsrDirectionField *RSRField
|
||||
rsrTenantField *RSRField
|
||||
rsrCategoryField *RSRField
|
||||
@@ -136,7 +146,7 @@ func (dcs DerivedChargers) Append(dc *DerivedCharger) (DerivedChargers, error) {
|
||||
}
|
||||
|
||||
func (dcs DerivedChargers) AppendDefaultRun() (DerivedChargers, error) {
|
||||
dcDf, _ := NewDerivedCharger(DEFAULT_RUNID, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT,
|
||||
dcDf, _ := NewDerivedCharger(DEFAULT_RUNID, "", META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT,
|
||||
META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT, META_DEFAULT)
|
||||
return append(dcs, dcDf), nil
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ func TestAppendDerivedChargers(t *testing.T) {
|
||||
func TestNewDerivedCharger(t *testing.T) {
|
||||
edc1 := &DerivedCharger{
|
||||
RunId: "test1",
|
||||
RunFilter: "",
|
||||
ReqTypeField: "reqtype1",
|
||||
DirectionField: "direction1",
|
||||
TenantField: "tenant1",
|
||||
@@ -58,7 +59,7 @@ func TestNewDerivedCharger(t *testing.T) {
|
||||
AnswerTimeField: "answertime1",
|
||||
UsageField: "duration1",
|
||||
}
|
||||
if dc1, err := NewDerivedCharger("test1", "reqtype1", "direction1", "tenant1", "tor1", "account1", "subject1", "destination1",
|
||||
if dc1, err := NewDerivedCharger("test1", "", "reqtype1", "direction1", "tenant1", "tor1", "account1", "subject1", "destination1",
|
||||
"setuptime1", "answertime1", "duration1"); err != nil {
|
||||
t.Error("Unexpected error", err.Error)
|
||||
} else if !reflect.DeepEqual(edc1, dc1) {
|
||||
@@ -66,6 +67,7 @@ func TestNewDerivedCharger(t *testing.T) {
|
||||
}
|
||||
edc2 := &DerivedCharger{
|
||||
RunId: "test2",
|
||||
RunFilter: "^cdr_source/tdm_cdrs",
|
||||
ReqTypeField: "~reqtype2:s/sip:(.+)/$1/",
|
||||
DirectionField: "~direction2:s/sip:(.+)/$1/",
|
||||
TenantField: "~tenant2:s/sip:(.+)/$1/",
|
||||
@@ -77,6 +79,7 @@ func TestNewDerivedCharger(t *testing.T) {
|
||||
AnswerTimeField: "~answertime2:s/sip:(.+)/$1/",
|
||||
UsageField: "~duration2:s/sip:(.+)/$1/",
|
||||
}
|
||||
edc2.rsrRunFilter, _ = NewRSRField("^cdr_source/tdm_cdrs")
|
||||
edc2.rsrReqTypeField, _ = NewRSRField("~reqtype2:s/sip:(.+)/$1/")
|
||||
edc2.rsrDirectionField, _ = NewRSRField("~direction2:s/sip:(.+)/$1/")
|
||||
edc2.rsrTenantField, _ = NewRSRField("~tenant2:s/sip:(.+)/$1/")
|
||||
@@ -88,6 +91,7 @@ func TestNewDerivedCharger(t *testing.T) {
|
||||
edc2.rsrAnswerTimeField, _ = NewRSRField("~answertime2:s/sip:(.+)/$1/")
|
||||
edc2.rsrUsageField, _ = NewRSRField("~duration2:s/sip:(.+)/$1/")
|
||||
if dc2, err := NewDerivedCharger("test2",
|
||||
"^cdr_source/tdm_cdrs",
|
||||
"~reqtype2:s/sip:(.+)/$1/",
|
||||
"~direction2:s/sip:(.+)/$1/",
|
||||
"~tenant2:s/sip:(.+)/$1/",
|
||||
@@ -112,7 +116,7 @@ func TestDerivedChargersKey(t *testing.T) {
|
||||
|
||||
func TestAppendDefaultRun(t *testing.T) {
|
||||
var dc1 DerivedChargers
|
||||
dcDf := &DerivedCharger{RunId: DEFAULT_RUNID, ReqTypeField: META_DEFAULT, DirectionField: META_DEFAULT,
|
||||
dcDf := &DerivedCharger{RunId: DEFAULT_RUNID, RunFilter: "", ReqTypeField: META_DEFAULT, DirectionField: META_DEFAULT,
|
||||
TenantField: META_DEFAULT, CategoryField: META_DEFAULT, AccountField: META_DEFAULT, SubjectField: META_DEFAULT,
|
||||
DestinationField: META_DEFAULT, SetupTimeField: META_DEFAULT, AnswerTimeField: META_DEFAULT, UsageField: META_DEFAULT}
|
||||
eDc1 := DerivedChargers{dcDf}
|
||||
@@ -120,7 +124,7 @@ func TestAppendDefaultRun(t *testing.T) {
|
||||
t.Error("Unexpected result.")
|
||||
}
|
||||
dc2 := DerivedChargers{
|
||||
&DerivedCharger{RunId: "extra1", ReqTypeField: "^prepaid", DirectionField: "*default", TenantField: "*default", CategoryField: "*default",
|
||||
&DerivedCharger{RunId: "extra1", RunFilter: "", ReqTypeField: "reqtype2", DirectionField: "*default", TenantField: "*default", CategoryField: "*default",
|
||||
AccountField: "rif", SubjectField: "rif", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"},
|
||||
&DerivedCharger{RunId: "extra2", ReqTypeField: "*default", DirectionField: "*default", TenantField: "*default", CategoryField: "*default",
|
||||
AccountField: "ivo", SubjectField: "ivo", DestinationField: "*default", SetupTimeField: "*default", AnswerTimeField: "*default", UsageField: "*default"},
|
||||
|
||||
Reference in New Issue
Block a user