mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-15 05:09:54 +05:00
Diameter CallControl operational for voice
This commit is contained in:
@@ -204,7 +204,11 @@ func (aReq *AgentRequest) ParseField(
|
||||
return "", fmt.Errorf("invalid debitInterval <%s> to %s",
|
||||
strVal3, utils.MetaCCUsage)
|
||||
}
|
||||
return usedCCTime + time.Duration(debitItvl.Nanoseconds()*reqNr), nil
|
||||
mltpl := reqNr - 2 // init and terminate will be ignored
|
||||
if mltpl < 0 {
|
||||
mltpl = 0
|
||||
}
|
||||
return usedCCTime + time.Duration(debitItvl.Nanoseconds()*mltpl), nil
|
||||
|
||||
}
|
||||
if err != nil {
|
||||
|
||||
@@ -263,7 +263,7 @@ func TestDiamItCCRInit(t *testing.T) {
|
||||
m.NewAVP(avp.ServiceIdentifier, avp.Mbit, 0, datatype.Unsigned32(0))
|
||||
m.NewAVP(avp.RequestedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(600))}})
|
||||
diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(300))}})
|
||||
m.NewAVP(avp.UsedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(0))}})
|
||||
@@ -305,7 +305,7 @@ func TestDiamItCCRInit(t *testing.T) {
|
||||
t.Errorf("expecting: %s, received: <%s>", eVal, val)
|
||||
}
|
||||
// Result-Code
|
||||
eVal = "900" // 15 mins of session
|
||||
eVal = "300" // 5 mins of session
|
||||
if avps, err := msg.FindAVPsWithPath([]interface{}{"Granted-Service-Unit", "CC-Time"},
|
||||
dict.UndefinedVendorID); err != nil {
|
||||
t.Error(err)
|
||||
@@ -317,3 +317,154 @@ func TestDiamItCCRInit(t *testing.T) {
|
||||
t.Errorf("expecting: %s, received: <%s>", eVal, val)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiamItCCRUpdate(t *testing.T) {
|
||||
m := diam.NewRequest(diam.CreditControl, 4, nil)
|
||||
m.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String("bb97be2b9f37c2be9614fff71c8b1d08b1acbff8"))
|
||||
m.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("192.168.1.1"))
|
||||
m.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("cgrates.org"))
|
||||
m.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(4))
|
||||
m.NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Enumerated(2))
|
||||
m.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Unsigned32(2))
|
||||
m.NewAVP(avp.DestinationHost, avp.Mbit, 0, datatype.DiameterIdentity("CGR-DA"))
|
||||
m.NewAVP(avp.DestinationRealm, avp.Mbit, 0, datatype.DiameterIdentity("cgrates.org"))
|
||||
m.NewAVP(avp.ServiceContextID, avp.Mbit, 0, datatype.UTF8String("voice@DiamItCCRInit"))
|
||||
m.NewAVP(avp.EventTimestamp, avp.Mbit, 0, datatype.Time(time.Date(2018, 10, 4, 14, 57, 20, 0, time.UTC)))
|
||||
m.NewAVP(avp.SubscriptionID, 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("1006")), // Subscription-Id-Data
|
||||
}})
|
||||
m.NewAVP(avp.ServiceIdentifier, avp.Mbit, 0, datatype.Unsigned32(0))
|
||||
m.NewAVP(avp.RequestedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(300))}})
|
||||
m.NewAVP(avp.UsedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(300))}})
|
||||
m.NewAVP(873, avp.Mbit, 10415, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(20300, avp.Mbit, 2011, &diam.GroupedAVP{ // IN-Information
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(831, avp.Mbit, 10415, datatype.UTF8String("1006")), // Calling-Party-Address
|
||||
diam.NewAVP(832, avp.Mbit, 10415, datatype.UTF8String("1002")), // Called-Party-Address
|
||||
diam.NewAVP(20327, avp.Mbit, 2011, datatype.UTF8String("1002")), // Real-Called-Number
|
||||
diam.NewAVP(20339, avp.Mbit, 2011, datatype.Unsigned32(0)), // Charge-Flow-Type
|
||||
diam.NewAVP(20302, avp.Mbit, 2011, datatype.UTF8String("")), // Calling-Vlr-Number
|
||||
diam.NewAVP(20303, avp.Mbit, 2011, datatype.UTF8String("")), // Calling-CellID-Or-SAI
|
||||
diam.NewAVP(20313, avp.Mbit, 2011, datatype.UTF8String("")), // Bearer-Capability
|
||||
diam.NewAVP(20321, avp.Mbit, 2011, datatype.UTF8String("bb97be2b9f37c2be9614fff71c8b1d08b1acbff8")), // Call-Reference-Number
|
||||
diam.NewAVP(20322, avp.Mbit, 2011, datatype.UTF8String("")), // MSC-Address
|
||||
diam.NewAVP(20324, avp.Mbit, 2011, datatype.Unsigned32(0)), // Time-Zone
|
||||
diam.NewAVP(20385, avp.Mbit, 2011, datatype.UTF8String("")), // Called-Party-NP
|
||||
diam.NewAVP(20386, avp.Mbit, 2011, datatype.UTF8String("")), // SSP-Time
|
||||
},
|
||||
}),
|
||||
}})
|
||||
if err := diamClnt.SendMessage(m); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
msg := diamClnt.ReceivedMessage(rplyTimeout)
|
||||
if msg == nil {
|
||||
t.Fatal("No message returned")
|
||||
}
|
||||
// Result-Code
|
||||
eVal := "2001"
|
||||
if avps, err := msg.FindAVPsWithPath([]interface{}{"Result-Code"}, dict.UndefinedVendorID); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(avps) == 0 {
|
||||
t.Error("Missing AVP")
|
||||
} else if val, err := diamAVPAsString(avps[0]); err != nil {
|
||||
t.Error(err)
|
||||
} else if val != eVal {
|
||||
t.Errorf("expecting: %s, received: <%s>", eVal, val)
|
||||
}
|
||||
// Result-Code
|
||||
eVal = "300" // 5 mins of session
|
||||
if avps, err := msg.FindAVPsWithPath([]interface{}{"Granted-Service-Unit", "CC-Time"},
|
||||
dict.UndefinedVendorID); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(avps) == 0 {
|
||||
t.Error("Missing AVP")
|
||||
} else if val, err := diamAVPAsString(avps[0]); err != nil {
|
||||
t.Error(err)
|
||||
} else if val != eVal {
|
||||
t.Errorf("expecting: %s, received: <%s>", eVal, val)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiamItCCRTerminate(t *testing.T) {
|
||||
m := diam.NewRequest(diam.CreditControl, 4, nil)
|
||||
m.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String("bb97be2b9f37c2be9614fff71c8b1d08b1acbff8"))
|
||||
m.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("192.168.1.1"))
|
||||
m.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("cgrates.org"))
|
||||
m.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(4))
|
||||
m.NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Enumerated(3))
|
||||
m.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Unsigned32(3))
|
||||
m.NewAVP(avp.DestinationHost, avp.Mbit, 0, datatype.DiameterIdentity("CGR-DA"))
|
||||
m.NewAVP(avp.DestinationRealm, avp.Mbit, 0, datatype.DiameterIdentity("cgrates.org"))
|
||||
m.NewAVP(avp.ServiceContextID, avp.Mbit, 0, datatype.UTF8String("voice@DiamItCCRInit"))
|
||||
m.NewAVP(avp.EventTimestamp, avp.Mbit, 0, datatype.Time(time.Date(2018, 10, 4, 15, 12, 20, 0, time.UTC)))
|
||||
m.NewAVP(avp.SubscriptionID, 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("1006")), // Subscription-Id-Data
|
||||
}})
|
||||
m.NewAVP(avp.ServiceIdentifier, avp.Mbit, 0, datatype.Unsigned32(0))
|
||||
m.NewAVP(avp.RequestedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(0))}})
|
||||
m.NewAVP(avp.UsedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(250))}})
|
||||
m.NewAVP(873, avp.Mbit, 10415, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(20300, avp.Mbit, 2011, &diam.GroupedAVP{ // IN-Information
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(831, avp.Mbit, 10415, datatype.UTF8String("1006")), // Calling-Party-Address
|
||||
diam.NewAVP(832, avp.Mbit, 10415, datatype.UTF8String("1002")), // Called-Party-Address
|
||||
diam.NewAVP(20327, avp.Mbit, 2011, datatype.UTF8String("1002")), // Real-Called-Number
|
||||
diam.NewAVP(20339, avp.Mbit, 2011, datatype.Unsigned32(0)), // Charge-Flow-Type
|
||||
diam.NewAVP(20302, avp.Mbit, 2011, datatype.UTF8String("")), // Calling-Vlr-Number
|
||||
diam.NewAVP(20303, avp.Mbit, 2011, datatype.UTF8String("")), // Calling-CellID-Or-SAI
|
||||
diam.NewAVP(20313, avp.Mbit, 2011, datatype.UTF8String("")), // Bearer-Capability
|
||||
diam.NewAVP(20321, avp.Mbit, 2011, datatype.UTF8String("bb97be2b9f37c2be9614fff71c8b1d08b1acbff8")), // Call-Reference-Number
|
||||
diam.NewAVP(20322, avp.Mbit, 2011, datatype.UTF8String("")), // MSC-Address
|
||||
diam.NewAVP(20324, avp.Mbit, 2011, datatype.Unsigned32(0)), // Time-Zone
|
||||
diam.NewAVP(20385, avp.Mbit, 2011, datatype.UTF8String("")), // Called-Party-NP
|
||||
diam.NewAVP(20386, avp.Mbit, 2011, datatype.UTF8String("")), // SSP-Time
|
||||
},
|
||||
}),
|
||||
}})
|
||||
if err := diamClnt.SendMessage(m); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
msg := diamClnt.ReceivedMessage(rplyTimeout)
|
||||
if msg == nil {
|
||||
t.Fatal("No message returned")
|
||||
}
|
||||
// Result-Code
|
||||
eVal := "2001"
|
||||
if avps, err := msg.FindAVPsWithPath([]interface{}{"Result-Code"}, dict.UndefinedVendorID); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(avps) == 0 {
|
||||
t.Error("Missing AVP")
|
||||
} else if val, err := diamAVPAsString(avps[0]); err != nil {
|
||||
t.Error(err)
|
||||
} else if val != eVal {
|
||||
t.Errorf("expecting: %s, received: <%s>", eVal, val)
|
||||
}
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond)
|
||||
var cdrs []*engine.CDR
|
||||
args := utils.RPCCDRsFilter{RunIDs: []string{utils.MetaRaw}}
|
||||
if err := apierRpc.Call(utils.CdrsV1GetCDRs, args, &cdrs); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(cdrs) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(cdrs))
|
||||
} else {
|
||||
if cdrs[0].Usage != 550*time.Second {
|
||||
t.Errorf("Unexpected Usage CDR: %+v", cdrs[0])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
"value": "~*req.Service-Information.IN-Information.Real-Called-Number", "mandatory": true},
|
||||
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed",
|
||||
"value": "~*req.Event-Timestamp", "mandatory": true},
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*constant", "value": "15m"},
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*composed",
|
||||
"value": "~*req.Requested-Service-Unit.CC-Time:s/(.*)/${1}s/", "mandatory": true},
|
||||
{"tag": "SubscriberID", "field_id": "SubscriberId", "type": "*composed",
|
||||
"value": "~*req.Subscription-Id.Subscription-Id-Data", "mandatory": true},
|
||||
],
|
||||
@@ -40,12 +41,16 @@
|
||||
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed",
|
||||
"value": "~*req.Session-Id", "mandatory": true},
|
||||
{"tag": "RequestType", "field_id": "RequestType", "type": "*constant", "value": "*attributes"},
|
||||
{"tag": "Category", "field_id": "Category", "type": "*constant", "value": "call"},
|
||||
{"tag": "Account", "field_id": "Account", "type": "*constant", "value": "*attributes"},
|
||||
{"tag": "Destination", "field_id": "Destination", "type": "*composed",
|
||||
"value": "~*req.Service-Information.IN-Information.Real-Called-Number", "mandatory": true},
|
||||
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed",
|
||||
"value": "~*req.Event-Timestamp", "mandatory": true},
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*ccr_usage", "mandatory": true},
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*composed",
|
||||
"value": "~*req.Requested-Service-Unit.CC-Time:s/(.*)/${1}s/", "mandatory": true},
|
||||
{"tag": "LastUsed", "field_id": "LastUsed", "type": "*composed",
|
||||
"value": "~*req.Used-Service-Unit.CC-Time:s/(.*)/${1}s/", "mandatory": true},
|
||||
{"tag": "SubscriberID", "field_id": "SubscriberId", "type": "*composed",
|
||||
"value": "~*req.Subscription-Id.Subscription-Id-Data", "mandatory": true},
|
||||
],
|
||||
@@ -60,7 +65,7 @@
|
||||
"id": "VoiceTerminate",
|
||||
"filters": ["*string:*vars.*cmd:CCR", "*string:*req.CC-Request-Type:3",
|
||||
"*prefix:*req.Service-Context-Id:voice"],
|
||||
"flags": ["*terminate", "*accounts", "*attributes"],
|
||||
"flags": ["*terminate", "*accounts", "*attributes", "*cdrs"],
|
||||
"request_fields":[
|
||||
{"tag": "TOR", "field_id": "ToR", "type": "*constant", "value": "*voice"},
|
||||
{"tag": "OriginID", "field_id": "OriginID", "type": "*composed",
|
||||
@@ -71,7 +76,10 @@
|
||||
"value": "~*req.Service-Information.IN-Information.Real-Called-Number", "mandatory": true},
|
||||
{"tag": "AnswerTime", "field_id": "AnswerTime", "type": "*composed",
|
||||
"value": "~*req.Event-Timestamp", "mandatory": true},
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*ccr_usage", "mandatory": true},
|
||||
{"tag": "Usage", "field_id": "Usage", "type": "*cc_usage", "mandatory": true,
|
||||
"value": "~*req.CC-Request-Number;~*req.Used-Service-Unit.CC-Time:s/(.*)/${1}s/;5m"},
|
||||
{"tag": "LastUsed", "field_id": "LastUsed", "type": "*composed",
|
||||
"value": "~*req.Used-Service-Unit.CC-Time:s/(.*)/${1}s/", "mandatory": true},
|
||||
{"tag": "SubscriberID", "field_id": "SubscriberId", "type": "*composed",
|
||||
"value": "~*req.Subscription-Id.Subscription-Id-Data", "mandatory": true},
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user