mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-21 07:08:45 +05:00
Add XML to EventReader and test for it
This commit is contained in:
96
cdrc/xml.go
96
cdrc/xml.go
@@ -23,8 +23,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -34,17 +32,6 @@ import (
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
// getElementText will process the node to extract the elementName's text out of it (only first one found)
|
||||
// returns utils.ErrNotFound if the element is not found in the node
|
||||
func elementText(xmlElement *xmlquery.Node, elmntPath string) (string, error) {
|
||||
elmnt := xmlquery.FindOne(xmlElement, elmntPath)
|
||||
if elmnt == nil {
|
||||
return "", utils.ErrNotFound
|
||||
}
|
||||
return elmnt.InnerText(), nil
|
||||
|
||||
}
|
||||
|
||||
// handlerUsageDiff will calculate the usage as difference between timeEnd and timeStart
|
||||
// Expects the 2 arguments in template separated by |
|
||||
func handlerSubstractUsage(xmlElement *xmlquery.Node, argsTpl config.RSRParsers,
|
||||
@@ -57,7 +44,7 @@ func handlerSubstractUsage(xmlElement *xmlquery.Node, argsTpl config.RSRParsers,
|
||||
}
|
||||
absolutePath := utils.ParseHierarchyPath(rsrArg.Rules, "")
|
||||
relPath := utils.HierarchyPath(absolutePath[len(cdrPath)+1:]) // Need relative path to the xmlElmnt
|
||||
argStr, _ := elementText(xmlElement, relPath.AsString("/", false))
|
||||
argStr, _ := config.ElementText(xmlElement, relPath.AsString("/", false))
|
||||
argsStr += argStr
|
||||
}
|
||||
handlerArgs := strings.Split(argsStr, utils.HandlerArgSep)
|
||||
@@ -116,7 +103,7 @@ func (xmlProc *XMLRecordsProcessor) ProcessNextRecord() (cdrs []*engine.CDR, err
|
||||
cdrs = make([]*engine.CDR, 0)
|
||||
cdrXML := xmlProc.cdrXmlElmts[xmlProc.procItems]
|
||||
xmlProc.procItems += 1
|
||||
xmlProvider := newXmlProvider(cdrXML, xmlProc.cdrPath)
|
||||
xmlProvider := config.NewXmlProvider(cdrXML, xmlProc.cdrPath, utils.MetaReq)
|
||||
for _, cdrcCfg := range xmlProc.cdrcCfgs {
|
||||
tenant, err := cdrcCfg.Tenant.ParseDataProvider(xmlProvider, utils.NestingSep)
|
||||
if err != nil {
|
||||
@@ -148,7 +135,7 @@ func (xmlProc *XMLRecordsProcessor) recordToCDR(xmlEntity *xmlquery.Node, cdrcCf
|
||||
var lazyHttpFields []*config.FCTemplate
|
||||
var err error
|
||||
fldVals := make(map[string]string)
|
||||
xmlProvider := newXmlProvider(xmlEntity, xmlProc.cdrPath)
|
||||
xmlProvider := config.NewXmlProvider(xmlEntity, xmlProc.cdrPath, utils.MetaReq)
|
||||
for _, cdrFldCfg := range cdrcCfg.ContentFields {
|
||||
if len(cdrFldCfg.Filters) != 0 {
|
||||
if pass, err := xmlProc.filterS.Pass(tenant,
|
||||
@@ -207,80 +194,3 @@ func (xmlProc *XMLRecordsProcessor) recordToCDR(xmlEntity *xmlquery.Node, cdrcCf
|
||||
}
|
||||
return cdr, nil
|
||||
}
|
||||
|
||||
// newXmlProvider constructs a DataProvider
|
||||
func newXmlProvider(req *xmlquery.Node, cdrPath utils.HierarchyPath) (dP config.DataProvider) {
|
||||
dP = &xmlProvider{req: req, cdrPath: cdrPath, cache: config.NewNavigableMap(nil)}
|
||||
return
|
||||
}
|
||||
|
||||
// xmlProvider implements engine.DataProvider so we can pass it to filters
|
||||
type xmlProvider struct {
|
||||
req *xmlquery.Node
|
||||
cdrPath utils.HierarchyPath //used to compute relative path
|
||||
cache *config.NavigableMap
|
||||
}
|
||||
|
||||
// String is part of engine.DataProvider interface
|
||||
// when called, it will display the already parsed values out of cache
|
||||
func (xP *xmlProvider) String() string {
|
||||
return utils.ToJSON(xP)
|
||||
}
|
||||
|
||||
// FieldAsInterface is part of engine.DataProvider interface
|
||||
func (xP *xmlProvider) FieldAsInterface(fldPath []string) (data interface{}, err error) {
|
||||
if len(fldPath) == 0 {
|
||||
return nil, utils.ErrNotFound
|
||||
}
|
||||
if fldPath[0] != utils.MetaReq {
|
||||
return "", utils.ErrPrefixNotFound(strings.Join(fldPath, utils.NestingSep))
|
||||
}
|
||||
if data, err = xP.cache.FieldAsInterface(fldPath); err == nil ||
|
||||
err != utils.ErrNotFound { // item found in cache
|
||||
return
|
||||
}
|
||||
err = nil // cancel previous err
|
||||
relPath := utils.HierarchyPath(fldPath[len(xP.cdrPath)+1:]) // Need relative path to the xmlElmnt
|
||||
var slctrStr string
|
||||
for i := range relPath {
|
||||
if sIdx := strings.Index(relPath[i], "["); sIdx != -1 {
|
||||
slctrStr = relPath[i][sIdx:]
|
||||
if slctrStr[len(slctrStr)-1:] != "]" {
|
||||
return nil, fmt.Errorf("filter rule <%s> needs to end in ]", slctrStr)
|
||||
}
|
||||
relPath[i] = relPath[i][:sIdx]
|
||||
if slctrStr[1:2] != "@" {
|
||||
i, err := strconv.Atoi(slctrStr[1 : len(slctrStr)-1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
slctrStr = "[" + strconv.Itoa(i+1) + "]"
|
||||
}
|
||||
relPath[i] = relPath[i] + slctrStr
|
||||
}
|
||||
}
|
||||
data, err = elementText(xP.req, relPath.AsString("/", false))
|
||||
xP.cache.Set(fldPath, data, false, false)
|
||||
return
|
||||
}
|
||||
|
||||
// FieldAsString is part of engine.DataProvider interface
|
||||
func (xP *xmlProvider) FieldAsString(fldPath []string) (data string, err error) {
|
||||
var valIface interface{}
|
||||
valIface, err = xP.FieldAsInterface(fldPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return utils.IfaceAsString(valIface), nil
|
||||
}
|
||||
|
||||
// AsNavigableMap is part of engine.DataProvider interface
|
||||
func (xP *xmlProvider) AsNavigableMap([]*config.FCTemplate) (
|
||||
nm *config.NavigableMap, err error) {
|
||||
return nil, utils.ErrNotImplemented
|
||||
}
|
||||
|
||||
// RemoteHost is part of engine.DataProvider interface
|
||||
func (xP *xmlProvider) RemoteHost() net.Addr {
|
||||
return utils.LocalAddr()
|
||||
}
|
||||
|
||||
@@ -132,7 +132,6 @@ func TestXmlITAnalyseCDRs(t *testing.T) {
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestXmlITKillEngine(t *testing.T) {
|
||||
|
||||
146
cdrc/xml_test.go
146
cdrc/xml_test.go
@@ -166,28 +166,40 @@ var cdrXmlBroadsoft = `<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
</cdrData>
|
||||
</broadWorksCDR>`
|
||||
|
||||
func TestXMLElementText(t *testing.T) {
|
||||
doc, err := xmlquery.Parse(strings.NewReader(cdrXmlBroadsoft))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
cdrs := xmlquery.Find(doc, path.Join("/broadWorksCDR/cdrData/"))
|
||||
cdrWithoutUserNr := cdrs[0]
|
||||
if _, err := elementText(cdrWithoutUserNr, "basicModule/userNumber"); err != utils.ErrNotFound {
|
||||
t.Error(err)
|
||||
}
|
||||
cdrWithUser := cdrs[1]
|
||||
if val, err := elementText(cdrWithUser, "basicModule/userNumber"); err != nil {
|
||||
t.Error(err)
|
||||
} else if val != "1001" {
|
||||
t.Errorf("Expecting: 1001, received: %s", val)
|
||||
}
|
||||
if val, err := elementText(cdrWithUser, "centrexModule/locationList/locationInformation/locationType"); err != nil {
|
||||
t.Error(err)
|
||||
} else if val != "Primary Device" {
|
||||
t.Errorf("Expecting: <Primary Device>, received: <%s>", val)
|
||||
}
|
||||
}
|
||||
var xmlMultipleIndex = `<complete-success-notification callid="109870">
|
||||
<createtime>2005-08-26T14:16:42</createtime>
|
||||
<connecttime>2005-08-26T14:16:56</connecttime>
|
||||
<endtime>2005-08-26T14:17:34</endtime>
|
||||
<reference>My Call Reference</reference>
|
||||
<userid>386</userid>
|
||||
<username>sampleusername</username>
|
||||
<customerid>1</customerid>
|
||||
<companyname>Conecto LLC</companyname>
|
||||
<totalcost amount="0.21" currency="USD">US$0.21</totalcost>
|
||||
<hasrecording>yes</hasrecording>
|
||||
<hasvoicemail>no</hasvoicemail>
|
||||
<agenttotalcost amount="0.13" currency="USD">US$0.13</agenttotalcost>
|
||||
<agentid>44</agentid>
|
||||
<callleg calllegid="222146">
|
||||
<number>+441624828505</number>
|
||||
<description>Isle of Man</description>
|
||||
<seconds>38</seconds>
|
||||
<perminuterate amount="0.0200" currency="USD">US$0.0200</perminuterate>
|
||||
<cost amount="0.0140" currency="USD">US$0.0140</cost>
|
||||
<agentperminuterate amount="0.0130" currency="USD">US$0.0130</agentperminuterate>
|
||||
<agentcost amount="0.0082" currency="USD">US$0.0082</agentcost>
|
||||
</callleg>
|
||||
<callleg calllegid="222147">
|
||||
<number>+44 7624 494075</number>
|
||||
<description>Isle of Man</description>
|
||||
<seconds>37</seconds>
|
||||
<perminuterate amount="0.2700" currency="USD">US$0.2700</perminuterate>
|
||||
<cost amount="0.1890" currency="USD">US$0.1890</cost>
|
||||
<agentperminuterate amount="0.1880" currency="USD">US$0.1880</agentperminuterate>
|
||||
<agentcost amount="0.1159" currency="USD">US$0.1159</agentcost>
|
||||
</callleg>
|
||||
</complete-success-notification>
|
||||
`
|
||||
|
||||
func TestXMLHandlerSubstractUsage(t *testing.T) {
|
||||
doc, err := xmlquery.Parse(strings.NewReader(cdrXmlBroadsoft))
|
||||
@@ -525,28 +537,6 @@ var xmlContent = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
</File>
|
||||
`
|
||||
|
||||
func TestXMLElementText3(t *testing.T) {
|
||||
doc, err := xmlquery.Parse(strings.NewReader(xmlContent))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
hPath2 := utils.ParseHierarchyPath("File.CDRs.Call", "")
|
||||
cdrs := xmlquery.Find(doc, hPath2.AsString("/", true))
|
||||
if len(cdrs) != 3 {
|
||||
t.Errorf("Expecting: 3, received: %+v", len(cdrs))
|
||||
}
|
||||
|
||||
if _, err := elementText(cdrs[0], "SignalingInfo/PChargingVector/test"); err != utils.ErrNotFound {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if val, err := elementText(cdrs[1], "SignalingInfo/PChargingVector/icidvalue"); err != nil {
|
||||
t.Error(err)
|
||||
} else if val != "46d7974398c2671016afccc3f2c428c7" {
|
||||
t.Errorf("Expecting: 46d7974398c2671016afccc3f2c428c7, received: %s", val)
|
||||
}
|
||||
}
|
||||
|
||||
func TestXMLRPNestingSeparator(t *testing.T) {
|
||||
cdrcCfgs := []*config.CdrcCfg{
|
||||
{
|
||||
@@ -627,71 +617,3 @@ func TestXMLRPNestingSeparator(t *testing.T) {
|
||||
t.Errorf("Expecting: %+v\n, received: %+v\n", expectedCDRs, cdrs)
|
||||
}
|
||||
}
|
||||
|
||||
var xmlMultipleIndex = `<complete-success-notification callid="109870">
|
||||
<createtime>2005-08-26T14:16:42</createtime>
|
||||
<connecttime>2005-08-26T14:16:56</connecttime>
|
||||
<endtime>2005-08-26T14:17:34</endtime>
|
||||
<reference>My Call Reference</reference>
|
||||
<userid>386</userid>
|
||||
<username>sampleusername</username>
|
||||
<customerid>1</customerid>
|
||||
<companyname>Conecto LLC</companyname>
|
||||
<totalcost amount="0.21" currency="USD">US$0.21</totalcost>
|
||||
<hasrecording>yes</hasrecording>
|
||||
<hasvoicemail>no</hasvoicemail>
|
||||
<agenttotalcost amount="0.13" currency="USD">US$0.13</agenttotalcost>
|
||||
<agentid>44</agentid>
|
||||
<callleg calllegid="222146">
|
||||
<number>+441624828505</number>
|
||||
<description>Isle of Man</description>
|
||||
<seconds>38</seconds>
|
||||
<perminuterate amount="0.0200" currency="USD">US$0.0200</perminuterate>
|
||||
<cost amount="0.0140" currency="USD">US$0.0140</cost>
|
||||
<agentperminuterate amount="0.0130" currency="USD">US$0.0130</agentperminuterate>
|
||||
<agentcost amount="0.0082" currency="USD">US$0.0082</agentcost>
|
||||
</callleg>
|
||||
<callleg calllegid="222147">
|
||||
<number>+44 7624 494075</number>
|
||||
<description>Isle of Man</description>
|
||||
<seconds>37</seconds>
|
||||
<perminuterate amount="0.2700" currency="USD">US$0.2700</perminuterate>
|
||||
<cost amount="0.1890" currency="USD">US$0.1890</cost>
|
||||
<agentperminuterate amount="0.1880" currency="USD">US$0.1880</agentperminuterate>
|
||||
<agentcost amount="0.1159" currency="USD">US$0.1159</agentcost>
|
||||
</callleg>
|
||||
</complete-success-notification>
|
||||
`
|
||||
|
||||
func TestXMLIndexes(t *testing.T) {
|
||||
doc, err := xmlquery.Parse(strings.NewReader(xmlMultipleIndex))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
dP := newXmlProvider(doc, utils.HierarchyPath([]string{}))
|
||||
if data, err := dP.FieldAsString([]string{"*req", "complete-success-notification", "userid"}); err != nil {
|
||||
t.Error(err)
|
||||
} else if data != "386" {
|
||||
t.Errorf("expecting: 386, received: <%s>", data)
|
||||
}
|
||||
if data, err := dP.FieldAsString([]string{"*req", "complete-success-notification", "username"}); err != nil {
|
||||
t.Error(err)
|
||||
} else if data != "sampleusername" {
|
||||
t.Errorf("expecting: sampleusername, received: <%s>", data)
|
||||
}
|
||||
if data, err := dP.FieldAsString([]string{"*req", "complete-success-notification", "callleg", "seconds"}); err != nil {
|
||||
t.Error(err)
|
||||
} else if data != "38" {
|
||||
t.Errorf("expecting: 38, received: <%s>", data)
|
||||
}
|
||||
if data, err := dP.FieldAsString([]string{"*req", "complete-success-notification", "callleg[1]", "seconds"}); err != nil {
|
||||
t.Error(err)
|
||||
} else if data != "37" {
|
||||
t.Errorf("expecting: 37, received: <%s>", data)
|
||||
}
|
||||
if data, err := dP.FieldAsString([]string{"*req", "complete-success-notification", "callleg[@calllegid='222147']", "seconds"}); err != nil {
|
||||
t.Error(err)
|
||||
} else if data != "37" {
|
||||
t.Errorf("expecting: 37, received: <%s>", data)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user