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:
DanB
2018-10-04 20:31:39 +02:00
parent 60a80fc8f1
commit e5299d97b1
10 changed files with 154 additions and 22 deletions

View File

@@ -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

View File

@@ -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)
}
}

View File

@@ -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)
}

View File

@@ -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": {

View File

@@ -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},

View File

@@ -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 #Tenant ID Contexts FilterIDs ActivationInterval FieldName Initial Substitute Append Blocker Weight
15 cgrates.org ATTR_1003_SESSIONAUTH RequestType *any *prepaid true
16 cgrates.org ATTR_1003_SESSIONAUTH PaypalAccount *any cgrates@paypal.com true
17 cgrates.org ATTR_1003_SESSIONAUTH LCRProfile *any premium_cli true
18 cgrates.org ATTR_1006_ALIAS *any *string:SubscriberId:1006 Account *any 1001 true false 10
19 cgrates.org ATTR_1006_ALIAS *any RequestType *any *prepaid true
20
21

View File

@@ -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
1 #Tenant ID FilterIDs ActivationInterval RunID AttributeIDs Weight
2 cgrates.org Charger1 DEFAULT *string:Account:1001 2014-07-29T15:00:00Z *rated *default ATTR_1001_SIMPLEAUTH *none 20 0

View File

@@ -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

View File

@@ -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{

View File

@@ -311,6 +311,7 @@ const (
HIERARCHY_SEP = ">"
META_COMPOSED = "*composed"
META_USAGE_DIFFERENCE = "*usage_difference"
MetaCCUsage = "*cc_usage"
MetaString = "*string"
NegativePrefix = "!"
MatchStartPrefix = "^"