mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-17 06:09:53 +05:00
Merge branch 'master' into hapool
This commit is contained in:
@@ -92,14 +92,21 @@ func (self DiameterAgent) processCCR(ccr *CCR, reqProcessor *config.DARequestPro
|
||||
err = errCdr
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cca := NewCCAFromCCR(ccr)
|
||||
cca := NewBareCCAFromCCR(ccr)
|
||||
cca.OriginHost = self.cgrCfg.DiameterAgentCfg().OriginHost
|
||||
cca.OriginRealm = self.cgrCfg.DiameterAgentCfg().OriginRealm
|
||||
if err != nil {
|
||||
cca.ResultCode = DiameterRatingFailed
|
||||
utils.Logger.Err(fmt.Sprintf("<DiameterAgent> Processing message: %+v, error: %s", ccr.diamMessage, err))
|
||||
return cca, nil
|
||||
}
|
||||
cca.ResultCode = diam.Success
|
||||
cca.GrantedServiceUnit.CCTime = int(maxUsage)
|
||||
if err := cca.SetProcessorAVPs(reqProcessor); err != nil {
|
||||
cca.ResultCode = DiameterRatingFailed
|
||||
utils.Logger.Err(fmt.Sprintf("<DiameterAgent> Processing message: %+v, error: %s", ccr.diamMessage, err))
|
||||
return cca, nil
|
||||
}
|
||||
return cca, nil
|
||||
}
|
||||
|
||||
@@ -124,11 +131,8 @@ func (self *DiameterAgent) handleCCR(c diam.Conn, m *diam.Message) {
|
||||
utils.Logger.Err(fmt.Sprintf("<DiameterAgent> No request processor enabled for CCR: %+v, ignoring request", ccr))
|
||||
return
|
||||
}
|
||||
if dmtA, err := cca.AsBareDiameterMessage(); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<DiameterAgent> Failed to convert cca as diameter message, error: %s", err.Error()))
|
||||
return
|
||||
} else if _, err := dmtA.WriteTo(c); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<DiameterAgent> Failed to write message to %s: %s\n%s\n", c.RemoteAddr(), err, dmtA))
|
||||
if _, err := cca.AsDiameterMessage().WriteTo(c); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<DiameterAgent> Failed to write message to %s: %s\n%s\n", c.RemoteAddr(), err, cca.AsDiameterMessage()))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
157
agents/libdmt.go
157
agents/libdmt.go
@@ -48,8 +48,9 @@ func init() {
|
||||
}
|
||||
|
||||
const (
|
||||
META_CCR_USAGE = "*ccr_usage"
|
||||
DIAMETER_CCR = "DIAMETER_CCR"
|
||||
META_CCR_USAGE = "*ccr_usage"
|
||||
DIAMETER_CCR = "DIAMETER_CCR"
|
||||
DiameterRatingFailed = 5031
|
||||
)
|
||||
|
||||
func loadDictionaries(dictsDir, componentId string) error {
|
||||
@@ -168,7 +169,7 @@ func avpValAsString(a *diam.AVP) string {
|
||||
}
|
||||
|
||||
// Handler for meta functions
|
||||
func metaHandler(m *diam.Message, tag, arg string, debitInterval time.Duration) (string, error) {
|
||||
func metaHandler(m *diam.Message, tag, arg string, dur time.Duration) (string, error) {
|
||||
switch tag {
|
||||
case META_CCR_USAGE:
|
||||
ccReqTypeAvp, err := m.FindAVP("CC-Request-Type", dict.UndefinedVendorID)
|
||||
@@ -198,7 +199,7 @@ func metaHandler(m *diam.Message, tag, arg string, debitInterval time.Duration)
|
||||
usage := usageFromCCR(int(ccReqTypeAvp.Data.(datatype.Enumerated)),
|
||||
int(ccReqNrAvp.Data.(datatype.Enumerated)),
|
||||
int(reqUnitAVPs[0].Data.(datatype.Unsigned32)),
|
||||
int(usedUnitAVPs[0].Data.(datatype.Unsigned32)), debitInterval)
|
||||
int(usedUnitAVPs[0].Data.(datatype.Unsigned32)), dur)
|
||||
return strconv.FormatFloat(usage.Seconds(), 'f', -1, 64), nil
|
||||
}
|
||||
return "", nil
|
||||
@@ -304,7 +305,8 @@ func fieldOutVal(m *diam.Message, cfgFld *config.CfgCdrField, debitInterval time
|
||||
}
|
||||
|
||||
// messageAddAVPsWithPath will dynamically add AVPs into the message
|
||||
func messageAddAVPsWithPath(m *diam.Message, path []interface{}, avpValByte []byte) error {
|
||||
// append: append to the message, on false overwrite if AVP is single or add to group if AVP is Grouped
|
||||
func messageSetAVPsWithPath(m *diam.Message, path []interface{}, avpValByte []byte, appnd bool) error {
|
||||
if len(path) == 0 {
|
||||
return errors.New("Empty path as AVP filter")
|
||||
}
|
||||
@@ -322,10 +324,11 @@ func messageAddAVPsWithPath(m *diam.Message, path []interface{}, avpValByte []by
|
||||
return errors.New("Last AVP in path needs not to be GroupedAVP")
|
||||
}
|
||||
var msgAVP *diam.AVP // Keep a reference here towards last AVP
|
||||
for i := len(path) - 1; i >= 0; i-- {
|
||||
lastAVPIdx := len(path) - 1
|
||||
for i := lastAVPIdx; i >= 0; i-- {
|
||||
var typeVal datatype.Type
|
||||
var err error
|
||||
if msgAVP == nil {
|
||||
if i == lastAVPIdx {
|
||||
typeVal, err = datatype.Decode(dictAVPs[i].Data.Type, avpValByte)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -334,7 +337,26 @@ func messageAddAVPsWithPath(m *diam.Message, path []interface{}, avpValByte []by
|
||||
typeVal = &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{msgAVP}}
|
||||
}
|
||||
msgAVP = diam.NewAVP(dictAVPs[i].Code, avp.Mbit, dictAVPs[i].VendorID, typeVal) // FixMe: maybe Mbit with dictionary one
|
||||
newMsgAVP := diam.NewAVP(dictAVPs[i].Code, avp.Mbit, dictAVPs[i].VendorID, typeVal) // FixMe: maybe Mbit with dictionary one
|
||||
if i == lastAVPIdx-1 && !appnd { // last AVP needs to be appended in group
|
||||
avps, _ := m.FindAVPsWithPath(path[:lastAVPIdx], dict.UndefinedVendorID)
|
||||
if len(avps) != 0 { // Group AVP already in the message
|
||||
prevGrpData := avps[0].Data.(*diam.GroupedAVP)
|
||||
prevGrpData.AVP = append(prevGrpData.AVP, msgAVP)
|
||||
m.Header.MessageLength += uint32(msgAVP.Len())
|
||||
return nil
|
||||
}
|
||||
}
|
||||
msgAVP = newMsgAVP
|
||||
}
|
||||
if !appnd { // Not group AVP, replace the previous set one with this one
|
||||
avps, _ := m.FindAVPsWithPath(path, dict.UndefinedVendorID)
|
||||
if len(avps) != 0 { // Group AVP already in the message
|
||||
m.Header.MessageLength -= uint32(avps[0].Len()) // decrease message length since we overwrite
|
||||
*avps[0] = *msgAVP
|
||||
m.Header.MessageLength += uint32(msgAVP.Len())
|
||||
return nil
|
||||
}
|
||||
}
|
||||
m.AVP = append(m.AVP, msgAVP)
|
||||
m.Header.MessageLength += uint32(msgAVP.Len())
|
||||
@@ -353,6 +375,7 @@ func NewCCRFromDiameterMessage(m *diam.Message, debitInterval time.Duration) (*C
|
||||
}
|
||||
|
||||
// CallControl Request
|
||||
// FixMe: strip it down to mandatory bare structure format by RFC 4006
|
||||
type CCR struct {
|
||||
SessionId string `avp:"Session-Id"`
|
||||
OriginHost string `avp:"Origin-Host"`
|
||||
@@ -395,36 +418,31 @@ type CCR struct {
|
||||
debitInterval time.Duration // Configured debit interval
|
||||
}
|
||||
|
||||
// AsBareDiameterMessage converts CCR into a bare DiameterMessage
|
||||
// Compatible with the required fields of CCA
|
||||
func (self *CCR) AsBareDiameterMessage() *diam.Message {
|
||||
m := diam.NewRequest(diam.CreditControl, 4, nil)
|
||||
m.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String(self.SessionId))
|
||||
m.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity(self.OriginHost))
|
||||
m.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity(self.OriginRealm))
|
||||
m.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(self.AuthApplicationId))
|
||||
m.NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Enumerated(self.CCRequestType))
|
||||
m.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Enumerated(self.CCRequestNumber))
|
||||
return m
|
||||
}
|
||||
|
||||
// Used when sending from client to agent
|
||||
func (self *CCR) AsDiameterMessage() (*diam.Message, error) {
|
||||
m := diam.NewRequest(diam.CreditControl, 4, nil)
|
||||
if _, err := m.NewAVP("Session-Id", avp.Mbit, 0, datatype.UTF8String(self.SessionId)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := m.NewAVP("Origin-Host", avp.Mbit, 0, datatype.DiameterIdentity(self.OriginHost)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := m.NewAVP("Origin-Realm", avp.Mbit, 0, datatype.DiameterIdentity(self.OriginRealm)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m := self.AsBareDiameterMessage()
|
||||
if _, err := m.NewAVP("Destination-Host", avp.Mbit, 0, datatype.DiameterIdentity(self.DestinationHost)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := m.NewAVP("Destination-Realm", avp.Mbit, 0, datatype.DiameterIdentity(self.DestinationRealm)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := m.NewAVP("Auth-Application-Id", avp.Mbit, 0, datatype.Unsigned32(self.AuthApplicationId)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := m.NewAVP("Service-Context-Id", avp.Mbit, 0, datatype.UTF8String(self.ServiceContextId)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := m.NewAVP("CC-Request-Type", avp.Mbit, 0, datatype.Enumerated(self.CCRequestType)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := m.NewAVP("CC-Request-Number", avp.Mbit, 0, datatype.Enumerated(self.CCRequestNumber)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := m.NewAVP("Event-Timestamp", avp.Mbit, 0, datatype.Time(self.EventTimestamp)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -483,20 +501,23 @@ func (self *CCR) AsSMGenericEvent(cfgFlds []*config.CfgCdrField) (sessionmanager
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, hasKey := outMap[cfgFld.FieldId]; !hasKey {
|
||||
outMap[cfgFld.FieldId] = fmtOut
|
||||
} else { // If already there, postpend
|
||||
if _, hasKey := outMap[cfgFld.FieldId]; hasKey && cfgFld.Append {
|
||||
outMap[cfgFld.FieldId] += fmtOut
|
||||
} else {
|
||||
outMap[cfgFld.FieldId] = fmtOut
|
||||
|
||||
}
|
||||
}
|
||||
return sessionmanager.SMGenericEvent(utils.ConvertMapValStrIf(outMap)), nil
|
||||
}
|
||||
|
||||
func NewCCAFromCCR(ccr *CCR) *CCA {
|
||||
return &CCA{SessionId: ccr.SessionId, AuthApplicationId: ccr.AuthApplicationId, CCRequestType: ccr.CCRequestType, CCRequestNumber: ccr.CCRequestNumber,
|
||||
func NewBareCCAFromCCR(ccr *CCR) *CCA {
|
||||
cca := &CCA{SessionId: ccr.SessionId, AuthApplicationId: ccr.AuthApplicationId, CCRequestType: ccr.CCRequestType, CCRequestNumber: ccr.CCRequestNumber,
|
||||
diamMessage: diam.NewMessage(ccr.diamMessage.Header.CommandCode, ccr.diamMessage.Header.CommandFlags&^diam.RequestFlag, ccr.diamMessage.Header.ApplicationID,
|
||||
ccr.diamMessage.Header.HopByHopID, ccr.diamMessage.Header.EndToEndID, ccr.diamMessage.Dictionary()),
|
||||
ccr.diamMessage.Header.HopByHopID, ccr.diamMessage.Header.EndToEndID, ccr.diamMessage.Dictionary()), ccrMessage: ccr.diamMessage, debitInterval: ccr.debitInterval,
|
||||
}
|
||||
cca.diamMessage = cca.AsBareDiameterMessage() // Add the required fields to the diameterMessage
|
||||
return cca
|
||||
}
|
||||
|
||||
// Call Control Answer, bare structure so we can dynamically manage adding it's fields
|
||||
@@ -511,42 +532,40 @@ type CCA struct {
|
||||
GrantedServiceUnit struct {
|
||||
CCTime int `avp:"CC-Time"`
|
||||
} `avp:"Granted-Service-Unit"`
|
||||
diamMessage *diam.Message
|
||||
ccrMessage *diam.Message
|
||||
diamMessage *diam.Message
|
||||
debitInterval time.Duration
|
||||
}
|
||||
|
||||
// Converts itself into DiameterMessage
|
||||
func (self *CCA) AsBareDiameterMessage() (*diam.Message, error) {
|
||||
if _, err := self.diamMessage.NewAVP("Session-Id", avp.Mbit, 0, datatype.UTF8String(self.SessionId)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := self.diamMessage.NewAVP("Origin-Host", avp.Mbit, 0, datatype.DiameterIdentity(self.OriginHost)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := self.diamMessage.NewAVP("Origin-Realm", avp.Mbit, 0, datatype.DiameterIdentity(self.OriginRealm)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := self.diamMessage.NewAVP("Auth-Application-Id", avp.Mbit, 0, datatype.Unsigned32(self.AuthApplicationId)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := self.diamMessage.NewAVP("CC-Request-Type", avp.Mbit, 0, datatype.Enumerated(self.CCRequestType)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := self.diamMessage.NewAVP("CC-Request-Number", avp.Mbit, 0, datatype.Enumerated(self.CCRequestNumber)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := self.diamMessage.NewAVP(avp.ResultCode, avp.Mbit, 0, datatype.Unsigned32(self.ResultCode)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
/*
|
||||
ccTimeAvp, err := self.diamMessage.Dictionary().FindAVP(self.diamMessage.Header.ApplicationID, "CC-Time")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := self.diamMessage.NewAVP("Granted-Service-Unit", avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(ccTimeAvp.Code, avp.Mbit, 0, datatype.Unsigned32(self.GrantedServiceUnit.CCTime))}}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
*/
|
||||
return self.diamMessage, nil
|
||||
// AsBareDiameterMessage converts CCA into a bare DiameterMessage
|
||||
func (self *CCA) AsBareDiameterMessage() *diam.Message {
|
||||
var m diam.Message
|
||||
utils.Clone(self.diamMessage, &m)
|
||||
m.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String(self.SessionId))
|
||||
m.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity(self.OriginHost))
|
||||
m.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity(self.OriginRealm))
|
||||
m.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(self.AuthApplicationId))
|
||||
m.NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Enumerated(self.CCRequestType))
|
||||
m.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Enumerated(self.CCRequestNumber))
|
||||
m.NewAVP(avp.ResultCode, avp.Mbit, 0, datatype.Unsigned32(self.ResultCode))
|
||||
return &m
|
||||
}
|
||||
|
||||
// AsDiameterMessage returns the diameter.Message which can be later written on network
|
||||
func (self *CCA) AsDiameterMessage() *diam.Message {
|
||||
return self.diamMessage
|
||||
}
|
||||
|
||||
// SetProcessorAVPs will add AVPs to self.diameterMessage based on template defined in processor.CCAFields
|
||||
func (self *CCA) SetProcessorAVPs(reqProcessor *config.DARequestProcessor) error {
|
||||
for _, cfgFld := range reqProcessor.CCAFields {
|
||||
fmtOut, err := fieldOutVal(self.ccrMessage, cfgFld, self.debitInterval)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := messageSetAVPsWithPath(self.diamMessage, splitIntoInterface(cfgFld.Value.Id(), utils.HIERARCHY_SEP), []byte(fmtOut), cfgFld.Append); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package agents
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -137,16 +138,113 @@ func TestFieldOutVal(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMessageAddAVPsWithPath(t *testing.T) {
|
||||
func TestMessageSetAVPsWithPath(t *testing.T) {
|
||||
eMessage := diam.NewRequest(diam.CreditControl, 4, nil)
|
||||
eMessage.NewAVP("Subscription-Id", avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("33708000003")), // Subscription-Id-Data
|
||||
}})
|
||||
eMessage.NewAVP("Session-Id", avp.Mbit, 0, datatype.UTF8String("simuhuawei;1449573472;00002"))
|
||||
m := diam.NewMessage(diam.CreditControl, diam.RequestFlag, 4, eMessage.Header.HopByHopID, eMessage.Header.EndToEndID, nil)
|
||||
if err := messageAddAVPsWithPath(m, []interface{}{"Subscription-Id", "Subscription-Id-Data"}, []byte("33708000003")); err != nil {
|
||||
if err := messageSetAVPsWithPath(m, []interface{}{"Session-Id", "Unknown"}, []byte("simuhuawei;1449573472;00002"), false); err == nil || err.Error() != "Could not find AVP Unknown" {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := messageSetAVPsWithPath(m, []interface{}{"Session-Id"}, []byte("simuhuawei;1449573472;00002"), false); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eMessage, m) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eMessage, m)
|
||||
}
|
||||
// test append
|
||||
eMessage.NewAVP("Session-Id", avp.Mbit, 0, datatype.UTF8String("simuhuawei;1449573472;00003"))
|
||||
if err := messageSetAVPsWithPath(m, []interface{}{"Session-Id"}, []byte("simuhuawei;1449573472;00003"), true); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eMessage, m) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eMessage, m)
|
||||
}
|
||||
// test overwrite
|
||||
eMessage = diam.NewRequest(diam.CreditControl, 4, nil)
|
||||
eMessage.NewAVP("Session-Id", avp.Mbit, 0, datatype.UTF8String("simuhuawei;1449573472;00002"))
|
||||
m = diam.NewMessage(diam.CreditControl, diam.RequestFlag, 4, eMessage.Header.HopByHopID, eMessage.Header.EndToEndID, nil)
|
||||
if err := messageSetAVPsWithPath(m, []interface{}{"Session-Id"}, []byte("simuhuawei;1449573472;00001"), false); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := messageSetAVPsWithPath(m, []interface{}{"Session-Id"}, []byte("simuhuawei;1449573472;00002"), false); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eMessage, m) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eMessage, m)
|
||||
}
|
||||
eMessage = diam.NewRequest(diam.CreditControl, 4, nil)
|
||||
eMessage.NewAVP("Subscription-Id", avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("33708000003")), // Subscription-Id-Data
|
||||
}})
|
||||
m = diam.NewMessage(diam.CreditControl, diam.RequestFlag, 4, eMessage.Header.HopByHopID, eMessage.Header.EndToEndID, nil)
|
||||
if err := messageSetAVPsWithPath(m, []interface{}{"Subscription-Id", "Subscription-Id-Data"}, []byte("33708000003"), false); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eMessage, m) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eMessage, m)
|
||||
}
|
||||
// diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(subscriptionId.SubscriptionIdType)), // Subscription-Id-Type
|
||||
// test append
|
||||
eMessage.NewAVP("Subscription-Id", avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(0)), // Subscription-Id-Data
|
||||
}})
|
||||
if err := messageSetAVPsWithPath(m, []interface{}{"Subscription-Id", "Subscription-Id-Type"}, []byte("0"), true); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eMessage, m) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eMessage, m)
|
||||
}
|
||||
// test group append
|
||||
eMessage = diam.NewRequest(diam.CreditControl, 4, nil)
|
||||
eMessage.NewAVP("Subscription-Id", avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(0)), // Subscription-Id-Data
|
||||
diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("33708000003")), // Subscription-Id-Data
|
||||
}})
|
||||
eMsgSrl, _ := eMessage.Serialize()
|
||||
m = diam.NewMessage(diam.CreditControl, diam.RequestFlag, 4, eMessage.Header.HopByHopID, eMessage.Header.EndToEndID, nil)
|
||||
if err := messageSetAVPsWithPath(m, []interface{}{"Subscription-Id", "Subscription-Id-Type"}, []byte("0"), false); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := messageSetAVPsWithPath(m, []interface{}{"Subscription-Id", "Subscription-Id-Data"}, []byte("33708000003"), false); err != nil {
|
||||
t.Error(err)
|
||||
} else {
|
||||
mSrl, _ := m.Serialize()
|
||||
if !bytes.Equal(eMsgSrl, mSrl) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eMessage, m)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCCASetProcessorAVPs(t *testing.T) {
|
||||
ccr := &CCR{ // Bare information, just the one needed for answer
|
||||
SessionId: "routinga;1442095190;1476802709",
|
||||
AuthApplicationId: 4,
|
||||
CCRequestType: 1,
|
||||
CCRequestNumber: 0,
|
||||
}
|
||||
ccr.diamMessage = ccr.AsBareDiameterMessage()
|
||||
ccr.diamMessage.NewAVP("Subscription-Id", avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(0)), // Subscription-Id-Type
|
||||
diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("33708000003")), // Subscription-Id-Data
|
||||
}})
|
||||
ccr.debitInterval = time.Duration(300) * time.Second
|
||||
cca := NewBareCCAFromCCR(ccr)
|
||||
reqProcessor := &config.DARequestProcessor{Id: "UNIT_TEST", // Set template for tests
|
||||
CCAFields: []*config.CfgCdrField{
|
||||
&config.CfgCdrField{Tag: "Subscription-Id/Subscription-Id-Type", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile("Subscription-Id>Subscription-Id-Type", utils.INFIELD_SEP), Mandatory: true},
|
||||
&config.CfgCdrField{Tag: "Subscription-Id/Subscription-Id-Data", Type: utils.META_COMPOSED,
|
||||
Value: utils.ParseRSRFieldsMustCompile("Subscription-Id>Subscription-Id-Data", utils.INFIELD_SEP), Mandatory: true},
|
||||
},
|
||||
}
|
||||
eMessage := cca.AsDiameterMessage()
|
||||
eMessage.NewAVP("Subscription-Id", avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(0)), // Subscription-Id-Type
|
||||
diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("33708000003")), // Subscription-Id-Data
|
||||
}})
|
||||
if err := cca.SetProcessorAVPs(reqProcessor); err != nil {
|
||||
t.Error(err)
|
||||
} else if ccaMsg := cca.AsDiameterMessage(); !reflect.DeepEqual(eMessage, ccaMsg) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eMessage, ccaMsg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,6 +216,19 @@ func (self *ApierV1) SetAccount(attr utils.AttrSetAccount, reply *string) error
|
||||
}
|
||||
ap.AccountIDs[accID] = struct{}{}
|
||||
schedulerReloadNeeded = true
|
||||
// create tasks
|
||||
for _, at := range ap.ActionTimings {
|
||||
if at.IsASAP() {
|
||||
t := &engine.Task{
|
||||
Uuid: utils.GenUUID(),
|
||||
AccountID: accID,
|
||||
ActionsID: at.ActionsID,
|
||||
}
|
||||
if err = self.RatingDb.PushTask(t); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
}
|
||||
if err := self.RatingDb.SetActionPlan(attr.ActionPlanId, ap); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
@@ -42,6 +42,9 @@ func NewCfgCdrFieldFromCdrFieldJsonCfg(jsnCfgFld *CdrFieldJsonCfg) (*CfgCdrField
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if jsnCfgFld.Append != nil {
|
||||
cfgFld.Append = *jsnCfgFld.Append
|
||||
}
|
||||
if jsnCfgFld.Field_filter != nil {
|
||||
if cfgFld.FieldFilter, err = utils.ParseRSRFields(*jsnCfgFld.Field_filter, utils.INFIELD_SEP); err != nil {
|
||||
return nil, err
|
||||
@@ -71,6 +74,7 @@ type CfgCdrField struct {
|
||||
FieldId string // Field identifier
|
||||
HandlerId string
|
||||
Value utils.RSRFields
|
||||
Append bool
|
||||
FieldFilter utils.RSRFields
|
||||
Width int
|
||||
Strip string
|
||||
|
||||
@@ -111,6 +111,7 @@ type CdrFieldJsonCfg struct {
|
||||
Field_id *string
|
||||
Handler_id *string
|
||||
Value *string
|
||||
Append *bool
|
||||
Width *int
|
||||
Strip *string
|
||||
Padding *string
|
||||
|
||||
@@ -1087,7 +1087,7 @@ func TestTutLocalSetAccount(t *testing.T) {
|
||||
return
|
||||
}
|
||||
var reply string
|
||||
attrs := &utils.AttrSetAccount{Tenant: "cgrates.org", Account: "tutacnt1", ActionPlanId: "PACKAGE_10", ActionTriggersId: "STANDARD_TRIGGERS"}
|
||||
attrs := &utils.AttrSetAccount{Tenant: "cgrates.org", Account: "tutacnt1", ActionPlanId: "PACKAGE_10", ActionTriggersId: "STANDARD_TRIGGERS", ReloadScheduler: true}
|
||||
if err := tutLocalRpc.Call("ApierV2.SetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.SetAccount: ", err.Error())
|
||||
} else if reply != "OK" {
|
||||
@@ -1100,7 +1100,7 @@ func TestTutLocalSetAccount(t *testing.T) {
|
||||
Offset int // Set the item offset
|
||||
Limit int // Limit number of items retrieved
|
||||
}
|
||||
time.Sleep(100*time.Millisecond + time.Duration(*waitRater)*time.Millisecond) // Give time for scheduler to execute topups
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for scheduler to execute topups
|
||||
var acnts []*engine.Account
|
||||
if err := tutLocalRpc.Call("ApierV2.GetAccounts", utils.AttrGetAccounts{Tenant: attrs.Tenant, AccountIds: []string{attrs.Account}}, &acnts); err != nil {
|
||||
t.Error(err)
|
||||
@@ -1125,7 +1125,7 @@ func TestTutLocalSetAccount(t *testing.T) {
|
||||
t.Error("Disabled should not be set")
|
||||
}
|
||||
}
|
||||
attrs = &utils.AttrSetAccount{Tenant: "cgrates.org", Account: "tutacnt1", AllowNegative: utils.BoolPointer(true), Disabled: utils.BoolPointer(true)}
|
||||
attrs = &utils.AttrSetAccount{Tenant: "cgrates.org", Account: "tutacnt1", AllowNegative: utils.BoolPointer(true), Disabled: utils.BoolPointer(true), ReloadScheduler: true}
|
||||
if err := tutLocalRpc.Call("ApierV2.SetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.SetAccount: ", err.Error())
|
||||
} else if reply != "OK" {
|
||||
|
||||
Reference in New Issue
Block a user