Files
cgrates/agents/diam_it_test.go
ionutboangiu d8ad760dbb Update both ReAuthorize API signatures
The one from sessions takes an additional event alongside the
SessionFilter, while the one from agents will accept a CGREvent
instead of a simple originID string

The additional event sent to SessionSv1ReAuthorize will be merged
with the EventStart event from the matched session and can be used
when building server initiated requests from the *req map. The
initial packet which was initially inside *req, will be moved to
the *oreq ExtraDP (stands for original request).
2024-02-14 10:15:51 +01:00

1622 lines
68 KiB
Go

//go:build integration
// +build integration
/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package agents
import (
"flag"
"fmt"
"os/exec"
"path"
"strings"
"sync"
"testing"
"time"
"github.com/cgrates/birpc"
"github.com/cgrates/birpc/context"
v1 "github.com/cgrates/cgrates/apier/v1"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
"github.com/cgrates/cgrates/utils"
"github.com/fiorix/go-diameter/v4/diam"
"github.com/fiorix/go-diameter/v4/diam/avp"
"github.com/fiorix/go-diameter/v4/diam/datatype"
"github.com/fiorix/go-diameter/v4/diam/dict"
)
var (
interations = flag.Int("iterations", 1, "Number of iterations to do for dry run simulation")
replyTimeout = flag.String("reply_timeout", "1s", "Maximum duration to wait for a reply")
daCfgPath, diamConfigDIR string
daCfg *config.CGRConfig
apierRpc *birpc.Client
diamClnt *DiameterClient
rplyTimeout time.Duration
isDispatcherActive bool
sTestsDiam = []func(t *testing.T){
testDiamItInitCfg,
testDiamItResetDataDb,
testDiamItResetStorDb,
testDiamItStartEngine,
testDiamItConnectDiameterClient,
testDiamItApierRpcConn,
testDiamItTPFromFolder,
testDiamItDryRun,
testDiamItCCRInit,
testDiamItCCRUpdate,
testDiamItRAR,
testDiamItCCRTerminate,
testDiamItCCRSMS,
testDiamItCCRMMS,
testDiamItEmulateTerminate,
testDiamItTemplateErr,
testDiamItCCRInitWithForceDuration,
testDiamItDRR,
testDiamItKillEngine,
}
)
// Test start here
func TestDiamItTcp(t *testing.T) {
switch *dbType {
case utils.MetaInternal:
diamConfigDIR = "diamagent_internal"
case utils.MetaMySQL:
diamConfigDIR = "diamagent_mysql"
case utils.MetaMongo:
diamConfigDIR = "diamagent_mongo"
case utils.MetaPostgres:
t.SkipNow()
default:
t.Fatal("Unknown Database type")
}
for _, stest := range sTestsDiam {
t.Run(diamConfigDIR, stest)
}
}
func TestDiamItDispatcher(t *testing.T) {
if *encoding == utils.MetaGOB {
t.SkipNow()
return
}
testDiamItResetAllDB(t)
isDispatcherActive = true
engine.StartEngine(path.Join(*dataDir, "conf", "samples", "dispatchers", "all"), 200)
engine.StartEngine(path.Join(*dataDir, "conf", "samples", "dispatchers", "all2"), 200)
diamConfigDIR = "dispatchers/diamagent"
for _, stest := range sTestsDiam {
t.Run(diamConfigDIR, stest)
}
isDispatcherActive = false
}
func TestDiamItSctp(t *testing.T) {
switch *dbType {
case utils.MetaInternal:
diamConfigDIR = "diamsctpagent_internal"
case utils.MetaMySQL:
diamConfigDIR = "diamsctpagent_mysql"
case utils.MetaMongo:
diamConfigDIR = "diamsctpagent_mongo"
case utils.MetaPostgres:
t.SkipNow()
default:
t.Fatal("Unknown Database type")
}
for _, stest := range sTestsDiam {
t.Run(diamConfigDIR, stest)
}
}
func TestDiamItBiRPC(t *testing.T) {
switch *dbType {
case utils.MetaInternal:
diamConfigDIR = "diamagent_internal_%sbirpc"
case utils.MetaMySQL:
diamConfigDIR = "diamagent_mysql_%sbirpc"
case utils.MetaMongo:
diamConfigDIR = "diamagent_mongo_%sbirpc"
case utils.MetaPostgres:
t.SkipNow()
default:
t.Fatal("Unknown Database type")
}
diamConfigDIR = fmt.Sprintf(diamConfigDIR, strings.TrimPrefix(*encoding, utils.Meta))
for _, stest := range sTestsDiam {
t.Run(diamConfigDIR, stest)
}
}
func TestDiamItMaxConn(t *testing.T) {
switch *dbType {
case utils.MetaInternal:
diamConfigDIR = "diamagentmaxconn_internal"
case utils.MetaMySQL:
diamConfigDIR = "diamagentmaxconn_mysql"
case utils.MetaMongo:
diamConfigDIR = "diamagentmaxconn_mongo"
case utils.MetaPostgres:
t.SkipNow()
default:
t.Fatal("Unknown Database type")
}
for _, stest := range sTestsDiam[:7] {
t.Run(diamConfigDIR, stest)
}
t.Run(diamConfigDIR, testDiamItDryRunMaxConn)
t.Run(diamConfigDIR, testDiamItKillEngine)
}
func TestDiamItSessionDisconnect(t *testing.T) {
switch *dbType {
case utils.MetaInternal:
diamConfigDIR = "diamagent_internal"
case utils.MetaMySQL:
diamConfigDIR = "diamagent_mysql"
case utils.MetaMongo:
diamConfigDIR = "diamagent_mongo"
case utils.MetaPostgres:
t.SkipNow()
default:
t.Fatal("Unknown Database type")
}
for _, stest := range sTestsDiam[:7] {
t.Run(diamConfigDIR, stest)
}
t.Run(diamConfigDIR, testDiamInitWithSessionDisconnect)
t.Run(diamConfigDIR, testDiamItKillEngine)
}
func testDiamItInitCfg(t *testing.T) {
daCfgPath = path.Join(*dataDir, "conf", "samples", diamConfigDIR)
// Init config first
var err error
daCfg, err = config.NewCGRConfigFromPath(daCfgPath)
if err != nil {
t.Fatal(err)
}
daCfg.DataFolderPath = *dataDir // Share DataFolderPath through config towards StoreDb for Flush()
rplyTimeout, _ = utils.ParseDurationWithSecs(*replyTimeout)
if isDispatcherActive {
daCfg.ListenCfg().RPCJSONListen = ":6012"
}
}
func testDiamItResetAllDB(t *testing.T) {
cfgPath1 := path.Join(*dataDir, "conf", "samples", "dispatchers", "all")
allCfg, err := config.NewCGRConfigFromPath(cfgPath1)
if err != nil {
t.Fatal(err)
}
if err := engine.InitDataDb(allCfg); err != nil {
t.Fatal(err)
}
if err := engine.InitStorDb(allCfg); err != nil {
t.Fatal(err)
}
cfgPath2 := path.Join(*dataDir, "conf", "samples", "dispatchers", "all2")
allCfg2, err := config.NewCGRConfigFromPath(cfgPath2)
if err != nil {
t.Fatal(err)
}
if err := engine.InitDataDb(allCfg2); err != nil {
t.Fatal(err)
}
if err := engine.InitStorDb(allCfg2); err != nil {
t.Fatal(err)
}
}
// Remove data in both rating and accounting db
func testDiamItResetDataDb(t *testing.T) {
if err := engine.InitDataDb(daCfg); err != nil {
t.Fatal(err)
}
}
// Wipe out the cdr database
func testDiamItResetStorDb(t *testing.T) {
if err := engine.InitStorDb(daCfg); err != nil {
t.Fatal(err)
}
}
// Start CGR Engine
func testDiamItStartEngine(t *testing.T) {
if _, err := engine.StartEngine(daCfgPath, 500); err != nil {
t.Fatal(err)
}
}
func testDiamItConnectDiameterClient(t *testing.T) {
diamClnt, err = NewDiameterClient(daCfg.DiameterAgentCfg().Listen, "INTEGRATION_TESTS",
daCfg.DiameterAgentCfg().OriginRealm, daCfg.DiameterAgentCfg().VendorID,
daCfg.DiameterAgentCfg().ProductName, utils.DiameterFirmwareRevision,
daCfg.DiameterAgentCfg().DictionariesPath, daCfg.DiameterAgentCfg().ListenNet)
if err != nil {
t.Fatal(err)
}
}
// Connect rpc client to rater
func testDiamItApierRpcConn(t *testing.T) {
var err error
apierRpc, err = newRPCClient(daCfg.ListenCfg()) // We connect over JSON so we can also troubleshoot if needed
if err != nil {
t.Fatal(err)
}
}
// Load the tariff plan, creating accounts and their balances
func testDiamItTPFromFolder(t *testing.T) {
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "tutorial")}
var loadInst utils.LoadInstance
if err := apierRpc.Call(context.Background(), utils.APIerSv2LoadTariffPlanFromFolder, attrs, &loadInst); err != nil {
t.Error(err)
}
if isDispatcherActive {
testDiamItTPLoadData(t)
}
time.Sleep(100 * time.Millisecond) // Give time for scheduler to execute topups
}
func testDiamItTPLoadData(t *testing.T) {
wchan := make(chan struct{}, 1)
go func() {
loaderPath, err := exec.LookPath("cgr-loader")
if err != nil {
t.Error(err)
}
loader := exec.Command(loaderPath, "-config_path", daCfgPath, "-path", path.Join(*dataDir, "tariffplans", "dispatchers"))
if err := loader.Start(); err != nil {
t.Error(err)
}
loader.Wait()
wchan <- struct{}{}
}()
select {
case <-wchan:
case <-time.After(time.Second):
t.Errorf("cgr-loader failed: ")
}
}
func testDiamItDryRun(t *testing.T) {
ccr := diam.NewRequest(diam.CreditControl, 4, nil)
ccr.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String("cgrates;1451911932;00082"))
ccr.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("CGR-DA"))
ccr.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("cgrates.org"))
ccr.NewAVP(avp.DestinationRealm, avp.Mbit, 0, datatype.DiameterIdentity("cgrates.org"))
ccr.NewAVP(avp.DestinationHost, avp.Mbit, 0, datatype.DiameterIdentity("CGR-DA"))
ccr.NewAVP(avp.UserName, avp.Mbit, 0, datatype.UTF8String("CGR-DA"))
ccr.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(4))
ccr.NewAVP(avp.ServiceContextID, avp.Mbit, 0, datatype.UTF8String("TestDiamItDryRun")) // Match specific DryRun profile
ccr.NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Enumerated(1))
ccr.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Unsigned32(1))
ccr.NewAVP(avp.EventTimestamp, avp.Mbit, 0, datatype.Time(time.Date(2016, 1, 5, 11, 30, 10, 0, time.UTC)))
ccr.NewAVP(avp.TerminationCause, avp.Mbit, 0, datatype.Enumerated(1))
ccr.NewAVP(443, avp.Mbit, 0, &diam.GroupedAVP{ // Subscription-Id
AVP: []*diam.AVP{
diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(0)), // Subscription-Id-Type
diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("1001")), // Subscription-Id-Data
}})
ccr.NewAVP(443, avp.Mbit, 0, &diam.GroupedAVP{ // Subscription-Id
AVP: []*diam.AVP{
diam.NewAVP(450, avp.Mbit, 0, datatype.Enumerated(1)), // Subscription-Id-Type
diam.NewAVP(444, avp.Mbit, 0, datatype.UTF8String("208123456789")), // Subscription-Id-Data
}})
ccr.NewAVP(439, avp.Mbit, 0, datatype.Unsigned32(0)) // Service-Identifier
ccr.NewAVP(437, avp.Mbit, 0, &diam.GroupedAVP{ // Requested-Service-Unit
AVP: []*diam.AVP{
diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(300)), // CC-Time
}})
ccr.NewAVP(873, avp.Mbit|avp.Vbit, 10415, &diam.GroupedAVP{ // Service-information
AVP: []*diam.AVP{
diam.NewAVP(20300, avp.Mbit, 2011, &diam.GroupedAVP{ // IN-Information
AVP: []*diam.AVP{
diam.NewAVP(20336, avp.Mbit, 2011, datatype.UTF8String("1001")), // CallingPartyAdress
diam.NewAVP(20337, avp.Mbit, 2011, datatype.UTF8String("1002")), // CalledPartyAdress
diam.NewAVP(20339, avp.Mbit, 2011, datatype.Unsigned32(0)), // ChargeFlowType
diam.NewAVP(20302, avp.Mbit, 2011, datatype.UTF8String("33609004940")), // CallingVlrNumber
diam.NewAVP(20303, avp.Mbit, 2011, datatype.UTF8String("208104941749984")), // CallingCellID
diam.NewAVP(20313, avp.Mbit, 2011, datatype.OctetString("0x8090a3")), // BearerCapability
diam.NewAVP(20321, avp.Mbit, 2011, datatype.OctetString("0x401c4132ed665")), // CallreferenceNumber
diam.NewAVP(20322, avp.Mbit, 2011, datatype.UTF8String("33609004940")), // MSCAddress
diam.NewAVP(20386, avp.Mbit, 2011, datatype.UTF8String("20160501010101")), // SSPTime
diam.NewAVP(20938, avp.Mbit, 2011, datatype.OctetString("0x00000001")), // HighLayerCharacteristics
diam.NewAVP(20324, avp.Mbit, 2011, datatype.Integer32(8)), // Time-Zone
},
}),
}})
ccr.NewAVP(avp.MultipleServicesCreditControl, avp.Mbit, 0, &diam.GroupedAVP{ // Multiple-Services-Credit-Control
AVP: []*diam.AVP{
diam.NewAVP(avp.UsedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{ // Used-Service-Unit
AVP: []*diam.AVP{
diam.NewAVP(avp.CCTotalOctets, avp.Mbit, 0, datatype.Unsigned64(7640)), // CC-Total-Octets
diam.NewAVP(avp.CCInputOctets, avp.Mbit, 0, datatype.Unsigned64(5337)), // CC-Input-Octets
diam.NewAVP(avp.CCOutputOctets, avp.Mbit, 0, datatype.Unsigned64(2303)), // CC-Output-Octets
},
}),
diam.NewAVP(avp.ServiceIdentifier, avp.Mbit, 0, datatype.Unsigned32(65000)), // Service-Identifier
diam.NewAVP(avp.RatingGroup, avp.Mbit, 0, datatype.Unsigned32(1)), // Rating-Group
diam.NewAVP(avp.ReportingReason, avp.Mbit, 0, datatype.Enumerated(2)), // Reporting-Reason
},
})
ccr.NewAVP(avp.MultipleServicesCreditControl, avp.Mbit, 0, &diam.GroupedAVP{ // Multiple-Services-Credit-Control
AVP: []*diam.AVP{
diam.NewAVP(avp.UsedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{ // Used-Service-Unit
AVP: []*diam.AVP{
diam.NewAVP(avp.CCTotalOctets, avp.Mbit, 0, datatype.Unsigned64(3000)), // CC-Total-Octets
diam.NewAVP(avp.CCInputOctets, avp.Mbit, 0, datatype.Unsigned64(2000)), // CC-Input-Octets
diam.NewAVP(avp.CCOutputOctets, avp.Mbit, 0, datatype.Unsigned64(1000)), // CC-Output-Octets
},
}),
diam.NewAVP(avp.ServiceIdentifier, avp.Mbit, 0, datatype.Unsigned32(65000)), // Service-Identifier
diam.NewAVP(avp.RatingGroup, avp.Mbit, 0, datatype.Unsigned32(2)), // Rating-Group
diam.NewAVP(avp.ReportingReason, avp.Mbit, 0, datatype.Enumerated(2)), // Reporting-Reason
},
})
if _, err := ccr.NewAVP("Framed-IP-Address", avp.Mbit, 0, datatype.UTF8String("10.228.16.4")); err != nil {
t.Error(err)
}
for i := 0; i < *interations; i++ {
// ============================================
// prevent nil pointer dereference
// ============================================
if diamClnt == nil {
t.Fatal("Diameter client should not be nil")
}
if diamClnt.conn == nil {
t.Fatal("Diameter connection should not be nil")
}
if ccr == nil {
t.Fatal("The mesage to diameter should not be nil")
}
// ============================================
if err := diamClnt.SendMessage(ccr); err != nil {
t.Error(err)
}
msg := diamClnt.ReceivedMessage(rplyTimeout)
if msg == nil {
t.Fatal("No message returned")
}
// Result-Code
eVal := "2002"
if avps, err := msg.FindAVPsWithPath([]any{"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)
}
eVal = "cgrates;1451911932;00082"
if avps, err := msg.FindAVPsWithPath([]any{"Session-Id"}, 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)
}
eVal = "CGR-DA"
if avps, err := msg.FindAVPsWithPath([]any{"Origin-Host"}, 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)
}
eVal = "cgrates.org"
if avps, err := msg.FindAVPsWithPath([]any{"Origin-Realm"}, 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)
}
eVal = "4"
if avps, err := msg.FindAVPsWithPath([]any{"Auth-Application-Id"}, 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)
}
eVal = "1"
if avps, err := msg.FindAVPsWithPath([]any{"CC-Request-Type"}, 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)
}
eVal = "1"
if avps, err := msg.FindAVPsWithPath([]any{"CC-Request-Number"}, 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)
}
if avps, err := msg.FindAVPsWithPath([]any{"Multiple-Services-Credit-Control", "Rating-Group"}, dict.UndefinedVendorID); err != nil {
t.Error(err)
} else if len(avps) != 2 {
t.Errorf("Unexpected number of Multiple-Services-Credit-Control.Rating-Group : %d", len(avps))
} else {
if val, err := diamAVPAsString(avps[0]); err != nil {
t.Error(err)
} else if val != "1" {
t.Errorf("expecting: 1, received: <%s>", val)
}
if val, err := diamAVPAsString(avps[1]); err != nil {
t.Error(err)
} else if val != "2" {
t.Errorf("expecting: 2, received: <%s>", val)
}
}
if avps, err := msg.FindAVPsWithPath([]any{"Multiple-Services-Credit-Control", "Used-Service-Unit", "CC-Total-Octets"}, dict.UndefinedVendorID); err != nil {
t.Error(err)
} else if len(avps) != 2 {
t.Errorf("Unexpected number of Multiple-Services-Credit-Control.Used-Service-Unit.CC-Total-Octets : %d", len(avps))
} else {
if val, err := diamAVPAsString(avps[0]); err != nil {
t.Error(err)
} else if val != "7640" {
t.Errorf("expecting: 7640, received: <%s>", val)
}
if val, err := diamAVPAsString(avps[1]); err != nil {
t.Error(err)
} else if val != "3000" {
t.Errorf("expecting: 3000, received: <%s>", val)
}
}
eVal = "6" // sum of items
if avps, err := msg.FindAVPsWithPath([]any{"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 testDiamItDryRunMaxConn(t *testing.T) {
ccr := diam.NewRequest(diam.CreditControl, 4, nil)
ccr.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String("cgrates;1451911932;00082"))
ccr.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("CGR-DA"))
ccr.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("cgrates.org"))
ccr.NewAVP(avp.DestinationRealm, avp.Mbit, 0, datatype.DiameterIdentity("cgrates.org"))
ccr.NewAVP(avp.DestinationHost, avp.Mbit, 0, datatype.DiameterIdentity("CGR-DA"))
ccr.NewAVP(avp.UserName, avp.Mbit, 0, datatype.UTF8String("CGR-DA"))
ccr.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(4))
ccr.NewAVP(avp.ServiceContextID, avp.Mbit, 0, datatype.UTF8String("TestDiamItDryRun")) // Match specific DryRun profile
ccr.NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Enumerated(1))
ccr.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Unsigned32(1))
ccr.NewAVP(avp.EventTimestamp, avp.Mbit, 0, datatype.Time(time.Date(2016, 1, 5, 11, 30, 10, 0, time.UTC)))
ccr.NewAVP(avp.TerminationCause, avp.Mbit, 0, datatype.Enumerated(1))
if _, err := ccr.NewAVP("Framed-IP-Address", avp.Mbit, 0, datatype.UTF8String("10.228.16.4")); err != nil {
t.Error(err)
}
for i := 0; i < *interations; i++ {
if err := diamClnt.SendMessage(ccr); err != nil {
t.Error(err)
}
msg := diamClnt.ReceivedMessage(rplyTimeout)
if msg == nil {
t.Fatal("No message returned")
}
// Result-Code
eVal := "5012"
if avps, err := msg.FindAVPsWithPath([]any{"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)
}
eVal = "cgrates;1451911932;00082"
if avps, err := msg.FindAVPsWithPath([]any{"Session-Id"}, 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)
}
eVal = "CGR-DA"
if avps, err := msg.FindAVPsWithPath([]any{"Origin-Host"}, 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)
}
eVal = "cgrates.org"
if avps, err := msg.FindAVPsWithPath([]any{"Origin-Realm"}, 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 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(0))
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(300))}})
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.OctetString("")), // 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
},
}),
}})
// ============================================
// prevent nil pointer dereference
// ============================================
if diamClnt == nil {
t.Fatal("Diameter client should not be nil")
}
if diamClnt.conn == nil {
t.Fatal("Diameter connection should not be nil")
}
if m == nil {
t.Fatal("The mesage to diameter should not be nil")
}
// ============================================
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([]any{"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([]any{"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 testDiamItCCRInitWithForceDuration(t *testing.T) {
m := diam.NewRequest(diam.CreditControl, 4, nil)
m.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String("bb97be2b9f37c2be9614fff71c8b1d08b1acbfx1"))
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(0))
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("forceDurationVoice@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(3000000000))}})
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.OctetString("")), // 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
},
}),
}})
// ============================================
// prevent nil pointer dereference
// ============================================
if diamClnt == nil {
t.Fatal("Diameter client should not be nil")
}
if diamClnt.conn == nil {
t.Fatal("Diameter connection should not be nil")
}
if m == nil {
t.Fatal("The mesage to diameter should not be nil")
}
// ============================================
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 := "5030"
if avps, err := msg.FindAVPsWithPath([]any{"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)
}
}
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(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, 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.OctetString("")), // 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
},
}),
}})
// ============================================
// prevent nil pointer dereference
// ============================================
if diamClnt == nil {
t.Fatal("Diameter client should not be nil")
}
if diamClnt.conn == nil {
t.Fatal("Diameter connection should not be nil")
}
if m == nil {
t.Fatal("The mesage to diameter should not be nil")
}
// ============================================
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([]any{"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([]any{"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(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, 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.OctetString("")), // 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
},
}),
}})
// ============================================
// prevent nil pointer dereference
// ============================================
if diamClnt == nil {
t.Fatal("Diameter client should not be nil")
}
if diamClnt.conn == nil {
t.Fatal("Diameter connection should not be nil")
}
if m == nil {
t.Fatal("The mesage to diameter should not be nil")
}
// ============================================
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([]any{"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.RPCCDRsFilterWithAPIOpts{RPCCDRsFilter: &utils.RPCCDRsFilter{RunIDs: []string{utils.MetaRaw}}}
if err := apierRpc.Call(context.Background(), 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])
}
// in case of sctp we get OriginHost ip1/ip2/ip3/...
if !strings.Contains(cdrs[0].OriginHost, "127.0.0.1") {
t.Errorf("Unexpected OriginHost CDR: %+v", cdrs[0])
}
}
}
func testDiamItCCRSMS(t *testing.T) {
ccr := diam.NewRequest(diam.CreditControl, 4, nil)
ccr.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String("TestDmtAgentSendCCRSMS"))
ccr.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("CGR-DA"))
ccr.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("cgrates.org"))
ccr.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(4))
ccr.NewAVP(avp.ServiceContextID, avp.Mbit, 0, datatype.UTF8String("message@DiamItCCRSMS"))
ccr.NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Enumerated(4))
ccr.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Unsigned32(0))
ccr.NewAVP(avp.EventTimestamp, avp.Mbit, 0, datatype.Time(time.Date(2018, 10, 5, 11, 43, 10, 0, time.UTC)))
ccr.NewAVP(avp.SubscriptionID, avp.Mbit, 0, &diam.GroupedAVP{
AVP: []*diam.AVP{
diam.NewAVP(avp.SubscriptionIDType, avp.Mbit, 0, datatype.Enumerated(0)),
diam.NewAVP(avp.SubscriptionIDData, avp.Mbit, 0, datatype.UTF8String("1001")), // Subscription-Id-Data
}})
ccr.NewAVP(avp.SubscriptionID, avp.Mbit, 0, &diam.GroupedAVP{
AVP: []*diam.AVP{
diam.NewAVP(avp.SubscriptionIDType, avp.Mbit, 0, datatype.Enumerated(1)),
diam.NewAVP(avp.SubscriptionIDData, avp.Mbit, 0, datatype.UTF8String("104502200011")), // Subscription-Id-Data
}})
ccr.NewAVP(avp.ServiceIdentifier, avp.Mbit, 0, datatype.Unsigned32(0))
ccr.NewAVP(avp.RequestedAction, avp.Mbit, 0, datatype.Enumerated(0))
ccr.NewAVP(avp.RequestedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{
AVP: []*diam.AVP{
diam.NewAVP(avp.CCTime, avp.Mbit, 0, datatype.Unsigned32(1))}})
ccr.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(20302, avp.Mbit, 2011, datatype.UTF8String("22509")), // Calling-Vlr-Number
diam.NewAVP(20385, avp.Mbit, 2011, datatype.UTF8String("4002")), // Called-Party-NP
},
}),
diam.NewAVP(2000, avp.Mbit, 10415, &diam.GroupedAVP{ // SMS-Information
AVP: []*diam.AVP{
diam.NewAVP(886, avp.Mbit, 10415, &diam.GroupedAVP{ // Originator-Address
AVP: []*diam.AVP{
diam.NewAVP(899, avp.Mbit, 10415, datatype.Enumerated(1)), // Address-Type
diam.NewAVP(897, avp.Mbit, 10415, datatype.UTF8String("1001")), // Address-Data
}}),
diam.NewAVP(1201, avp.Mbit, 10415, &diam.GroupedAVP{ // Recipient-Address
AVP: []*diam.AVP{
diam.NewAVP(899, avp.Mbit, 10415, datatype.Enumerated(1)), // Address-Type
diam.NewAVP(897, avp.Mbit, 10415, datatype.UTF8String("1003")), // Address-Data
}}),
},
}),
}})
// ============================================
// prevent nil pointer dereference
// ============================================
if diamClnt == nil {
t.Fatal("Diameter client should not be nil")
}
if diamClnt.conn == nil {
t.Fatal("Diameter connection should not be nil")
}
if ccr == nil {
t.Fatal("The mesage to diameter should not be nil")
}
// ============================================
if err := diamClnt.SendMessage(ccr); err != nil {
t.Error(err)
}
time.Sleep(100 * time.Millisecond)
diamClnt.ReceivedMessage(rplyTimeout)
var cdrs []*engine.CDR
args := &utils.RPCCDRsFilterWithAPIOpts{RPCCDRsFilter: &utils.RPCCDRsFilter{RunIDs: []string{utils.MetaRaw}, ToRs: []string{utils.MetaSMS}}}
if err := apierRpc.Call(context.Background(), 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 != 1 {
t.Errorf("Unexpected Usage CDR: %+v", cdrs[0])
}
}
func testDiamItCCRMMS(t *testing.T) {
ccr := diam.NewRequest(diam.CreditControl, 4, nil)
ccr.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String("TestDmtAgentSendCCRMMS"))
ccr.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("CGR-DA"))
ccr.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("cgrates.org"))
ccr.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(4))
ccr.NewAVP(avp.ServiceContextID, avp.Mbit, 0, datatype.UTF8String("mms@DiamItCCRMMS"))
ccr.NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Enumerated(4))
ccr.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Unsigned32(0))
ccr.NewAVP(avp.EventTimestamp, avp.Mbit, 0, datatype.Time(time.Date(2018, 10, 5, 11, 43, 10, 0, time.UTC)))
ccr.NewAVP(avp.SubscriptionID, avp.Mbit, 0, &diam.GroupedAVP{
AVP: []*diam.AVP{
diam.NewAVP(avp.SubscriptionIDType, avp.Mbit, 0, datatype.Enumerated(0)),
diam.NewAVP(avp.SubscriptionIDData, avp.Mbit, 0, datatype.UTF8String("1001")), // Subscription-Id-Data
}})
ccr.NewAVP(avp.SubscriptionID, avp.Mbit, 0, &diam.GroupedAVP{
AVP: []*diam.AVP{
diam.NewAVP(avp.SubscriptionIDType, avp.Mbit, 0, datatype.Enumerated(1)),
diam.NewAVP(avp.SubscriptionIDData, avp.Mbit, 0, datatype.UTF8String("104502200011")), // Subscription-Id-Data
}})
ccr.NewAVP(avp.ServiceIdentifier, avp.Mbit, 0, datatype.Unsigned32(0))
ccr.NewAVP(avp.RequestedAction, avp.Mbit, 0, datatype.Enumerated(0))
ccr.NewAVP(avp.RequestedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{
AVP: []*diam.AVP{
diam.NewAVP(avp.CCTime, avp.Mbit, 0, datatype.Unsigned32(1))}})
ccr.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(20302, avp.Mbit, 2011, datatype.UTF8String("22509")), // Calling-Vlr-Number
diam.NewAVP(20385, avp.Mbit, 2011, datatype.UTF8String("4002")), // Called-Party-NP
},
}),
diam.NewAVP(2000, avp.Mbit, 10415, &diam.GroupedAVP{ // SMS-Information
AVP: []*diam.AVP{
diam.NewAVP(886, avp.Mbit, 10415, &diam.GroupedAVP{ // Originator-Address
AVP: []*diam.AVP{
diam.NewAVP(899, avp.Mbit, 10415, datatype.Enumerated(1)), // Address-Type
diam.NewAVP(897, avp.Mbit, 10415, datatype.UTF8String("1001")), // Address-Data
}}),
diam.NewAVP(1201, avp.Mbit, 10415, &diam.GroupedAVP{ // Recipient-Address
AVP: []*diam.AVP{
diam.NewAVP(899, avp.Mbit, 10415, datatype.Enumerated(1)), // Address-Type
diam.NewAVP(897, avp.Mbit, 10415, datatype.UTF8String("1003")), // Address-Data
}}),
},
}),
}})
// ============================================
// prevent nil pointer dereference
// ============================================
if diamClnt == nil {
t.Fatal("Diameter client should not be nil")
}
if diamClnt.conn == nil {
t.Fatal("Diameter connection should not be nil")
}
if ccr == nil {
t.Fatal("The mesage to diameter should not be nil")
}
// ============================================
if err := diamClnt.SendMessage(ccr); err != nil {
t.Error(err)
}
time.Sleep(100 * time.Millisecond)
diamClnt.ReceivedMessage(rplyTimeout)
var cdrs []*engine.CDR
args := &utils.RPCCDRsFilterWithAPIOpts{RPCCDRsFilter: &utils.RPCCDRsFilter{RunIDs: []string{utils.MetaRaw}, ToRs: []string{utils.MetaMMS}}}
if err := apierRpc.Call(context.Background(), 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 != 1 {
t.Errorf("Unexpected Usage CDR: %+v", cdrs[0])
}
}
func testDiamInitWithSessionDisconnect(t *testing.T) {
attrSetBalance := utils.AttrSetBalance{Tenant: "cgrates.org",
Account: "testDiamInitWithSessionDisconnect",
BalanceType: utils.MetaVoice,
Value: float64(time.Second),
Balance: map[string]any{
utils.ID: "testDiamInitWithSessionDisconnect",
utils.RatingSubject: "*zero1ms",
},
}
var reply string
if err := apierRpc.Call(context.Background(), utils.APIerSv2SetBalance, attrSetBalance, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Errorf("Received: %s", reply)
}
sessID := "bb97be2b9f37c2be9614fff71c8b1d08bdisconnect"
m := diam.NewRequest(diam.CreditControl, 4, nil)
m.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String(sessID))
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("testSessionDisconnect"))
m.NewAVP(avp.EventTimestamp, avp.Mbit, 0, datatype.Time(time.Date(2018, 10, 4, 14, 42, 20, 0, time.UTC)))
m.NewAVP(avp.UserName, avp.Mbit, 0, datatype.UTF8String("testDiamInitWithSessionDisconnect"))
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("testDiamInitWithSessionDisconnect")), // 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(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("1001")), // 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.OctetString("")), // Bearer-Capability
diam.NewAVP(20321, avp.Mbit, 2011, datatype.UTF8String("bb97be2b9f37c2be9614fff71c8b1d08bdisconnect")), // 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
},
}),
}})
// ============================================
// prevent nil pointer dereference
// ============================================
if diamClnt == nil {
t.Fatal("Diameter client should not be nil")
}
if diamClnt.conn == nil {
t.Fatal("Diameter connection should not be nil")
}
if m == nil {
t.Fatal("The mesage to diameter should not be nil")
}
// ============================================
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([]any{"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(2 * time.Second)
msg = diamClnt.ReceivedMessage(rplyTimeout)
if msg == nil {
t.Fatal("No message returned")
}
if avps, err := msg.FindAVPsWithPath([]any{"Session-Id"}, 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 != sessID {
t.Errorf("expecting: %s, received: <%s>", sessID, val)
}
}
func testDiamItKillEngine(t *testing.T) {
if err := engine.KillEngine(1000); err != nil {
t.Error(err)
}
}
func testDiamItRAR(t *testing.T) {
if diamConfigDIR == "dispatchers/diamagent" {
t.SkipNow()
}
// ============================================
// prevent nil pointer dereference
// ============================================
if diamClnt == nil {
t.Fatal("Diameter client should not be nil")
}
if diamClnt.conn == nil {
t.Fatal("Diameter connection should not be nil")
}
// ============================================
var wait sync.WaitGroup
wait.Add(1)
go func() {
var reply string
if err := apierRpc.Call(context.Background(), utils.SessionSv1ReAuthorize, utils.SessionFilterWithEvent{}, &reply); err != nil {
t.Error(err)
}
wait.Done()
}()
rar := diamClnt.ReceivedMessage(rplyTimeout)
if rar == nil {
t.Fatal("No message returned")
}
raa := rar.Answer(2001)
raa.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String("bb97be2b9f37c2be9614fff71c8b1d08b1acbff8"))
if err := diamClnt.SendMessage(raa); err != nil {
t.Error(err)
}
wait.Wait()
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(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, 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(301))}})
m.NewAVP(avp.UsedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{
AVP: []*diam.AVP{
diam.NewAVP(420, avp.Mbit, 0, datatype.Unsigned32(301))}})
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.OctetString("")), // 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([]any{"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 = "301" // 5 mins of session
if avps, err := msg.FindAVPsWithPath([]any{"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 testDiamItDRR(t *testing.T) {
if diamConfigDIR == "dispatchers/diamagent" {
t.SkipNow()
}
// ============================================
// prevent nil pointer dereference
// ============================================
if diamClnt == nil {
t.Fatal("Diameter client should not be nil")
}
if diamClnt.conn == nil {
t.Fatal("Diameter connection should not be nil")
}
// ============================================
var wait sync.WaitGroup
wait.Add(1)
go func() {
var reply string
if err := apierRpc.Call(context.Background(), utils.SessionSv1DisconnectPeer, &utils.DPRArgs{
OriginHost: "INTEGRATION_TESTS",
OriginRealm: "cgrates.org",
DisconnectCause: 1, // BUSY
}, &reply); err != nil {
t.Error(err)
}
wait.Done()
}()
drr := diamClnt.ReceivedMessage(rplyTimeout)
if drr == nil {
t.Fatal("No message returned")
}
dra := drr.Answer(2001)
// dra.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("INTEGRATION_TESTS"))
// dra.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("cgrates.org"))
if err := diamClnt.SendMessage(dra); err != nil {
t.Error(err)
}
wait.Wait()
eVal := "1"
if avps, err := drr.FindAVPsWithPath([]any{avp.DisconnectCause}, 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 testDiamItTemplateErr(t *testing.T) {
ccr := diam.NewRequest(diam.CreditControl, 4, nil)
ccr.NewAVP(avp.SessionID, avp.Mbit, 0, datatype.UTF8String("TestDmtAgentSendCCRError"))
ccr.NewAVP(avp.OriginHost, avp.Mbit, 0, datatype.DiameterIdentity("CGR-DA"))
ccr.NewAVP(avp.OriginRealm, avp.Mbit, 0, datatype.DiameterIdentity("cgrates.org"))
ccr.NewAVP(avp.AuthApplicationID, avp.Mbit, 0, datatype.Unsigned32(4))
ccr.NewAVP(avp.ServiceContextID, avp.Mbit, 0, datatype.UTF8String("error@DiamItError"))
ccr.NewAVP(avp.CCRequestType, avp.Mbit, 0, datatype.Enumerated(4))
ccr.NewAVP(avp.CCRequestNumber, avp.Mbit, 0, datatype.Unsigned32(0))
ccr.NewAVP(avp.EventTimestamp, avp.Mbit, 0, datatype.Time(time.Date(2018, 10, 5, 11, 43, 10, 0, time.UTC)))
ccr.NewAVP(avp.SubscriptionID, avp.Mbit, 0, &diam.GroupedAVP{
AVP: []*diam.AVP{
diam.NewAVP(avp.SubscriptionIDType, avp.Mbit, 0, datatype.Enumerated(0)),
diam.NewAVP(avp.SubscriptionIDData, avp.Mbit, 0, datatype.UTF8String("1001")), // Subscription-Id-Data
}})
ccr.NewAVP(avp.SubscriptionID, avp.Mbit, 0, &diam.GroupedAVP{
AVP: []*diam.AVP{
diam.NewAVP(avp.SubscriptionIDType, avp.Mbit, 0, datatype.Enumerated(1)),
diam.NewAVP(avp.SubscriptionIDData, avp.Mbit, 0, datatype.UTF8String("104502200011")), // Subscription-Id-Data
}})
ccr.NewAVP(avp.ServiceIdentifier, avp.Mbit, 0, datatype.Unsigned32(0))
ccr.NewAVP(avp.RequestedAction, avp.Mbit, 0, datatype.Enumerated(0))
ccr.NewAVP(avp.RequestedServiceUnit, avp.Mbit, 0, &diam.GroupedAVP{
AVP: []*diam.AVP{
diam.NewAVP(avp.CCTime, avp.Mbit, 0, datatype.Unsigned32(1))}})
ccr.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(20302, avp.Mbit, 2011, datatype.UTF8String("22509")), // Calling-Vlr-Number
diam.NewAVP(20385, avp.Mbit, 2011, datatype.UTF8String("4002")), // Called-Party-NP
},
}),
diam.NewAVP(2000, avp.Mbit, 10415, &diam.GroupedAVP{ // SMS-Information
AVP: []*diam.AVP{
diam.NewAVP(886, avp.Mbit, 10415, &diam.GroupedAVP{ // Originator-Address
AVP: []*diam.AVP{
diam.NewAVP(899, avp.Mbit, 10415, datatype.Enumerated(1)), // Address-Type
diam.NewAVP(897, avp.Mbit, 10415, datatype.UTF8String("1001")), // Address-Data
}}),
diam.NewAVP(1201, avp.Mbit, 10415, &diam.GroupedAVP{ // Recipient-Address
AVP: []*diam.AVP{
diam.NewAVP(899, avp.Mbit, 10415, datatype.Enumerated(1)), // Address-Type
diam.NewAVP(897, avp.Mbit, 10415, datatype.UTF8String("1003")), // Address-Data
}}),
},
}),
}})
// ============================================
// prevent nil pointer dereference
// ============================================
if diamClnt == nil {
t.Fatal("Diameter client should not be nil")
}
if diamClnt.conn == nil {
t.Fatal("Diameter connection should not be nil")
}
if ccr == nil {
t.Fatal("The mesage to diameter should not be nil")
}
// ============================================
if err := diamClnt.SendMessage(ccr); err != nil {
t.Error(err)
}
time.Sleep(100 * time.Millisecond)
msg := diamClnt.ReceivedMessage(rplyTimeout)
if msg == nil {
t.Fatal("Message should not be nil")
}
// Result-Code
eVal := "5012" // error code diam.UnableToComply
if avps, err := msg.FindAVPsWithPath([]any{"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)
}
}
func testDiamItEmulateTerminate(t *testing.T) {
if diamConfigDIR == "dispatchers/diamagent" {
t.SkipNow()
}
var result string
//add the second charger
chargerProfile := &v1.ChargerWithAPIOpts{
ChargerProfile: &engine.ChargerProfile{
Tenant: "cgrates.com",
ID: "CustomCharger",
RunID: "CustomCharger",
AttributeIDs: []string{"*constant:*req.Category:custom_charger"},
Weight: 20,
},
}
if err := apierRpc.Call(context.Background(), utils.APIerSv1SetChargerProfile, chargerProfile, &result); err != nil {
t.Error(err)
} else if result != utils.OK {
t.Error("Unexpected reply returned", result)
}
//add the second charger
chargerProfile2 := &v1.ChargerWithAPIOpts{
ChargerProfile: &engine.ChargerProfile{
Tenant: "cgrates.com",
ID: "Default",
RunID: "*default",
AttributeIDs: []string{"*none"},
Weight: 20,
},
}
if err := apierRpc.Call(context.Background(), utils.APIerSv1SetChargerProfile, chargerProfile2, &result); err != nil {
t.Error(err)
} else if result != utils.OK {
t.Error("Unexpected reply returned", result)
}
//set the account
attrSetBalance := utils.AttrSetBalance{
Tenant: "cgrates.com",
Account: "testDiamItEmulateTerminate",
Value: float64(time.Hour),
BalanceType: utils.MetaVoice,
Balance: map[string]any{
utils.ID: "testDiamItEmulateTerminate",
utils.Categories: "custom_charger",
},
}
var reply string
if err := apierRpc.Call(context.Background(), utils.APIerSv2SetBalance, attrSetBalance, &reply); err != nil {
t.Error(err)
} else if reply != utils.OK {
t.Errorf("Received: %s", reply)
}
var acnt *engine.Account
attrs := &utils.AttrGetAccount{Tenant: "cgrates.com", Account: "testDiamItEmulateTerminate"}
if err := apierRpc.Call(context.Background(), utils.APIerSv2GetAccount, attrs, &acnt); err != nil {
t.Error(err)
} else if acnt.BalanceMap[utils.MetaVoice].GetTotalValue() != float64(time.Hour) {
t.Errorf("Expected: %f, received: %f", float64(time.Hour), acnt.BalanceMap[utils.MetaVoice].GetTotalValue())
}
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(0))
m.NewAVP(avp.DestinationHost, avp.Mbit, 0, datatype.DiameterIdentity("CGR-DA"))
m.NewAVP(avp.DestinationRealm, avp.Mbit, 0, datatype.DiameterIdentity("cgrates.com"))
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("testDiamItEmulateTerminate")), // 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(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.OctetString("")), // 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
},
}),
}})
// ============================================
// prevent nil pointer dereference
// ============================================
if diamClnt == nil {
t.Fatal("Diameter client should not be nil")
}
if diamClnt.conn == nil {
t.Fatal("Diameter connection should not be nil")
}
if m == nil {
t.Fatal("The mesage to diameter should not be nil")
}
// ============================================
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([]any{"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 = "0" // 0 from sessions
if avps, err := msg.FindAVPsWithPath([]any{"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)
}
if err := apierRpc.Call(context.Background(), utils.APIerSv2GetAccount, attrs, &acnt); err != nil {
t.Error(err)
} else if acnt.BalanceMap[utils.MetaVoice].GetTotalValue() != float64(time.Hour) {
t.Errorf("Expected: %f, received: %f", float64(time.Hour), acnt.BalanceMap[utils.MetaVoice].GetTotalValue())
}
}