mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
SessionS returning NO_SESSION if ChargerS are not returning any charger profile, diameter integration test for init voice calls, AttributeS properly rejecting non modified *attributes fields
This commit is contained in:
@@ -20,7 +20,9 @@ package agents
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
@@ -170,6 +172,40 @@ func (aReq *AgentRequest) ParseField(
|
||||
}
|
||||
out = tEnd.Sub(tStart).String()
|
||||
isString = true
|
||||
case utils.MetaCCUsage:
|
||||
if len(cfgFld.Value) != 3 {
|
||||
return nil, fmt.Errorf("invalid arguments <%s> to %s",
|
||||
utils.ToJSON(cfgFld.Value), utils.MetaCCUsage)
|
||||
}
|
||||
strVal1, err := cfgFld.Value[0].ParseDataProvider(aReq, utils.NestingSep) // ReqNr
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
reqNr, err := strconv.ParseInt(strVal1, 10, 64)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid requestNumber <%s> to %s",
|
||||
strVal1, utils.MetaCCUsage)
|
||||
}
|
||||
strVal2, err := cfgFld.Value[1].ParseDataProvider(aReq, utils.NestingSep) // TotalUsage
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
usedCCTime, err := utils.ParseDurationWithNanosecs(strVal2)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid usedCCTime <%s> to %s",
|
||||
strVal2, utils.MetaCCUsage)
|
||||
}
|
||||
strVal3, err := cfgFld.Value[2].ParseDataProvider(aReq, utils.NestingSep) // DebitInterval
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
debitItvl, err := utils.ParseDurationWithNanosecs(strVal3)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid debitInterval <%s> to %s",
|
||||
strVal3, utils.MetaCCUsage)
|
||||
}
|
||||
return usedCCTime + time.Duration(debitItvl.Nanoseconds()*reqNr), nil
|
||||
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
|
||||
@@ -42,7 +42,7 @@ var replyTimeout = flag.String("reply_timeout", "1s", "Maximum duration to wait
|
||||
var daCfgPath string
|
||||
var daCfg *config.CGRConfig
|
||||
var apierRpc *rpc.Client
|
||||
var dmtClient *DiameterClient
|
||||
var diamClnt *DiameterClient
|
||||
|
||||
var rplyTimeout time.Duration
|
||||
|
||||
@@ -83,7 +83,7 @@ func TestDiamItStartEngine(t *testing.T) {
|
||||
*/
|
||||
|
||||
func TestDiamItConnectDiameterClient(t *testing.T) {
|
||||
dmtClient, err = NewDiameterClient(daCfg.DiameterAgentCfg().Listen, "INTEGRATION_TESTS",
|
||||
diamClnt, err = NewDiameterClient(daCfg.DiameterAgentCfg().Listen, "INTEGRATION_TESTS",
|
||||
daCfg.DiameterAgentCfg().OriginRealm,
|
||||
daCfg.DiameterAgentCfg().VendorId, daCfg.DiameterAgentCfg().ProductName,
|
||||
utils.DIAMETER_FIRMWARE_REVISION, daCfg.DiameterAgentCfg().DictionariesPath)
|
||||
@@ -103,7 +103,7 @@ func TestDiamItApierRpcConn(t *testing.T) {
|
||||
|
||||
// Load the tariff plan, creating accounts and their balances
|
||||
func TestDiamItTPFromFolder(t *testing.T) {
|
||||
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "oldtutorial")}
|
||||
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "tutorial")}
|
||||
var loadInst utils.LoadInstance
|
||||
if err := apierRpc.Call("ApierV2.LoadTariffPlanFromFolder", attrs, &loadInst); err != nil {
|
||||
t.Error(err)
|
||||
@@ -162,10 +162,10 @@ func TestDiamItDryRun(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
for i := 0; i < *interations; i++ {
|
||||
if err := dmtClient.SendMessage(ccr); err != nil {
|
||||
if err := diamClnt.SendMessage(ccr); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
msg := dmtClient.ReceivedMessage(rplyTimeout)
|
||||
msg := diamClnt.ReceivedMessage(rplyTimeout)
|
||||
if msg == nil {
|
||||
t.Fatal("No message returned")
|
||||
}
|
||||
@@ -242,3 +242,78 @@ func TestDiamItDryRun(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiamItCCRInit(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(1))
|
||||
m.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Unsigned32(1))
|
||||
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, 42, 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(600))}})
|
||||
m.NewAVP(avp.UsedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{
|
||||
AVP: []*diam.AVP{
|
||||
diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(0))}})
|
||||
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 = "900" // 15 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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,12 +281,12 @@ func (prsr *RSRParser) ParseDataProvider(dP DataProvider, separator string) (out
|
||||
}
|
||||
|
||||
func (prsr *RSRParser) ParseDataProviderWithInterfaces(dP DataProvider, separator string) (out string, err error) {
|
||||
var outStr interface{}
|
||||
var outIface interface{}
|
||||
if prsr.attrValue == "" {
|
||||
if outStr, err = dP.FieldAsInterface(
|
||||
if outIface, err = dP.FieldAsInterface(
|
||||
strings.Split(prsr.attrName, separator)); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return prsr.ParseValue(outStr)
|
||||
return prsr.ParseValue(outIface)
|
||||
}
|
||||
|
||||
@@ -44,9 +44,25 @@
|
||||
"enabled": true,
|
||||
},
|
||||
|
||||
"chargers": {
|
||||
"enabled": true,
|
||||
},
|
||||
|
||||
|
||||
"sessions": {
|
||||
"enabled": true,
|
||||
"attributes_conns": [
|
||||
{"address": "127.0.0.1:2012","transport":"*json"}
|
||||
],
|
||||
"chargers_conns": [
|
||||
{"address": "127.0.0.1:2012","transport":"*json"}
|
||||
],
|
||||
"rals_conns": [
|
||||
{"address": "127.0.0.1:2012","transport":"*json"}
|
||||
],
|
||||
"cdrs_conns": [
|
||||
{"address": "127.0.0.1:2012","transport":"*json"}
|
||||
],
|
||||
},
|
||||
|
||||
"diameter_agent": {
|
||||
|
||||
@@ -13,19 +13,18 @@
|
||||
{"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": "*constant", "value": "15m"},
|
||||
{"tag": "SubscriberID", "field_id": "SubscriberId", "type": "*composed",
|
||||
"value": "~*req.Subscription-Id.Subscription-Id-Data", "mandatory": true},
|
||||
],
|
||||
"reply_fields":[
|
||||
{"tag": "ResultCode", "filters": ["*string:*cgrep.Error:ACCOUNT_NOT_FOUND"],
|
||||
"field_id": "Result-Code", "type": "*constant", "value": "5030", "blocker": true},
|
||||
{"tag": "ResultCode", "filters": ["*string:*cgrep.Error:USER_NOT_FOUND"],
|
||||
{"tag": "ResultCode", "filters": ["*rsr::~*cgrep.Error(!^$)"],
|
||||
"field_id": "Result-Code", "type": "*constant", "value": "5030", "blocker": true},
|
||||
{"tag": "GrantedUnits", "field_id": "Granted-Service-Unit.CC-Time", "type": "*composed",
|
||||
"value": "~*cgrep.MaxUsage{*duration_seconds}", "mandatory": true},
|
||||
|
||||
@@ -15,5 +15,7 @@ cgrates.org,ATTR_1003_SESSIONAUTH,*sessions,*string:Account:1003,,Password,*any,
|
||||
cgrates.org,ATTR_1003_SESSIONAUTH,,,,RequestType,*any,*prepaid,true,,
|
||||
cgrates.org,ATTR_1003_SESSIONAUTH,,,,PaypalAccount,*any,cgrates@paypal.com,true,,
|
||||
cgrates.org,ATTR_1003_SESSIONAUTH,,,,LCRProfile,*any,premium_cli,true,,
|
||||
cgrates.org,ATTR_1006_ALIAS,*any,*string:SubscriberId:1006,,Account,*any,1001,true,false,10
|
||||
cgrates.org,ATTR_1006_ALIAS,*any,,,RequestType,*any,*prepaid,true,,
|
||||
|
||||
|
||||
|
||||
|
@@ -1,2 +1,2 @@
|
||||
#Tenant,ID,FilterIDs,ActivationInterval,RunID,AttributeIDs,Weight
|
||||
cgrates.org,Charger1,*string:Account:1001,2014-07-29T15:00:00Z,*rated,ATTR_1001_SIMPLEAUTH,20
|
||||
cgrates.org,DEFAULT,,,*default,*none,0
|
||||
|
@@ -201,13 +201,14 @@ func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent) (
|
||||
}
|
||||
rply.AlteredFields = append(rply.AlteredFields, fldName)
|
||||
}
|
||||
for _, valIface := range rply.CGREvent.Event {
|
||||
if valIface == interface{}(utils.MetaAttributes) {
|
||||
return nil, utils.NewCGRError(utils.AttributeSv1ProcessEvent,
|
||||
utils.AttributesNotFoundCaps,
|
||||
utils.AttributesNotFound,
|
||||
utils.AttributesNotFound)
|
||||
}
|
||||
}
|
||||
for _, valIface := range rply.CGREvent.Event {
|
||||
if valIface == interface{}(utils.MetaAttributes) {
|
||||
return nil, utils.NewCGRError(
|
||||
utils.AttributeSv1ProcessEvent,
|
||||
utils.AttributesNotFound,
|
||||
utils.AttributesNotFound,
|
||||
utils.AttributesNotFound)
|
||||
}
|
||||
}
|
||||
return
|
||||
|
||||
@@ -532,8 +532,10 @@ func (smg *SMGeneric) v2ForkSessions(tnt string, evStart *engine.SafEvent,
|
||||
Event: evStart.AsMapInterface(),
|
||||
}
|
||||
var chrgrs []*engine.ChrgSProcessEventReply
|
||||
if err := smg.chargerS.Call(utils.ChargerSv1ProcessEvent, cgrEv, &chrgrs); err != nil &&
|
||||
err.Error() != utils.ErrNotFound.Error() {
|
||||
if err := smg.chargerS.Call(utils.ChargerSv1ProcessEvent, cgrEv, &chrgrs); err != nil {
|
||||
if err.Error() == utils.ErrNotFound.Error() {
|
||||
return nil, utils.ErrNoActiveSession
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
noneSession := []*SMGSession{
|
||||
|
||||
@@ -311,6 +311,7 @@ const (
|
||||
HIERARCHY_SEP = ">"
|
||||
META_COMPOSED = "*composed"
|
||||
META_USAGE_DIFFERENCE = "*usage_difference"
|
||||
MetaCCUsage = "*cc_usage"
|
||||
MetaString = "*string"
|
||||
NegativePrefix = "!"
|
||||
MatchStartPrefix = "^"
|
||||
|
||||
Reference in New Issue
Block a user