mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Merge branch 'master' of https://github.com/cgrates/cgrates
This commit is contained in:
@@ -21,6 +21,7 @@ package agents
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/sessions"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
@@ -174,7 +175,37 @@ func (smaEv *SMAsteriskEvent) ExtraParameters() (extraParams map[string]string)
|
||||
return
|
||||
}
|
||||
|
||||
func (smaEv *SMAsteriskEvent) AsSMGenericEvent() *sessions.SMGenericEvent {
|
||||
func (smaEv *SMAsteriskEvent) UpdateCGREvent(cgrEv *utils.CGREvent) error {
|
||||
resCGREv := *cgrEv
|
||||
switch smaEv.EventType() {
|
||||
case ARIChannelStateChange:
|
||||
resCGREv.Event[utils.EVENT_NAME] = SMASessionStart
|
||||
resCGREv.Event[utils.AnswerTime] = smaEv.Timestamp()
|
||||
case ARIChannelDestroyed:
|
||||
resCGREv.Event[utils.EVENT_NAME] = SMASessionTerminate
|
||||
resCGREv.Event[utils.DISCONNECT_CAUSE] = smaEv.DisconnectCause()
|
||||
if _, hasIt := resCGREv.Event[utils.AnswerTime]; !hasIt {
|
||||
resCGREv.Event[utils.Usage] = "0s"
|
||||
} else {
|
||||
if aTime, err := utils.IfaceAsTime(resCGREv.Event[utils.AnswerTime], config.CgrConfig().DefaultTimezone); err != nil {
|
||||
return err
|
||||
} else if aTime.IsZero() {
|
||||
resCGREv.Event[utils.Usage] = "0s"
|
||||
} else {
|
||||
actualTime, err := utils.ParseTimeDetectLayout(smaEv.Timestamp(), "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resCGREv.Event[utils.Usage] = actualTime.Sub(aTime).String()
|
||||
}
|
||||
}
|
||||
}
|
||||
*cgrEv = resCGREv
|
||||
return nil
|
||||
}
|
||||
|
||||
func (smaEv *SMAsteriskEvent) AsMapStringInterface() (mp map[string]interface{}) {
|
||||
mp = make(map[string]interface{})
|
||||
var evName string
|
||||
switch smaEv.EventType() {
|
||||
case ARIStasisStart:
|
||||
@@ -184,62 +215,144 @@ func (smaEv *SMAsteriskEvent) AsSMGenericEvent() *sessions.SMGenericEvent {
|
||||
case ARIChannelDestroyed:
|
||||
evName = SMASessionTerminate
|
||||
}
|
||||
smgEv := sessions.SMGenericEvent{utils.EVENT_NAME: evName}
|
||||
smgEv[utils.OriginID] = smaEv.ChannelID()
|
||||
mp[utils.EVENT_NAME] = evName
|
||||
mp[utils.OriginID] = smaEv.ChannelID()
|
||||
if smaEv.RequestType() != "" {
|
||||
smgEv[utils.RequestType] = smaEv.RequestType()
|
||||
mp[utils.RequestType] = smaEv.RequestType()
|
||||
}
|
||||
if smaEv.Tenant() != "" {
|
||||
smgEv[utils.Tenant] = smaEv.Tenant()
|
||||
mp[utils.Tenant] = smaEv.Tenant()
|
||||
}
|
||||
if smaEv.Category() != "" {
|
||||
smgEv[utils.Category] = smaEv.Category()
|
||||
mp[utils.Category] = smaEv.Category()
|
||||
}
|
||||
if smaEv.Subject() != "" {
|
||||
smgEv[utils.Subject] = smaEv.Subject()
|
||||
mp[utils.Subject] = smaEv.Subject()
|
||||
}
|
||||
smgEv[utils.OriginHost] = smaEv.OriginatorIP()
|
||||
smgEv[utils.Account] = smaEv.Account()
|
||||
smgEv[utils.Destination] = smaEv.Destination()
|
||||
smgEv[utils.SetupTime] = smaEv.Timestamp()
|
||||
mp[utils.OriginHost] = smaEv.OriginatorIP()
|
||||
mp[utils.Account] = smaEv.Account()
|
||||
mp[utils.Destination] = smaEv.Destination()
|
||||
mp[utils.SetupTime] = smaEv.SetupTime()
|
||||
if smaEv.Supplier() != "" {
|
||||
smgEv[utils.SUPPLIER] = smaEv.Supplier()
|
||||
mp[utils.SUPPLIER] = smaEv.Supplier()
|
||||
}
|
||||
for extraKey, extraVal := range smaEv.ExtraParameters() { // Append extraParameters
|
||||
smgEv[extraKey] = extraVal
|
||||
mp[extraKey] = extraVal
|
||||
}
|
||||
return &smgEv
|
||||
return
|
||||
}
|
||||
|
||||
// Updates fields in smgEv based on own fields
|
||||
// Using pointer so we update it directly in cache
|
||||
func (smaEv *SMAsteriskEvent) UpdateSMGEvent(smgEv *sessions.SMGenericEvent) error {
|
||||
resSMGEv := *smgEv
|
||||
switch smaEv.EventType() {
|
||||
case ARIChannelStateChange:
|
||||
if smaEv.ChannelState() == channelUp {
|
||||
resSMGEv[utils.EVENT_NAME] = SMASessionStart
|
||||
resSMGEv[utils.AnswerTime] = smaEv.Timestamp()
|
||||
// AsCDR converts KamEvent into CGREvent
|
||||
func (smaEv *SMAsteriskEvent) AsCGREvent(timezone string) (cgrEv *utils.CGREvent, err error) {
|
||||
setupTime, err := utils.ParseTimeDetectLayout(
|
||||
smaEv.Timestamp(), timezone)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cgrEv = &utils.CGREvent{
|
||||
Tenant: utils.FirstNonEmpty(smaEv.Tenant(),
|
||||
config.CgrConfig().DefaultTenant),
|
||||
ID: utils.UUIDSha1Prefix(),
|
||||
Time: &setupTime,
|
||||
Event: smaEv.AsMapStringInterface(),
|
||||
}
|
||||
return cgrEv, nil
|
||||
}
|
||||
|
||||
func (smaEv *SMAsteriskEvent) V1AuthorizeArgs() (args *sessions.V1AuthorizeArgs) {
|
||||
cgrEv, err := smaEv.AsCGREvent(config.CgrConfig().DefaultTimezone)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
args = &sessions.V1AuthorizeArgs{
|
||||
GetMaxUsage: true,
|
||||
CGREvent: *cgrEv,
|
||||
}
|
||||
// For the moment hardcoded only GetMaxUsage : true
|
||||
/*
|
||||
subsystems, has := kev[KamCGRSubsystems]
|
||||
if !has {
|
||||
return
|
||||
}
|
||||
case ARIChannelDestroyed:
|
||||
resSMGEv[utils.EVENT_NAME] = SMASessionTerminate
|
||||
resSMGEv[utils.DISCONNECT_CAUSE] = smaEv.DisconnectCause()
|
||||
if _, hasIt := resSMGEv[utils.AnswerTime]; !hasIt {
|
||||
resSMGEv[utils.Usage] = "0s"
|
||||
} else {
|
||||
if aTime, err := smgEv.GetAnswerTime(utils.META_DEFAULT, ""); err != nil {
|
||||
return err
|
||||
} else if aTime.IsZero() {
|
||||
resSMGEv[utils.Usage] = "0s"
|
||||
} else {
|
||||
actualTime, err := utils.ParseTimeDetectLayout(smaEv.Timestamp(), "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resSMGEv[utils.Usage] = actualTime.Sub(aTime).String()
|
||||
if strings.Index(subsystems, utils.MetaAccounts) == -1 {
|
||||
args.GetMaxUsage = false
|
||||
}
|
||||
if strings.Index(subsystems, utils.MetaResources) != -1 {
|
||||
args.AuthorizeResources = true
|
||||
}
|
||||
if strings.Index(subsystems, utils.MetaSuppliers) != -1 {
|
||||
args.GetSuppliers = true
|
||||
if strings.Index(subsystems, utils.MetaSuppliersEventCost) != -1 {
|
||||
args.SuppliersMaxCost = utils.MetaEventCost
|
||||
}
|
||||
if strings.Index(subsystems, utils.MetaSuppliersIgnoreErrors) != -1 {
|
||||
args.SuppliersIgnoreErrors = true
|
||||
}
|
||||
}
|
||||
}
|
||||
*smgEv = resSMGEv
|
||||
return nil
|
||||
if strings.Index(subsystems, utils.MetaAttributes) != -1 {
|
||||
args.GetAttributes = true
|
||||
}
|
||||
if strings.Index(subsystems, utils.MetaThresholds) != -1 {
|
||||
args.ProcessThresholds = utils.BoolPointer(true)
|
||||
}
|
||||
if strings.Index(subsystems, utils.MetaStats) != -1 {
|
||||
args.ProcessStatQueues = utils.BoolPointer(true)
|
||||
}
|
||||
*/
|
||||
return
|
||||
}
|
||||
|
||||
func (smaEv *SMAsteriskEvent) V1InitSessionArgs(cgrEv utils.CGREvent) (args *sessions.V1InitSessionArgs) {
|
||||
args = &sessions.V1InitSessionArgs{ // defaults
|
||||
InitSession: true,
|
||||
CGREvent: cgrEv,
|
||||
}
|
||||
/*
|
||||
subsystems, has := kev[KamCGRSubsystems]
|
||||
if !has {
|
||||
return
|
||||
}
|
||||
if strings.Index(subsystems, utils.MetaAccounts) == -1 {
|
||||
args.InitSession = false
|
||||
}
|
||||
if strings.Index(subsystems, utils.MetaResources) != -1 {
|
||||
args.AllocateResources = true
|
||||
}
|
||||
if strings.Index(subsystems, utils.MetaAttributes) != -1 {
|
||||
args.GetAttributes = true
|
||||
}
|
||||
if strings.Index(subsystems, utils.MetaThresholds) != -1 {
|
||||
args.ProcessThresholds = utils.BoolPointer(true)
|
||||
}
|
||||
if strings.Index(subsystems, utils.MetaStats) != -1 {
|
||||
args.ProcessStatQueues = utils.BoolPointer(true)
|
||||
}
|
||||
*/
|
||||
return
|
||||
}
|
||||
|
||||
func (smaEv *SMAsteriskEvent) V1TerminateSessionArgs(cgrEv utils.CGREvent) (args *sessions.V1TerminateSessionArgs) {
|
||||
args = &sessions.V1TerminateSessionArgs{ // defaults
|
||||
TerminateSession: true,
|
||||
CGREvent: cgrEv,
|
||||
}
|
||||
/*
|
||||
subsystems, has := kev[KamCGRSubsystems]
|
||||
if !has {
|
||||
return
|
||||
}
|
||||
if strings.Index(subsystems, utils.MetaAccounts) == -1 {
|
||||
args.TerminateSession = false
|
||||
}
|
||||
if strings.Index(subsystems, utils.MetaResources) != -1 {
|
||||
args.ReleaseResources = true
|
||||
}
|
||||
if strings.Index(subsystems, utils.MetaThresholds) != -1 {
|
||||
args.ProcessThresholds = utils.BoolPointer(true)
|
||||
}
|
||||
if strings.Index(subsystems, utils.MetaStats) != -1 {
|
||||
args.ProcessStatQueues = utils.BoolPointer(true)
|
||||
}
|
||||
*/
|
||||
return
|
||||
}
|
||||
|
||||
@@ -21,9 +21,6 @@ import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/cgrates/cgrates/sessions"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -328,212 +325,3 @@ func TestSMAEventExtraParameters(t *testing.T) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", expExtraParams, extraParams)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func TestSMAEventUpdateFromEvent(t *testing.T) {
|
||||
var ev map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(stasisStart), &ev); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
smaEv := NewSMAsteriskEvent(ev, "127.0.0.1")
|
||||
ev = make(map[string]interface{})
|
||||
if err := json.Unmarshal([]byte(channelAnsweredDestroyed), &ev); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
smaEv2 := NewSMAsteriskEvent(ev, "127.0.0.1")
|
||||
smaEv.UpdateFromEvent(smaEv2)
|
||||
eSMAEv := &SMAsteriskEvent{
|
||||
ariEv: map[string]interface{}{
|
||||
"type": "ChannelDestroyed",
|
||||
"args": []interface{}{"cgr_reqtype=*prepaid", "cgr_destination=1003", "extra1=val1", "extra2=val2"},
|
||||
"timestamp": "2016-09-12T13:54:27.335+0200",
|
||||
"application": "cgrates_auth",
|
||||
"cause_txt": "Normal Clearing",
|
||||
"channel": map[string]interface{}{
|
||||
"id": "1473681228.6",
|
||||
"state": "Up",
|
||||
"name": "PJSIP/1001-00000004",
|
||||
"caller": map[string]interface{}{
|
||||
"name": "1001",
|
||||
"number": "1001"},
|
||||
"language": "en",
|
||||
"connected": map[string]interface{}{
|
||||
"name": "",
|
||||
"number": "1002"},
|
||||
"accountcode": "",
|
||||
"dialplan": map[string]interface{}{
|
||||
"context": "internal",
|
||||
"exten": "1002",
|
||||
"priority": 3.0},
|
||||
"creationtime": "2016-09-12T13:53:48.918+0200"},
|
||||
"cause": 16.0},
|
||||
asteriskIP: "127.0.0.1",
|
||||
cachedFields: map[string]string{"cgr_reqtype": "*prepaid",
|
||||
"cgr_destination": "1003", "extra1": "val1", "extra2": "val2"},
|
||||
}
|
||||
if !reflect.DeepEqual(eSMAEv, smaEv) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eSMAEv, smaEv)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
//Here
|
||||
func TestSMAEventAsSMGenericEvent(t *testing.T) {
|
||||
var ev map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(stasisStart), &ev); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
eSMGEv := &sessions.SMGenericEvent{
|
||||
utils.EVENT_NAME: SMAAuthorization,
|
||||
utils.OriginID: "1473681228.6",
|
||||
utils.RequestType: "*prepaid",
|
||||
utils.OriginHost: "127.0.0.1",
|
||||
utils.Account: "1001",
|
||||
utils.Destination: "1002",
|
||||
utils.SetupTime: "2016-09-12T13:53:48.919+0200",
|
||||
utils.SUPPLIER: "supplier1",
|
||||
"extra1": "val1",
|
||||
"extra2": "val2",
|
||||
}
|
||||
smaEv := NewSMAsteriskEvent(ev, "127.0.0.1")
|
||||
if smgEv := smaEv.AsSMGenericEvent(); !reflect.DeepEqual(eSMGEv, smgEv) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eSMGEv, smgEv)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSMAEventUpdateSMGEventAnswered(t *testing.T) {
|
||||
var ev map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(channelStateChange), &ev); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
smaEv := NewSMAsteriskEvent(ev, "127.0.0.1")
|
||||
smgEv := &sessions.SMGenericEvent{
|
||||
utils.EVENT_NAME: SMAAuthorization,
|
||||
utils.OriginID: "1473681228.6",
|
||||
utils.RequestType: "*prepaid",
|
||||
utils.OriginHost: "127.0.0.1",
|
||||
utils.Account: "1001",
|
||||
utils.Destination: "1003",
|
||||
utils.SetupTime: "2016-09-12T13:53:48.919+0200",
|
||||
"extra1": "val1",
|
||||
"extra2": "val2",
|
||||
}
|
||||
eSMGEv := &sessions.SMGenericEvent{
|
||||
utils.EVENT_NAME: SMASessionStart,
|
||||
utils.OriginID: "1473681228.6",
|
||||
utils.RequestType: "*prepaid",
|
||||
utils.OriginHost: "127.0.0.1",
|
||||
utils.Account: "1001",
|
||||
utils.Destination: "1003",
|
||||
utils.SetupTime: "2016-09-12T13:53:48.919+0200",
|
||||
utils.AnswerTime: "2016-09-12T13:53:52.110+0200",
|
||||
"extra1": "val1",
|
||||
"extra2": "val2",
|
||||
}
|
||||
if err := smaEv.UpdateSMGEvent(smgEv); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eSMGEv, smgEv) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eSMGEv, smgEv)
|
||||
}
|
||||
// Apply update using a terminate event
|
||||
ev = make(map[string]interface{})
|
||||
if err = json.Unmarshal([]byte(channelAnsweredDestroyed), &ev); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
smaEv = NewSMAsteriskEvent(ev, "127.0.0.1")
|
||||
eSMGEv = &sessions.SMGenericEvent{
|
||||
utils.EVENT_NAME: SMASessionTerminate,
|
||||
utils.OriginID: "1473681228.6",
|
||||
utils.RequestType: "*prepaid",
|
||||
utils.OriginHost: "127.0.0.1",
|
||||
utils.Account: "1001",
|
||||
utils.Destination: "1003",
|
||||
utils.SetupTime: "2016-09-12T13:53:48.919+0200",
|
||||
utils.AnswerTime: "2016-09-12T13:53:52.110+0200",
|
||||
utils.Usage: "35.225s",
|
||||
utils.DISCONNECT_CAUSE: "Normal Clearing",
|
||||
"extra1": "val1",
|
||||
"extra2": "val2",
|
||||
}
|
||||
if err := smaEv.UpdateSMGEvent(smgEv); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eSMGEv, smgEv) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eSMGEv, smgEv)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSMAEventUpdateSMGEventUnaswered(t *testing.T) {
|
||||
smgEv := &sessions.SMGenericEvent{
|
||||
utils.EVENT_NAME: SMAAuthorization,
|
||||
utils.OriginID: "1473681228.6",
|
||||
utils.RequestType: "*prepaid",
|
||||
utils.OriginHost: "127.0.0.1",
|
||||
utils.Account: "1001",
|
||||
utils.Destination: "1003",
|
||||
utils.SetupTime: "2016-09-12T13:53:48.919+0200",
|
||||
"extra1": "val1",
|
||||
"extra2": "val2",
|
||||
}
|
||||
eSMGEv := &sessions.SMGenericEvent{
|
||||
utils.EVENT_NAME: SMASessionTerminate,
|
||||
utils.OriginID: "1473681228.6",
|
||||
utils.RequestType: "*prepaid",
|
||||
utils.OriginHost: "127.0.0.1",
|
||||
utils.Account: "1001",
|
||||
utils.Destination: "1003",
|
||||
utils.SetupTime: "2016-09-12T13:53:48.919+0200",
|
||||
utils.Usage: "0s",
|
||||
utils.DISCONNECT_CAUSE: "Normal Clearing",
|
||||
"extra1": "val1",
|
||||
"extra2": "val2",
|
||||
}
|
||||
// Apply update using a terminate event
|
||||
ev := make(map[string]interface{})
|
||||
if err := json.Unmarshal([]byte(channelUnansweredDestroyed), &ev); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
smaEv := NewSMAsteriskEvent(ev, "127.0.0.1")
|
||||
if err := smaEv.UpdateSMGEvent(smgEv); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eSMGEv, smgEv) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eSMGEv, smgEv)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSMAEventUpdateSMGEventBusy(t *testing.T) {
|
||||
smgEv := &sessions.SMGenericEvent{
|
||||
utils.EVENT_NAME: SMAAuthorization,
|
||||
utils.OriginID: "1473681228.6",
|
||||
utils.RequestType: "*prepaid",
|
||||
utils.OriginHost: "127.0.0.1",
|
||||
utils.Account: "1001",
|
||||
utils.Destination: "1003",
|
||||
utils.SetupTime: "2016-09-12T13:53:48.919+0200",
|
||||
"extra1": "val1",
|
||||
"extra2": "val2",
|
||||
}
|
||||
eSMGEv := &sessions.SMGenericEvent{
|
||||
utils.EVENT_NAME: SMASessionTerminate,
|
||||
utils.OriginID: "1473681228.6",
|
||||
utils.RequestType: "*prepaid",
|
||||
utils.OriginHost: "127.0.0.1",
|
||||
utils.Account: "1001",
|
||||
utils.Destination: "1003",
|
||||
utils.SetupTime: "2016-09-12T13:53:48.919+0200",
|
||||
utils.Usage: "0s",
|
||||
utils.DISCONNECT_CAUSE: "User busy",
|
||||
"extra1": "val1",
|
||||
"extra2": "val2",
|
||||
}
|
||||
// Apply update using a terminate event
|
||||
ev := make(map[string]interface{})
|
||||
if err := json.Unmarshal([]byte(channelBusyDestroyed), &ev); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
smaEv := NewSMAsteriskEvent(ev, "127.0.0.1")
|
||||
if err := smaEv.UpdateSMGEvent(smgEv); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eSMGEv, smgEv) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", eSMGEv, smgEv)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,30 +48,33 @@ const (
|
||||
SMASessionTerminate = "SMA_SESSION_TERMINATE"
|
||||
)
|
||||
|
||||
func NewSMAsterisk(cgrCfg *config.CGRConfig, astConnIdx int, smgConn *utils.BiRPCInternalClient) (*SMAsterisk, error) {
|
||||
sma := &SMAsterisk{cgrCfg: cgrCfg, smg: smgConn,
|
||||
eventsCache: make(map[string]*sessions.SMGenericEvent)}
|
||||
func NewAsteriskAgent(cgrCfg *config.CGRConfig, astConnIdx int,
|
||||
smgConn *utils.BiRPCInternalClient) (*AsteriskAgent, error) {
|
||||
sma := &AsteriskAgent{cgrCfg: cgrCfg, smg: smgConn,
|
||||
eventsCache: make(map[string]*utils.CGREvent)}
|
||||
sma.smg.SetClientConn(sma) // pass the connection to SMA back into smg so we can receive the disconnects
|
||||
return sma, nil
|
||||
}
|
||||
|
||||
type SMAsterisk struct {
|
||||
type AsteriskAgent struct {
|
||||
cgrCfg *config.CGRConfig // Separate from smCfg since there can be multiple
|
||||
astConnIdx int
|
||||
smg *utils.BiRPCInternalClient
|
||||
astConn *aringo.ARInGO
|
||||
astEvChan chan map[string]interface{}
|
||||
astErrChan chan error
|
||||
eventsCache map[string]*sessions.SMGenericEvent // used to gather information about events during various phases
|
||||
evCacheMux sync.RWMutex // Protect eventsCache
|
||||
eventsCache map[string]*utils.CGREvent // used to gather information about events during various phases
|
||||
evCacheMux sync.RWMutex // Protect eventsCache
|
||||
}
|
||||
|
||||
func (sma *SMAsterisk) connectAsterisk() (err error) {
|
||||
func (sma *AsteriskAgent) connectAsterisk() (err error) {
|
||||
connCfg := sma.cgrCfg.AsteriskAgentCfg().AsteriskConns[sma.astConnIdx]
|
||||
sma.astEvChan = make(chan map[string]interface{})
|
||||
sma.astErrChan = make(chan error)
|
||||
sma.astConn, err = aringo.NewARInGO(fmt.Sprintf("ws://%s/ari/events?api_key=%s:%s&app=%s", connCfg.Address, connCfg.User, connCfg.Password, CGRAuthAPP), "http://cgrates.org",
|
||||
connCfg.User, connCfg.Password, fmt.Sprintf("%s %s", utils.CGRateS, utils.VERSION), sma.astEvChan, sma.astErrChan, connCfg.ConnectAttempts, connCfg.Reconnects)
|
||||
sma.astConn, err = aringo.NewARInGO(fmt.Sprintf("ws://%s/ari/events?api_key=%s:%s&app=%s",
|
||||
connCfg.Address, connCfg.User, connCfg.Password, CGRAuthAPP), "http://cgrates.org",
|
||||
connCfg.User, connCfg.Password, fmt.Sprintf("%s %s", utils.CGRateS, utils.VERSION),
|
||||
sma.astEvChan, sma.astErrChan, connCfg.ConnectAttempts, connCfg.Reconnects)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -79,7 +82,7 @@ func (sma *SMAsterisk) connectAsterisk() (err error) {
|
||||
}
|
||||
|
||||
// Called to start the service
|
||||
func (sma *SMAsterisk) ListenAndServe() (err error) {
|
||||
func (sma *AsteriskAgent) ListenAndServe() (err error) {
|
||||
if err := sma.connectAsterisk(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -88,7 +91,8 @@ func (sma *SMAsterisk) ListenAndServe() (err error) {
|
||||
case err = <-sma.astErrChan:
|
||||
return
|
||||
case astRawEv := <-sma.astEvChan:
|
||||
smAsteriskEvent := NewSMAsteriskEvent(astRawEv, strings.Split(sma.cgrCfg.AsteriskAgentCfg().AsteriskConns[sma.astConnIdx].Address, ":")[0])
|
||||
smAsteriskEvent := NewSMAsteriskEvent(astRawEv,
|
||||
strings.Split(sma.cgrCfg.AsteriskAgentCfg().AsteriskConns[sma.astConnIdx].Address, ":")[0])
|
||||
switch smAsteriskEvent.EventType() {
|
||||
case ARIStasisStart:
|
||||
go sma.handleStasisStart(smAsteriskEvent)
|
||||
@@ -99,52 +103,69 @@ func (sma *SMAsterisk) ListenAndServe() (err error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
panic("<SMAsterisk> ListenAndServe out of select")
|
||||
panic("<AsteriskAgent> ListenAndServe out of select")
|
||||
}
|
||||
|
||||
// hangupChannel will disconnect from CGRateS side with congestion reason
|
||||
func (sma *SMAsterisk) hangupChannel(channelID string) (err error) {
|
||||
func (sma *AsteriskAgent) hangupChannel(channelID string) (err error) {
|
||||
_, err = sma.astConn.Call(aringo.HTTP_DELETE, fmt.Sprintf("http://%s/ari/channels/%s",
|
||||
sma.cgrCfg.AsteriskAgentCfg().AsteriskConns[sma.astConnIdx].Address, channelID),
|
||||
url.Values{"reason": {"congestion"}})
|
||||
return
|
||||
}
|
||||
|
||||
func (sma *SMAsterisk) handleStasisStart(ev *SMAsteriskEvent) {
|
||||
func (sma *AsteriskAgent) handleStasisStart(ev *SMAsteriskEvent) {
|
||||
// Subscribe for channel updates even after we leave Stasis
|
||||
if _, err := sma.astConn.Call(aringo.HTTP_POST, fmt.Sprintf("http://%s/ari/applications/%s/subscription?eventSource=channel:%s",
|
||||
sma.cgrCfg.AsteriskAgentCfg().AsteriskConns[sma.astConnIdx].Address, CGRAuthAPP, ev.ChannelID()), nil); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<SMAsterisk> Error: %s when subscribing to events for channelID: %s", err.Error(), ev.ChannelID()))
|
||||
if _, err := sma.astConn.Call(aringo.HTTP_POST,
|
||||
fmt.Sprintf("http://%s/ari/applications/%s/subscription?eventSource=channel:%s",
|
||||
sma.cgrCfg.AsteriskAgentCfg().AsteriskConns[sma.astConnIdx].Address,
|
||||
CGRAuthAPP, ev.ChannelID()), nil); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> Error: %s when subscribingto events for channelID: %s",
|
||||
utils.AsteriskAgent, err.Error(), ev.ChannelID()))
|
||||
// Since we got error, disconnect channel
|
||||
if err := sma.hangupChannel(ev.ChannelID()); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<SMAsterisk> Error: %s when attempting to disconnect channelID: %s", err.Error(), ev.ChannelID()))
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> Error: %s when attempting to disconnect channelID: %s",
|
||||
utils.AsteriskAgent, err.Error(), ev.ChannelID()))
|
||||
}
|
||||
return
|
||||
}
|
||||
// Query the SMG via RPC for maxUsage
|
||||
var maxUsage float64
|
||||
smgEv := ev.AsSMGenericEvent()
|
||||
if err := sma.smg.Call("SMGenericV1.GetMaxUsage", *smgEv, &maxUsage); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<SMAsterisk> Error: %s when attempting to authorize session for channelID: %s", err.Error(), ev.ChannelID()))
|
||||
//authorize Session
|
||||
authArgs := ev.V1AuthorizeArgs()
|
||||
if authArgs == nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> event: %s cannot generate auth session arguments",
|
||||
utils.AsteriskAgent, ev.ChannelID()))
|
||||
return
|
||||
}
|
||||
var authReply sessions.V1AuthorizeReply
|
||||
if err := sma.smg.Call(utils.SessionSv1AuthorizeEvent, authArgs, &authReply); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> Error: %s when attempting to authorize session for channelID: %s",
|
||||
utils.AsteriskAgent, err.Error(), ev.ChannelID()))
|
||||
if err := sma.hangupChannel(ev.ChannelID()); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<SMAsterisk> Error: %s when attempting to disconnect channelID: %s", err.Error(), ev.ChannelID()))
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> Error: %s when attempting to disconnect channelID: %s",
|
||||
utils.AsteriskAgent, err.Error(), ev.ChannelID()))
|
||||
}
|
||||
return
|
||||
}
|
||||
if maxUsage == 0 {
|
||||
if authReply.MaxUsage != nil && *authReply.MaxUsage == time.Duration(0) {
|
||||
if err := sma.hangupChannel(ev.ChannelID()); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<SMAsterisk> Error: %s when attempting to disconnect channelID: %s", err.Error(), ev.ChannelID()))
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> Error: %s when attempting to disconnect channelID: %s",
|
||||
utils.AsteriskAgent, err.Error(), ev.ChannelID()))
|
||||
}
|
||||
return
|
||||
} else if maxUsage != -1 {
|
||||
} else if *authReply.MaxUsage != time.Duration(-1) {
|
||||
// Set absolute timeout for non-postpaid calls
|
||||
if _, err := sma.astConn.Call(aringo.HTTP_POST, fmt.Sprintf("http://%s/ari/channels/%s/variable?variable=%s", // Asterisk having issue with variable terminating empty so harcoding param in url
|
||||
sma.cgrCfg.AsteriskAgentCfg().AsteriskConns[sma.astConnIdx].Address, ev.ChannelID(), CGRMaxSessionTime),
|
||||
url.Values{"value": {strconv.FormatFloat(maxUsage*1000, 'f', -1, 64)}}); err != nil { // Asterisk expects value in ms
|
||||
utils.Logger.Err(fmt.Sprintf("<SMAsterisk> Error: %s when setting %s for channelID: %s", err.Error(), CGRMaxSessionTime, ev.ChannelID()))
|
||||
if _, err := sma.astConn.Call(aringo.HTTP_POST,
|
||||
fmt.Sprintf("http://%s/ari/channels/%s/variable?variable=%s&value=%d", // Asterisk having issue with variable terminating empty so harcoding param in url
|
||||
sma.cgrCfg.AsteriskAgentCfg().AsteriskConns[sma.astConnIdx].Address,
|
||||
ev.ChannelID(), CGRMaxSessionTime, int64(authReply.MaxUsage.Seconds()*1000)),
|
||||
url.Values{"value": {strconv.FormatFloat(
|
||||
authReply.MaxUsage.Seconds()*1000, 'f', -1, 64)}}); err != nil { // Asterisk expects value in ms
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> Error: %s when setting %s for channelID: %s",
|
||||
utils.AsteriskAgent, err.Error(), CGRMaxSessionTime, ev.ChannelID()))
|
||||
// Since we got error, disconnect channel
|
||||
if err := sma.hangupChannel(ev.ChannelID()); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<SMAsterisk> Error: %s when attempting to disconnect channelID: %s", err.Error(), ev.ChannelID()))
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> Error: %s when attempting to disconnect channelID: %s",
|
||||
utils.AsteriskAgent, err.Error(), ev.ChannelID()))
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -152,108 +173,133 @@ func (sma *SMAsterisk) handleStasisStart(ev *SMAsteriskEvent) {
|
||||
|
||||
// Exit channel from stasis
|
||||
if _, err := sma.astConn.Call(aringo.HTTP_POST, fmt.Sprintf("http://%s/ari/channels/%s/continue",
|
||||
sma.cgrCfg.AsteriskAgentCfg().AsteriskConns[sma.astConnIdx].Address, ev.ChannelID()), nil); err != nil {
|
||||
sma.cgrCfg.AsteriskAgentCfg().AsteriskConns[sma.astConnIdx].Address,
|
||||
ev.ChannelID()), nil); err != nil {
|
||||
}
|
||||
// Done with processing event, cache it for later use
|
||||
sma.evCacheMux.Lock()
|
||||
sma.eventsCache[ev.ChannelID()] = smgEv
|
||||
sma.eventsCache[ev.ChannelID()] = &authArgs.CGREvent
|
||||
sma.evCacheMux.Unlock()
|
||||
}
|
||||
|
||||
// Ussually channelUP
|
||||
func (sma *SMAsterisk) handleChannelStateChange(ev *SMAsteriskEvent) {
|
||||
func (sma *AsteriskAgent) handleChannelStateChange(ev *SMAsteriskEvent) {
|
||||
if ev.ChannelState() != channelUp {
|
||||
return
|
||||
}
|
||||
sma.evCacheMux.RLock()
|
||||
smgEv, hasIt := sma.eventsCache[ev.ChannelID()]
|
||||
cgrEv, hasIt := sma.eventsCache[ev.ChannelID()]
|
||||
sma.evCacheMux.RUnlock()
|
||||
if !hasIt { // Not handled by us
|
||||
return
|
||||
}
|
||||
sma.evCacheMux.Lock()
|
||||
err := ev.UpdateSMGEvent(smgEv) // Updates the event directly in the cache
|
||||
err := ev.UpdateCGREvent(cgrEv) // Updates the event directly in the cache
|
||||
sma.evCacheMux.Unlock()
|
||||
if err != nil {
|
||||
utils.Logger.Err(
|
||||
fmt.Sprintf("<SMAsterisk> Error: %s when attempting to initiate session for channelID: %s",
|
||||
err.Error(), ev.ChannelID()))
|
||||
fmt.Sprintf("<%s> Error: %s when attempting to initiate session for channelID: %s",
|
||||
utils.AsteriskAgent, err.Error(), ev.ChannelID()))
|
||||
if err := sma.hangupChannel(ev.ChannelID()); err != nil {
|
||||
utils.Logger.Err(
|
||||
fmt.Sprintf("<SMAsterisk> Error: %s when attempting to disconnect channelID: %s",
|
||||
err.Error(), ev.ChannelID()))
|
||||
fmt.Sprintf("<%s> Error: %s when attempting to disconnect channelID: %s",
|
||||
utils.AsteriskAgent, err.Error(), ev.ChannelID()))
|
||||
}
|
||||
return
|
||||
}
|
||||
var maxUsage time.Duration
|
||||
if err := sma.smg.Call(utils.SMGenericV2InitiateSession,
|
||||
*smgEv, &maxUsage); err != nil {
|
||||
// populate init session args
|
||||
initSessionArgs := ev.V1InitSessionArgs(*cgrEv)
|
||||
if initSessionArgs == nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> event: %s cannot generate init session arguments",
|
||||
utils.AsteriskAgent, ev.ChannelID()))
|
||||
return
|
||||
}
|
||||
|
||||
//initit Session
|
||||
var initReply sessions.V1InitSessionReply
|
||||
if err := sma.smg.Call(utils.SessionSv1InitiateSession,
|
||||
initSessionArgs, &initReply); err != nil {
|
||||
utils.Logger.Err(
|
||||
fmt.Sprintf("<SMAsterisk> Error: %s when attempting to initiate session for channelID: %s",
|
||||
err.Error(), ev.ChannelID()))
|
||||
fmt.Sprintf("<%s> Error: %s when attempting to initiate session for channelID: %s",
|
||||
utils.AsteriskAgent, err.Error(), ev.ChannelID()))
|
||||
if err := sma.hangupChannel(ev.ChannelID()); err != nil {
|
||||
utils.Logger.Err(
|
||||
fmt.Sprintf("<SMAsterisk> Error: %s when attempting to disconnect channelID: %s",
|
||||
err.Error(), ev.ChannelID()))
|
||||
fmt.Sprintf("<%s> Error: %s when attempting to disconnect channelID: %s",
|
||||
utils.AsteriskAgent, err.Error(), ev.ChannelID()))
|
||||
}
|
||||
return
|
||||
} else if maxUsage == 0 {
|
||||
} else if initReply.MaxUsage != nil && *initReply.MaxUsage == time.Duration(0) {
|
||||
if err := sma.hangupChannel(ev.ChannelID()); err != nil {
|
||||
utils.Logger.Err(
|
||||
fmt.Sprintf("<SMAsterisk> Error: %s when attempting to disconnect channelID: %s",
|
||||
err.Error(), ev.ChannelID()))
|
||||
fmt.Sprintf("<%s> Error: %s when attempting to disconnect channelID: %s",
|
||||
utils.AsteriskAgent, err.Error(), ev.ChannelID()))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Channel disconnect
|
||||
func (sma *SMAsterisk) handleChannelDestroyed(ev *SMAsteriskEvent) {
|
||||
func (sma *AsteriskAgent) handleChannelDestroyed(ev *SMAsteriskEvent) {
|
||||
sma.evCacheMux.RLock()
|
||||
smgEv, hasIt := sma.eventsCache[ev.ChannelID()]
|
||||
cgrEv, hasIt := sma.eventsCache[ev.ChannelID()]
|
||||
sma.evCacheMux.RUnlock()
|
||||
if !hasIt { // Not handled by us
|
||||
return
|
||||
}
|
||||
sma.evCacheMux.Lock()
|
||||
err := ev.UpdateSMGEvent(smgEv) // Updates the event directly in the cache
|
||||
err := ev.UpdateCGREvent(cgrEv) // Updates the event directly in the cache
|
||||
sma.evCacheMux.Unlock()
|
||||
if err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<SMAsterisk> Error: %s when attempting to initiate session for channelID: %s", err.Error(), ev.ChannelID()))
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> Error: %s when attempting to initiate session for channelID: %s",
|
||||
utils.AsteriskAgent, err.Error(), ev.ChannelID()))
|
||||
if err := sma.hangupChannel(ev.ChannelID()); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<SMAsterisk> Error: %s when attempting to disconnect channelID: %s", err.Error(), ev.ChannelID()))
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> Error: %s when attempting to disconnect channelID: %s",
|
||||
utils.AsteriskAgent, err.Error(), ev.ChannelID()))
|
||||
}
|
||||
return
|
||||
}
|
||||
// populate terminate session args
|
||||
tsArgs := ev.V1TerminateSessionArgs(*cgrEv)
|
||||
if tsArgs == nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> event: %s cannot generate terminate session arguments",
|
||||
utils.AsteriskAgent, ev.ChannelID()))
|
||||
return
|
||||
}
|
||||
|
||||
var reply string
|
||||
if err := sma.smg.Call("SMGenericV1.TerminateSession", *smgEv, &reply); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<SMAsterisk> Error: %s when attempting to terminate session for channelID: %s", err.Error(), ev.ChannelID()))
|
||||
if err := sma.smg.Call(utils.SessionSv1TerminateSession,
|
||||
tsArgs, &reply); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> Error: %s when attempting to terminate session for channelID: %s",
|
||||
utils.AsteriskAgent, err.Error(), ev.ChannelID()))
|
||||
}
|
||||
if sma.cgrCfg.AsteriskAgentCfg().CreateCDR {
|
||||
if err := sma.smg.Call("SMGenericV1.ProcessCDR", *smgEv, &reply); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<SMAsterisk> Error: %s when attempting to process CDR for channelID: %s", err.Error(), ev.ChannelID()))
|
||||
if err := sma.smg.Call(utils.SessionSv1ProcessCDR, *cgrEv, &reply); err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<%s> Error: %s when attempting to process CDR for channelID: %s",
|
||||
utils.AsteriskAgent, err.Error(), ev.ChannelID()))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Called to shutdown the service
|
||||
func (sma *SMAsterisk) ServiceShutdown() error {
|
||||
func (sma *AsteriskAgent) ServiceShutdown() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Internal method to disconnect session in asterisk
|
||||
func (sma *SMAsterisk) V1DisconnectSession(args utils.AttrDisconnectSession, reply *string) error {
|
||||
func (sma *AsteriskAgent) V1DisconnectSession(args utils.AttrDisconnectSession, reply *string) error {
|
||||
channelID := sessions.SMGenericEvent(args.EventStart).GetOriginID(utils.META_DEFAULT)
|
||||
if err := sma.hangupChannel(channelID); err != nil {
|
||||
utils.Logger.Err(
|
||||
fmt.Sprintf("<SMAsterisk> Error: %s when attempting to disconnect channelID: %s",
|
||||
err.Error(), channelID))
|
||||
fmt.Sprintf("<%s> Error: %s when attempting to disconnect channelID: %s",
|
||||
utils.AsteriskAgent, err.Error(), channelID))
|
||||
}
|
||||
*reply = utils.OK
|
||||
return nil
|
||||
}
|
||||
|
||||
// rpcclient.RpcClientConnection interface
|
||||
func (sma *SMAsterisk) Call(serviceMethod string, args interface{}, reply interface{}) error {
|
||||
func (sma *AsteriskAgent) Call(serviceMethod string, args interface{}, reply interface{}) error {
|
||||
return utils.RPCCall(sma, serviceMethod, args, reply)
|
||||
}
|
||||
|
||||
@@ -241,7 +241,7 @@ func startAsteriskAgent(internalSMGChan chan rpcclient.RpcClientConnection, exit
|
||||
internalSMGChan <- smgRpcConn
|
||||
birpcClnt := utils.NewBiRPCInternalClient(smgRpcConn.(*sessions.SMGeneric))
|
||||
for connIdx := range cfg.AsteriskAgentCfg().AsteriskConns { // Instantiate connections towards asterisk servers
|
||||
sma, err := agents.NewSMAsterisk(cfg, connIdx, birpcClnt)
|
||||
sma, err := agents.NewAsteriskAgent(cfg, connIdx, birpcClnt)
|
||||
if err != nil {
|
||||
utils.Logger.Err(fmt.Sprintf("<SMAsterisk> error: %s!", err))
|
||||
exitChan <- true
|
||||
|
||||
69
data/conf/samples/tutmongojson/cgrates.json
Normal file
69
data/conf/samples/tutmongojson/cgrates.json
Normal file
@@ -0,0 +1,69 @@
|
||||
{
|
||||
// CGRateS Configuration file
|
||||
|
||||
|
||||
"general": {
|
||||
"log_level": 7,
|
||||
"reply_timeout": "30s",
|
||||
"dbdata_encoding": "json",
|
||||
},
|
||||
|
||||
|
||||
"listen": {
|
||||
"rpc_json": ":2012",
|
||||
"rpc_gob": ":2013",
|
||||
"http": ":2080",
|
||||
},
|
||||
|
||||
|
||||
"data_db": {
|
||||
"db_type": "mongo",
|
||||
"db_name": "10",
|
||||
"db_port": 27017,
|
||||
},
|
||||
|
||||
|
||||
"stor_db": {
|
||||
"db_type": "mongo",
|
||||
"db_port": 27017,
|
||||
},
|
||||
|
||||
|
||||
"cache":{
|
||||
"destinations": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"reverse_destinations": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"rating_plans": {"limit": 10000, "ttl":"0s","precache": true},
|
||||
"rating_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"lcr_rules": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"cdr_stats": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"actions": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"action_plans": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"account_action_plans": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"action_triggers": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"shared_groups": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"aliases": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"reverse_aliases": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"derived_chargers": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"resource_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"resources": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"statqueues": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"statqueue_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"thresholds": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"threshold_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"filters": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"supplier_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"attribute_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"resource_filter_indexes" :{"limit": 10000, "ttl":"0s"},
|
||||
"resource_filter_revindexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"stat_filter_indexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"stat_filter_revindexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"threshold_filter_indexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"threshold_filter_revindexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"supplier_filter_indexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"supplier_filter_revindexes" :{"limit": 10000, "ttl":"0s"},
|
||||
"attribute_filter_indexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"attribute_filter_revindexes" : {"limit": 10000, "ttl":"0s"},
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
69
data/conf/samples/tutmongomsgpack/cgrates.json
Normal file
69
data/conf/samples/tutmongomsgpack/cgrates.json
Normal file
@@ -0,0 +1,69 @@
|
||||
{
|
||||
// CGRateS Configuration file
|
||||
|
||||
|
||||
"general": {
|
||||
"log_level": 7,
|
||||
"reply_timeout": "30s",
|
||||
"dbdata_encoding": "msgpack",
|
||||
},
|
||||
|
||||
|
||||
"listen": {
|
||||
"rpc_json": ":2012",
|
||||
"rpc_gob": ":2013",
|
||||
"http": ":2080",
|
||||
},
|
||||
|
||||
|
||||
"data_db": {
|
||||
"db_type": "mongo",
|
||||
"db_name": "11",
|
||||
"db_port": 27017,
|
||||
},
|
||||
|
||||
|
||||
"stor_db": {
|
||||
"db_type": "mongo",
|
||||
"db_port": 27017,
|
||||
},
|
||||
|
||||
|
||||
"cache":{
|
||||
"destinations": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"reverse_destinations": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"rating_plans": {"limit": 10000, "ttl":"0s","precache": true},
|
||||
"rating_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"lcr_rules": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"cdr_stats": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"actions": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"action_plans": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"account_action_plans": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"action_triggers": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"shared_groups": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"aliases": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"reverse_aliases": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"derived_chargers": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"resource_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"resources": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"statqueues": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"statqueue_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"thresholds": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"threshold_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"filters": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"supplier_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"attribute_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"resource_filter_indexes" :{"limit": 10000, "ttl":"0s"},
|
||||
"resource_filter_revindexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"stat_filter_indexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"stat_filter_revindexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"threshold_filter_indexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"threshold_filter_revindexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"supplier_filter_indexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"supplier_filter_revindexes" :{"limit": 10000, "ttl":"0s"},
|
||||
"attribute_filter_indexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"attribute_filter_revindexes" : {"limit": 10000, "ttl":"0s"},
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
67
data/conf/samples/tutmysqljson/cgrates.json
Normal file
67
data/conf/samples/tutmysqljson/cgrates.json
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
// CGRateS Configuration file
|
||||
//
|
||||
|
||||
|
||||
"general": {
|
||||
"log_level": 7,
|
||||
"dbdata_encoding": "json", // encoding used to store object data in strings: <msgpack|json>
|
||||
},
|
||||
|
||||
|
||||
"listen": {
|
||||
"rpc_json": ":2012",
|
||||
"rpc_gob": ":2013",
|
||||
"http": ":2080",
|
||||
},
|
||||
|
||||
"data_db": { // database used to store runtime data (eg: accounts, cdr stats)
|
||||
"db_type": "redis", // data_db type: <redis|mongo>
|
||||
"db_port": 6379, // data_db port to reach the database
|
||||
"db_name": "10", // data_db database name to connect to
|
||||
|
||||
},
|
||||
|
||||
"stor_db": {
|
||||
"db_password": "CGRateS.org",
|
||||
},
|
||||
|
||||
|
||||
"cache":{
|
||||
"destinations": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"reverse_destinations": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"rating_plans": {"limit": 10000, "ttl":"0s","precache": true},
|
||||
"rating_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"lcr_rules": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"cdr_stats": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"actions": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"action_plans": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"account_action_plans": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"action_triggers": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"shared_groups": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"aliases": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"reverse_aliases": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"derived_chargers": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"resource_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"resources": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"statqueues": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"statqueue_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"thresholds": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"threshold_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"filters": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"supplier_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"attribute_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"resource_filter_indexes" :{"limit": 10000, "ttl":"0s"},
|
||||
"resource_filter_revindexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"stat_filter_indexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"stat_filter_revindexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"threshold_filter_indexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"threshold_filter_revindexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"supplier_filter_indexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"supplier_filter_revindexes" :{"limit": 10000, "ttl":"0s"},
|
||||
"attribute_filter_indexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"attribute_filter_revindexes" : {"limit": 10000, "ttl":"0s"},
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
67
data/conf/samples/tutmysqlmsgpack/cgrates.json
Normal file
67
data/conf/samples/tutmysqlmsgpack/cgrates.json
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
// CGRateS Configuration file
|
||||
//
|
||||
|
||||
|
||||
"general": {
|
||||
"log_level": 7,
|
||||
"dbdata_encoding": "msgpack", // encoding used to store object data in strings: <msgpack|json>
|
||||
},
|
||||
|
||||
|
||||
"listen": {
|
||||
"rpc_json": ":2012",
|
||||
"rpc_gob": ":2013",
|
||||
"http": ":2080",
|
||||
},
|
||||
|
||||
"data_db": { // database used to store runtime data (eg: accounts, cdr stats)
|
||||
"db_type": "redis", // data_db type: <redis|mongo>
|
||||
"db_port": 6379, // data_db port to reach the database
|
||||
"db_name": "11", // data_db database name to connect to
|
||||
|
||||
},
|
||||
|
||||
"stor_db": {
|
||||
"db_password": "CGRateS.org",
|
||||
},
|
||||
|
||||
|
||||
"cache":{
|
||||
"destinations": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"reverse_destinations": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"rating_plans": {"limit": 10000, "ttl":"0s","precache": true},
|
||||
"rating_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"lcr_rules": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"cdr_stats": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"actions": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"action_plans": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"account_action_plans": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"action_triggers": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"shared_groups": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"aliases": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"reverse_aliases": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"derived_chargers": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"resource_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"resources": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"statqueues": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"statqueue_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"thresholds": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"threshold_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"filters": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"supplier_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"attribute_profiles": {"limit": 10000, "ttl":"0s", "precache": true},
|
||||
"resource_filter_indexes" :{"limit": 10000, "ttl":"0s"},
|
||||
"resource_filter_revindexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"stat_filter_indexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"stat_filter_revindexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"threshold_filter_indexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"threshold_filter_revindexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"supplier_filter_indexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"supplier_filter_revindexes" :{"limit": 10000, "ttl":"0s"},
|
||||
"attribute_filter_indexes" : {"limit": 10000, "ttl":"0s"},
|
||||
"attribute_filter_revindexes" : {"limit": 10000, "ttl":"0s"},
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
@@ -4,61 +4,80 @@
|
||||
// Copyright (C) ITsysCOM GmbH
|
||||
|
||||
"general": {
|
||||
"http_skip_tls_verify": false, // if enabled Http Client will accept any TLS certificate
|
||||
"rounding_decimals": 5, // system level precision for floats
|
||||
"dbdata_encoding": "msgpack", // encoding used to store object data in strings: <msgpack|json>
|
||||
"tpexport_dir": "/var/spool/cgrates/tpe", // path towards export folder for offline Tariff Plans
|
||||
"httpposter_attempts": 3, // number of http attempts before considering request failed (eg: *call_url)
|
||||
"default_request_type": "*rated", // default request type to consider when missing from requests: <""|*prepaid|*postpaid|*pseudoprepaid|*rated>
|
||||
"default_category": "call", // default category to consider when missing from requests
|
||||
"default_tenant": "cgrates.org", // default tenant to consider when missing from requests
|
||||
"default_timezone": "Local", // default timezone for timestamps where not specified <""|UTC|Local|$IANA_TZ_DB>
|
||||
"connect_attempts": 3, // initial server connect attempts
|
||||
"reconnects": -1, // number of retries in case of connection lost
|
||||
"connect_timeout": "1s", // consider connection unsuccessful on timeout, 0 to disable the feature
|
||||
"reply_timeout": "2s", // consider connection down for replies taking longer than this value
|
||||
"response_cache_ttl": "0s", // the life span of a cached response
|
||||
"internal_ttl": "2m", // maximum duration to wait for internal connections before giving up
|
||||
"locking_timeout": "5s", // timeout internal locks to avoid deadlocks
|
||||
"cache_dump_dir": "", // cache dump for faster start (leave empty to disable)
|
||||
"log_level": 7,
|
||||
},
|
||||
|
||||
|
||||
"rals": {
|
||||
"enabled": true,
|
||||
"cdrstats_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"pubsubs_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"users_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"aliases_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"listen": {
|
||||
"rpc_json": ":2012",
|
||||
"rpc_gob": ":2013",
|
||||
"http": ":2080",
|
||||
},
|
||||
|
||||
"stor_db": { // database used to store offline tariff plans and CDRs
|
||||
"db_password": "CGRateS.org", // password to use when connecting to stordb
|
||||
|
||||
"stor_db": {
|
||||
"db_password": "CGRateS.org",
|
||||
},
|
||||
|
||||
|
||||
"scheduler": {
|
||||
"enabled": true,
|
||||
},
|
||||
|
||||
|
||||
"cdrs": {
|
||||
"enabled": true, // start the CDR Server service: <true|false>
|
||||
"cdrstats_conns": [
|
||||
"rals": {
|
||||
"enabled": true,
|
||||
"thresholds_conns": [
|
||||
{"address": "127.0.0.1:2012", "transport": "*json"}
|
||||
],
|
||||
"stats_conns": [
|
||||
{"address": "127.0.0.1:2012", "transport": "*json"}
|
||||
],
|
||||
"pubsubs_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"attributes_conns": [
|
||||
{"address": "127.0.0.1:2012", "transport": "*json"}
|
||||
],
|
||||
},
|
||||
|
||||
|
||||
"cdrstats": {
|
||||
"enabled": true, // starts the cdrstats service: <true|false>
|
||||
"cdrs": {
|
||||
"enabled": true,
|
||||
"sessions_conns": [
|
||||
{"address": "127.0.0.1:2012", "transport": "*json"}
|
||||
],
|
||||
"stats_conns": [
|
||||
{"address": "127.0.0.1:2012", "transport": "*json"}
|
||||
],
|
||||
"sessions_cost_retries": 5,
|
||||
},
|
||||
|
||||
|
||||
"sessions": {
|
||||
"enabled": true,
|
||||
"rals_conns": [
|
||||
{"address": "127.0.0.1:2012", "transport": "*json"}
|
||||
],
|
||||
"cdrs_conns": [
|
||||
{"address": "127.0.0.1:2012", "transport": "*json"}
|
||||
],
|
||||
"resources_conns": [
|
||||
{"address": "127.0.0.1:2012", "transport": "*json"}
|
||||
],
|
||||
"suppliers_conns": [
|
||||
{"address": "127.0.0.1:2012", "transport": "*json"}
|
||||
],
|
||||
"attributes_conns": [
|
||||
{"address": "127.0.0.1:2012", "transport": "*json"}
|
||||
],
|
||||
"stats_conns": [
|
||||
{"address": "127.0.0.1:2012", "transport": "*json"}
|
||||
],
|
||||
"thresholds_conns": [
|
||||
{"address": "127.0.0.1:2012", "transport": "*json"}
|
||||
],
|
||||
"debit_interval": "10s",
|
||||
},
|
||||
|
||||
|
||||
@@ -125,33 +144,68 @@
|
||||
},
|
||||
|
||||
|
||||
"sessions": {
|
||||
"enabled": true,
|
||||
"debit_interval": "5s", // interval to perform debits on.
|
||||
},
|
||||
|
||||
"sm_asterisk": {
|
||||
"enabled": true, // starts Asterisk SessionManager service: <true|false>
|
||||
"asterisk_agent": {
|
||||
"enabled": true,
|
||||
"sessions_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"create_cdr": true,
|
||||
"asterisk_conns":[ // instantiate connections to multiple Asterisk servers
|
||||
"asterisk_conns":[
|
||||
{"address": "127.0.0.1:8088", "user": "cgrates", "password": "CGRateS.org", "connect_attempts": 3,"reconnects": 10}
|
||||
],
|
||||
},
|
||||
|
||||
|
||||
"pubsubs": {
|
||||
"enabled": true, // starts PubSub service: <true|false>.
|
||||
"enabled": true,
|
||||
},
|
||||
|
||||
|
||||
"aliases": {
|
||||
"enabled": true, // starts PubSub service: <true|false>.
|
||||
"attributes": {
|
||||
"enabled": true,
|
||||
"string_indexed_fields": ["Account"],
|
||||
},
|
||||
|
||||
|
||||
"users": {
|
||||
"enabled": true, // starts User service: <true|false>.
|
||||
"indexes": ["Uuid"], // user profile field indexes
|
||||
"resources": {
|
||||
"enabled": true,
|
||||
"thresholds_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"string_indexed_fields": ["Account"],
|
||||
"prefix_indexed_fields": ["Destination"],
|
||||
},
|
||||
|
||||
|
||||
"stats": {
|
||||
"enabled": true,
|
||||
"thresholds_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"string_indexed_fields": ["Account"],
|
||||
},
|
||||
|
||||
|
||||
"thresholds": {
|
||||
"enabled": true,
|
||||
"string_indexed_fields": ["Account"],
|
||||
},
|
||||
|
||||
|
||||
"suppliers": {
|
||||
"enabled": true,
|
||||
"rals_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"resources_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"stats_conns": [
|
||||
{"address": "*internal"}
|
||||
],
|
||||
"string_indexed_fields": ["Account"],
|
||||
"prefix_indexed_fields": ["Destination"],
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
{
|
||||
|
||||
// Real-time Charging System for Telecom & ISP environments
|
||||
// Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
|
||||
// Copyright (C) ITsysCOM GmbH
|
||||
//
|
||||
// This file contains the default configuration hardcoded into CGRateS.
|
||||
// This is what you get when you load CGRateS with an empty configuration file.
|
||||
|
||||
"general": {
|
||||
"log_level": 7,
|
||||
},
|
||||
|
||||
|
||||
"listen": {
|
||||
"rpc_json": ":2012",
|
||||
"rpc_gob": ":2013",
|
||||
|
||||
@@ -1,484 +0,0 @@
|
||||
// +build calls
|
||||
|
||||
/*
|
||||
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 general_tests
|
||||
|
||||
import (
|
||||
"net/rpc"
|
||||
"net/rpc/jsonrpc"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/apier/v1"
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
const astPassword = "CGRateS.org"
|
||||
|
||||
var tutAstCallsCfg *config.CGRConfig
|
||||
var tutAstCallsRpc *rpc.Client
|
||||
var tutAstCallsPjSuaListener *os.File
|
||||
|
||||
func TestTutAstCallsInitCfg(t *testing.T) {
|
||||
// Init config first
|
||||
var err error
|
||||
tutAstCallsCfg, err = config.NewCGRConfigFromFolder(path.Join(*dataDir, "tutorials", "asterisk_ari", "cgrates", "etc", "cgrates"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
tutAstCallsCfg.DataFolderPath = *dataDir // Share DataFolderPath through config towards StoreDb for Flush()
|
||||
config.SetCgrConfig(tutAstCallsCfg)
|
||||
}
|
||||
|
||||
// Remove data in both rating and accounting db
|
||||
func TestTutAstCallsResetDataDb(t *testing.T) {
|
||||
if err := engine.InitDataDb(tutAstCallsCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Wipe out the cdr database
|
||||
func TestTutAstCallsResetStorDb(t *testing.T) {
|
||||
if err := engine.InitStorDb(tutAstCallsCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// start Asterisk server
|
||||
func TestTutAstCallsStartAsterisk(t *testing.T) {
|
||||
engine.KillProcName("asterisk", 1000)
|
||||
if err := engine.CallScript(path.Join(*dataDir, "tutorials", "asterisk_ari", "asterisk", "etc", "init.d", "asterisk"), "start", 2000); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Start CGR Engine
|
||||
func TestTutAstCallsStartEngine(t *testing.T) {
|
||||
engine.KillProcName("cgr-engine", *waitRater)
|
||||
if err := engine.CallScript(path.Join(*dataDir, "tutorials", "asterisk_ari", "cgrates", "etc", "init.d", "cgrates"), "start", 100); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// Restart FS so we make sure reconnects are working
|
||||
func TestTutAstCallsRestartAsterisk(t *testing.T) {
|
||||
if err := engine.CallScript(path.Join(*dataDir, "tutorials", "asterisk_ari", "asterisk", "etc", "init.d", "asterisk"), "restart", 2000); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
*/
|
||||
// Connect rpc client to rater
|
||||
func TestTutAstCallsRpcConn(t *testing.T) {
|
||||
var err error
|
||||
tutAstCallsRpc, err = jsonrpc.Dial("tcp", tutAstCallsCfg.RPCJSONListen) // 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 TestTutAstCallsLoadTariffPlanFromFolder(t *testing.T) {
|
||||
reply := ""
|
||||
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "tutorial")}
|
||||
if err := tutAstCallsRpc.Call("ApierV1.LoadTariffPlanFromFolder", attrs, &reply); err != nil {
|
||||
t.Error(err)
|
||||
} else if reply != utils.OK {
|
||||
t.Error(reply)
|
||||
}
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for scheduler to execute topups
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutAstCallsAccountsBefore(t *testing.T) {
|
||||
var reply *engine.Account
|
||||
attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"}
|
||||
if err := tutAstCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() != 10.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
}
|
||||
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1002"}
|
||||
if err := tutAstCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() != 10.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
}
|
||||
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1003"}
|
||||
if err := tutAstCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() != 10.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
}
|
||||
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1004"}
|
||||
if err := tutAstCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() != 10.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
}
|
||||
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1007"}
|
||||
if err := tutAstCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() != 0.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
}
|
||||
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1005"}
|
||||
if err := tutAstCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err == nil || err.Error() != utils.ErrNotFound.Error() {
|
||||
t.Error("Got error on ApierV2.GetAccount: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure all stats queues are in place
|
||||
func TestTutAstCallsCdrStatsBefore(t *testing.T) {
|
||||
//eQueueIds := []string{"*default", "CDRST1", "CDRST_1001", "CDRST_1002", "CDRST_1003", "STATS_SUPPL1", "STATS_SUPPL2"}
|
||||
var statMetrics map[string]float64
|
||||
eMetrics := map[string]float64{engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1, engine.ACC: -1}
|
||||
if err := tutAstCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "CDRST1"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
eMetrics = map[string]float64{engine.ACC: -1, engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1}
|
||||
if err := tutAstCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "CDRST_1001"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
eMetrics = map[string]float64{engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1, engine.ACC: -1}
|
||||
if err := tutAstCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "CDRST_1002"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
eMetrics = map[string]float64{engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1, engine.ACC: -1}
|
||||
if err := tutAstCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "CDRST_1003"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
eMetrics = map[string]float64{engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1, engine.ACC: -1}
|
||||
if err := tutAstCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "STATS_SUPPL1"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
eMetrics = map[string]float64{engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1, engine.ACC: -1}
|
||||
if err := tutAstCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "STATS_SUPPL2"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
}
|
||||
|
||||
// Start Pjsua as listener and register it to receive calls
|
||||
func TestTutAstCallsStartPjsuaListener(t *testing.T) {
|
||||
var err error
|
||||
acnts := []*engine.PjsuaAccount{
|
||||
&engine.PjsuaAccount{Id: "sip:1001@127.0.0.1", Username: "1001", Password: astPassword, Realm: "*", Registrar: "sip:127.0.0.1:5060"},
|
||||
&engine.PjsuaAccount{Id: "sip:1002@127.0.0.1", Username: "1002", Password: astPassword, Realm: "*", Registrar: "sip:127.0.0.1:5060"},
|
||||
&engine.PjsuaAccount{Id: "sip:1003@127.0.0.1", Username: "1003", Password: astPassword, Realm: "*", Registrar: "sip:127.0.0.1:5060"},
|
||||
&engine.PjsuaAccount{Id: "sip:1004@127.0.0.1", Username: "1004", Password: astPassword, Realm: "*", Registrar: "sip:127.0.0.1:5060"},
|
||||
&engine.PjsuaAccount{Id: "sip:1006@127.0.0.1", Username: "1006", Password: astPassword, Realm: "*", Registrar: "sip:127.0.0.1:5060"},
|
||||
&engine.PjsuaAccount{Id: "sip:1007@127.0.0.1", Username: "1007", Password: astPassword, Realm: "*", Registrar: "sip:127.0.0.1:5060"}}
|
||||
if tutAstCallsPjSuaListener, err = engine.StartPjsuaListener(acnts, 5070, time.Duration(500*time.Millisecond)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Call from 1001 (prepaid) to 1002
|
||||
func TestTutAstCallsCall1001To1002(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1001@127.0.0.1", Username: "1001", Password: astPassword, Realm: "*"}, "sip:1002@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(67)*time.Second, 5071); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Call from 1001 (prepaid) to 1003
|
||||
func TestTutAstCallsCall1001To1003(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1001@127.0.0.1", Username: "1001", Password: astPassword, Realm: "*"}, "sip:1003@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(65)*time.Second, 5072); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutAstCallsCall1002To1001(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1002@127.0.0.1", Username: "1002", Password: astPassword, Realm: "*"}, "sip:1001@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(61)*time.Second, 5073); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutAstCallsCall1003To1001(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1003@127.0.0.1", Username: "1003", Password: astPassword, Realm: "*"}, "sip:1001@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(63)*time.Second, 5074); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutAstCallsCall1004To1001(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1004@127.0.0.1", Username: "1004", Password: astPassword, Realm: "*"}, "sip:1001@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(62)*time.Second, 5075); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutAstCallsCall1006To1002(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1006@127.0.0.1", Username: "1006", Password: astPassword, Realm: "*"}, "sip:1002@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(64)*time.Second, 5076); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutAstCallsCall1007To1002(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1007@127.0.0.1", Username: "1007", Password: astPassword, Realm: "*"}, "sip:1002@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(66)*time.Second, 5077); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutAstCallsAccount1001(t *testing.T) {
|
||||
time.Sleep(time.Duration(70) * time.Second) // Allow calls to finish before start querying the results
|
||||
var reply *engine.Account
|
||||
attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"}
|
||||
if err := tutAstCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() == 10.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
} else if reply.Disabled == true {
|
||||
t.Error("Account disabled")
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutAstCalls1001Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
//var cgrId string // Share with getCostDetails
|
||||
//var cCost engine.CallCost
|
||||
req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}, DestinationPrefixes: []string{"1002"}}
|
||||
if err := tutAstCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
//cgrId = reply[0].CGRID
|
||||
if reply[0].Source != "OSIPS_E_ACC_EVENT" {
|
||||
t.Errorf("Unexpected Source for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].RequestType != utils.META_PREPAID {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "67" { // Usage as seconds
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Cost == -1.0 { // Cost was not calculated
|
||||
t.Errorf("Unexpected Cost for CDR: %+v", reply[0])
|
||||
}
|
||||
//if reply[0].Supplier != "suppl2" { // Usage as seconds
|
||||
// t.Errorf("Unexpected Supplier for CDR: %+v", reply[0])
|
||||
//}
|
||||
}
|
||||
req = utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}, DestinationPrefixes: []string{"1003"}}
|
||||
if err := tutAstCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
//cgrId = reply[0].CGRID
|
||||
if reply[0].RequestType != utils.META_PREPAID {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "65" && reply[0].Usage != "66" { // Usage as seconds
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Cost != 0 { // Cost was not calculated
|
||||
t.Errorf("Unexpected Cost for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
req = utils.RPCCDRsFilter{Accounts: []string{"1001"}, RunIDs: []string{"derived_run1"}}
|
||||
if err := tutAstCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 2 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
if reply[0].RequestType != utils.META_RATED {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Subject != "1002" {
|
||||
t.Errorf("Unexpected Subject for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutAstCalls1002Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{Accounts: []string{"1002"}, RunIDs: []string{utils.META_DEFAULT}}
|
||||
if err := tutAstCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 2 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
if reply[0].Source != "OSIPS_E_ACC_EVENT" {
|
||||
t.Errorf("Unexpected Source for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].RequestType != utils.META_POSTPAID {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Destination != "1001" {
|
||||
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "61" { // Usage as seconds
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutAstCalls1003Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{Accounts: []string{"1003"}, RunIDs: []string{utils.META_DEFAULT}}
|
||||
if err := tutAstCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
if reply[0].Source != "OSIPS_E_ACC_EVENT" {
|
||||
t.Errorf("Unexpected Source for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].RequestType != utils.META_PSEUDOPREPAID {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Destination != "1001" {
|
||||
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "63" && reply[0].Usage != "64" { // Usage as seconds, sometimes takes a second longer to disconnect
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutAstCalls1004Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{Accounts: []string{"1004"}, RunIDs: []string{utils.META_DEFAULT}}
|
||||
if err := tutAstCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
if reply[0].Source != "OSIPS_E_ACC_EVENT" {
|
||||
t.Errorf("Unexpected Source for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].RequestType != utils.META_RATED {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Destination != "1001" {
|
||||
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "62" && reply[0].Usage != "63" { // Usage as seconds
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Make sure aliasing was done for 1006 and we have no CDRs for it
|
||||
func TestTutAstCalls1006Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{Accounts: []string{"1006"}, RunIDs: []string{utils.META_DEFAULT}}
|
||||
if err := tutAstCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 0 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutAstCalls1007Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{Accounts: []string{"1007"}, RunIDs: []string{utils.META_DEFAULT}}
|
||||
if err := tutAstCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
if reply[0].Source != "OSIPS_E_ACC_EVENT" {
|
||||
t.Errorf("Unexpected Source for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].RequestType != utils.META_PREPAID {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Destination != "1002" {
|
||||
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "66" && reply[0].Usage != "67" { // Usage as seconds
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Cost == -1.0 { // Cost was not calculated
|
||||
t.Errorf("Unexpected Cost for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutAstCallsAccountFraud1001(t *testing.T) {
|
||||
var reply string
|
||||
attrAddBlnc := &v1.AttrAddBalance{Tenant: "cgrates.org", Account: "1001", BalanceType: "*monetary", Value: 101}
|
||||
if err := tutAstCallsRpc.Call("ApierV1.AddBalance", attrAddBlnc, &reply); err != nil {
|
||||
t.Error("Got error on ApierV1.AddBalance: ", err.Error())
|
||||
} else if reply != "OK" {
|
||||
t.Errorf("Calling ApierV1.AddBalance received: %s", reply)
|
||||
}
|
||||
}
|
||||
|
||||
// Based on Fraud automatic mitigation, our account should be disabled
|
||||
func TestTutAstCallsAccountDisabled1001(t *testing.T) {
|
||||
var reply *engine.Account
|
||||
attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"}
|
||||
if err := tutAstCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.Disabled == false {
|
||||
t.Error("Account should be disabled per fraud detection rules.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutAstCallsStopPjsuaListener(t *testing.T) {
|
||||
time.Sleep(70 * time.Second) // Give time for calls to go through before unregistering
|
||||
tutAstCallsPjSuaListener.Write([]byte("q\n")) // Close pjsua
|
||||
time.Sleep(time.Duration(1) * time.Second) // Allow pjsua to finish it's tasks, eg un-REGISTER
|
||||
}
|
||||
|
||||
func TestTutAstCallsStopCgrEngine(t *testing.T) {
|
||||
if err := engine.KillEngine(100); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutAstCallsStopAsterisk(t *testing.T) {
|
||||
engine.KillProcName("asterisk", 100)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// +build newcall
|
||||
// +build call
|
||||
|
||||
/*
|
||||
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
|
||||
@@ -22,7 +22,6 @@ package general_tests
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/rpc"
|
||||
"net/rpc/jsonrpc"
|
||||
"os"
|
||||
@@ -37,14 +36,15 @@ import (
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
var tutFsCallsCfg *config.CGRConfig
|
||||
var tutFsCallsRpc *rpc.Client
|
||||
var tutFsCallsPjSuaListener *os.File
|
||||
var tutorialCallsCfg *config.CGRConfig
|
||||
var tutorialCallsRpc *rpc.Client
|
||||
var tutorialCallsPjSuaListener *os.File
|
||||
var waitRater = flag.Int("wait_rater", 100, "Number of miliseconds to wait for rater to start and cache")
|
||||
var dataDir = flag.String("data_dir", "/usr/share/cgrates", "CGR data dir path here")
|
||||
var fsConfig = flag.String("fsConfig", "/usr/share/cgrates/tutorials/fs_evsock", "FreeSwitch tutorial folder")
|
||||
var kamConfig = flag.String("kamConfig", "/usr/share/cgrates/tutorials/kamevapi", "Kamailio tutorial folder")
|
||||
var oSipsConfig = flag.String("osConfig", "/usr/share/cgrates/tutorials/osips_native", "OpenSips tutorial folder")
|
||||
var ariConf = flag.String("ariConf", "/usr/share/cgrates/tutorials/asterisk_ari", "Asterisk tutorial folder")
|
||||
var optConf string
|
||||
|
||||
var sTestsCalls = []func(t *testing.T){
|
||||
@@ -80,61 +80,75 @@ var sTestsCalls = []func(t *testing.T){
|
||||
}
|
||||
|
||||
//Test start here
|
||||
func TestFSCalls(t *testing.T) {
|
||||
func TestFreeswitchCalls(t *testing.T) {
|
||||
optConf = utils.Freeswitch
|
||||
for _, stest := range sTestsCalls {
|
||||
t.Run("", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestKamCalls(t *testing.T) {
|
||||
func TestKamailioCalls(t *testing.T) {
|
||||
optConf = utils.Kamailio
|
||||
for _, stest := range sTestsCalls {
|
||||
t.Run("", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOSCalls(t *testing.T) {
|
||||
func TestOpensipsCalls(t *testing.T) {
|
||||
optConf = utils.Opensips
|
||||
for _, stest := range sTestsCalls {
|
||||
t.Run("", stest)
|
||||
}
|
||||
}
|
||||
|
||||
/* Need to be checked
|
||||
func TestAsteriskCalls(t *testing.T) {
|
||||
optConf = utils.Asterisk
|
||||
for _, stest := range sTestsCalls {
|
||||
t.Run("", stest)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
func testCallInitCfg(t *testing.T) {
|
||||
// Init config first
|
||||
var err error
|
||||
if optConf == utils.Freeswitch {
|
||||
tutFsCallsCfg, err = config.NewCGRConfigFromFolder(path.Join(*fsConfig, "cgrates", "etc", "cgrates"))
|
||||
tutorialCallsCfg, err = config.NewCGRConfigFromFolder(path.Join(*fsConfig, "cgrates", "etc", "cgrates"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
} else if optConf == utils.Kamailio {
|
||||
tutFsCallsCfg, err = config.NewCGRConfigFromFolder(path.Join(*kamConfig, "cgrates", "etc", "cgrates"))
|
||||
tutorialCallsCfg, err = config.NewCGRConfigFromFolder(path.Join(*kamConfig, "cgrates", "etc", "cgrates"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
} else if optConf == utils.Opensips {
|
||||
tutFsCallsCfg, err = config.NewCGRConfigFromFolder(path.Join(*oSipsConfig, "cgrates", "etc", "cgrates"))
|
||||
tutorialCallsCfg, err = config.NewCGRConfigFromFolder(path.Join(*oSipsConfig, "cgrates", "etc", "cgrates"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
} else if optConf == utils.Asterisk {
|
||||
tutorialCallsCfg, err = config.NewCGRConfigFromFolder(path.Join(*ariConf, "cgrates", "etc", "cgrates"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
tutFsCallsCfg.DataFolderPath = *dataDir // Share DataFolderPath through config towards StoreDb for Flush()
|
||||
config.SetCgrConfig(tutFsCallsCfg)
|
||||
tutorialCallsCfg.DataFolderPath = *dataDir // Share DataFolderPath through config towards StoreDb for Flush()
|
||||
config.SetCgrConfig(tutorialCallsCfg)
|
||||
}
|
||||
|
||||
// Remove data in both rating and accounting db
|
||||
func testCallResetDataDb(t *testing.T) {
|
||||
if err := engine.InitDataDb(tutFsCallsCfg); err != nil {
|
||||
if err := engine.InitDataDb(tutorialCallsCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Wipe out the cdr database
|
||||
func testCallResetStorDb(t *testing.T) {
|
||||
if err := engine.InitStorDb(tutFsCallsCfg); err != nil {
|
||||
if err := engine.InitStorDb(tutorialCallsCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -156,6 +170,11 @@ func testCallStartFS(t *testing.T) {
|
||||
if err := engine.CallScript(path.Join(*oSipsConfig, "opensips", "etc", "init.d", "opensips"), "start", 3000); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
} else if optConf == utils.Asterisk {
|
||||
engine.KillProcName(utils.Asterisk, 5000)
|
||||
if err := engine.CallScript(path.Join(*ariConf, "asterisk", "etc", "init.d", "asterisk"), "start", 3000); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,6 +193,10 @@ func testCallStartEngine(t *testing.T) {
|
||||
if err := engine.CallScript(path.Join(*oSipsConfig, "cgrates", "etc", "init.d", "cgrates"), "start", 100); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
} else if optConf == utils.Asterisk {
|
||||
if err := engine.CallScript(path.Join(*ariConf, "cgrates", "etc", "init.d", "cgrates"), "start", 100); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,13 +214,17 @@ func testCallRestartFS(t *testing.T) {
|
||||
if err := engine.CallScript(path.Join(*oSipsConfig, "opensips", "etc", "init.d", "opensips"), "restart", 5000); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
} else if optConf == utils.Asterisk {
|
||||
if err := engine.CallScript(path.Join(*ariConf, "asterisk", "etc", "init.d", "asterisk"), "restart", 5000); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Connect rpc client to rater
|
||||
func testCallRpcConn(t *testing.T) {
|
||||
var err error
|
||||
tutFsCallsRpc, err = jsonrpc.Dial("tcp", tutFsCallsCfg.RPCJSONListen) // We connect over JSON so we can also troubleshoot if needed
|
||||
tutorialCallsRpc, err = jsonrpc.Dial("tcp", tutorialCallsCfg.RPCJSONListen) // We connect over JSON so we can also troubleshoot if needed
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -208,7 +235,7 @@ func testCallRpcConn(t *testing.T) {
|
||||
func testCallLoadTariffPlanFromFolder(t *testing.T) {
|
||||
var reply string
|
||||
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "tutorial2")}
|
||||
if err := tutFsCallsRpc.Call("ApierV1.LoadTariffPlanFromFolder", attrs, &reply); err != nil {
|
||||
if err := tutorialCallsRpc.Call("ApierV1.LoadTariffPlanFromFolder", attrs, &reply); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for scheduler to execute topups
|
||||
@@ -218,14 +245,14 @@ func testCallLoadTariffPlanFromFolder(t *testing.T) {
|
||||
func testCallAccountsBefore(t *testing.T) {
|
||||
var reply *engine.Account
|
||||
attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"}
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
if err := tutorialCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() != 10.0 {
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
}
|
||||
var reply2 *engine.Account
|
||||
attrs2 := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1002"}
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetAccount", attrs2, &reply2); err != nil {
|
||||
if err := tutorialCallsRpc.Call("ApierV2.GetAccount", attrs2, &reply2); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply2.BalanceMap[utils.MONETARY].GetTotalValue() != 10.0 {
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply2.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
@@ -238,7 +265,7 @@ func testCallStatMetricsBefore(t *testing.T) {
|
||||
utils.MetaTCC: utils.NOT_AVAILABLE,
|
||||
utils.MetaTCD: utils.NOT_AVAILABLE,
|
||||
}
|
||||
if err := tutFsCallsRpc.Call(utils.StatSv1GetQueueStringMetrics,
|
||||
if err := tutorialCallsRpc.Call(utils.StatSv1GetQueueStringMetrics,
|
||||
&utils.TenantID{Tenant: "cgrates.org", ID: "Stats2"}, &metrics); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(expectedMetrics, metrics) {
|
||||
@@ -257,7 +284,7 @@ func testCallCheckResourceBeforeAllocation(t *testing.T) {
|
||||
utils.Subject: "1001",
|
||||
utils.Destination: "1002"},
|
||||
}}
|
||||
if err := tutFsCallsRpc.Call(utils.ResourceSv1GetResourcesForEvent, args, &rs); err != nil {
|
||||
if err := tutorialCallsRpc.Call(utils.ResourceSv1GetResourcesForEvent, args, &rs); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(*rs) != 2 {
|
||||
t.Errorf("Resources: %+v", utils.ToJSON(rs))
|
||||
@@ -273,7 +300,7 @@ func testCallCheckResourceBeforeAllocation(t *testing.T) {
|
||||
func testCallCheckThreshold1001Before(t *testing.T) {
|
||||
var td engine.Threshold
|
||||
eTd := engine.Threshold{Tenant: "cgrates.org", ID: "THD_ACNT_1001", Hits: 0}
|
||||
if err := tutFsCallsRpc.Call(utils.ThresholdSv1GetThreshold,
|
||||
if err := tutorialCallsRpc.Call(utils.ThresholdSv1GetThreshold,
|
||||
&utils.TenantID{Tenant: "cgrates.org", ID: "THD_ACNT_1001"}, &td); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eTd, td) {
|
||||
@@ -284,7 +311,7 @@ func testCallCheckThreshold1001Before(t *testing.T) {
|
||||
func testCallCheckThreshold1002Before(t *testing.T) {
|
||||
var td engine.Threshold
|
||||
eTd := engine.Threshold{Tenant: "cgrates.org", ID: "THD_ACNT_1002", Hits: 0}
|
||||
if err := tutFsCallsRpc.Call(utils.ThresholdSv1GetThreshold,
|
||||
if err := tutorialCallsRpc.Call(utils.ThresholdSv1GetThreshold,
|
||||
&utils.TenantID{Tenant: "cgrates.org", ID: "THD_ACNT_1002"}, &td); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eTd, td) {
|
||||
@@ -303,7 +330,7 @@ func testCallStartPjsuaListener(t *testing.T) {
|
||||
&engine.PjsuaAccount{Id: "sip:1003@127.0.0.1",
|
||||
Username: "1003", Password: "CGRateS.org", Realm: "*", Registrar: "sip:127.0.0.1:5080"},
|
||||
}
|
||||
if tutFsCallsPjSuaListener, err = engine.StartPjsuaListener(
|
||||
if tutorialCallsPjSuaListener, err = engine.StartPjsuaListener(
|
||||
acnts, 5070, time.Duration(*waitRater)*time.Millisecond); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -332,7 +359,7 @@ func testCallGetActiveSessions(t *testing.T) {
|
||||
Destination: "1002",
|
||||
},
|
||||
}
|
||||
if err := tutFsCallsRpc.Call(utils.SessionSv1GetActiveSessions,
|
||||
if err := tutorialCallsRpc.Call(utils.SessionSv1GetActiveSessions,
|
||||
&map[string]string{}, &reply); err != nil {
|
||||
t.Error("Got error on SessionSv1.GetActiveSessions: ", err.Error())
|
||||
} else {
|
||||
@@ -377,7 +404,7 @@ func testCallCheckResourceAllocation(t *testing.T) {
|
||||
utils.Subject: "1001",
|
||||
utils.Destination: "1002"},
|
||||
}}
|
||||
if err := tutFsCallsRpc.Call(utils.ResourceSv1GetResourcesForEvent, args, &rs); err != nil {
|
||||
if err := tutorialCallsRpc.Call(utils.ResourceSv1GetResourcesForEvent, args, &rs); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(*rs) != 2 {
|
||||
t.Errorf("Resources: %+v", utils.ToJSON(rs))
|
||||
@@ -395,7 +422,7 @@ func testCallAccount1001(t *testing.T) {
|
||||
time.Sleep(time.Duration(80) * time.Second) // Allow calls to finish before start querying the results
|
||||
var reply *engine.Account
|
||||
attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"}
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
if err := tutorialCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error(err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() == 10.0 { // Make sure we debitted
|
||||
t.Errorf("Expected: 10, received: %+v", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
@@ -408,15 +435,12 @@ func testCallAccount1001(t *testing.T) {
|
||||
func testCall1001Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}}
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
if err := tutorialCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 2 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
for _, cdr := range reply {
|
||||
if cdr.Source != "freeswitch_json" && cdr.Source != "SMG_KamailioAgent" {
|
||||
t.Errorf("Unexpected Source for CDR: %+v", cdr.Source)
|
||||
}
|
||||
if cdr.RequestType != utils.META_PREPAID {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", cdr.RequestType)
|
||||
}
|
||||
@@ -443,14 +467,11 @@ func testCall1001Cdrs(t *testing.T) {
|
||||
func testCall1002Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{"1002"}, DestinationPrefixes: []string{"1001"}}
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
if err := tutorialCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
if reply[0].Source != "freeswitch_json" && reply[0].Source != "SMG_KamailioAgent" {
|
||||
t.Errorf("Unexpected Source for CDR: %+v", reply[0].Source)
|
||||
}
|
||||
if reply[0].RequestType != utils.META_POSTPAID {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0].RequestType)
|
||||
}
|
||||
@@ -473,7 +494,7 @@ func testCallStatMetrics(t *testing.T) {
|
||||
utils.MetaTCC: "1.34009",
|
||||
utils.MetaTCD: "2m24s",
|
||||
}
|
||||
if err := tutFsCallsRpc.Call(utils.StatSv1GetQueueStringMetrics,
|
||||
if err := tutorialCallsRpc.Call(utils.StatSv1GetQueueStringMetrics,
|
||||
&utils.TenantID{Tenant: "cgrates.org", ID: "Stats2"}, &metrics); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(expectedMetrics1, metrics) &&
|
||||
@@ -493,7 +514,7 @@ func testCallCheckResourceRelease(t *testing.T) {
|
||||
utils.Subject: "1001",
|
||||
utils.Destination: "1002"},
|
||||
}}
|
||||
if err := tutFsCallsRpc.Call(utils.ResourceSv1GetResourcesForEvent, args, &rs); err != nil {
|
||||
if err := tutorialCallsRpc.Call(utils.ResourceSv1GetResourcesForEvent, args, &rs); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(*rs) != 2 {
|
||||
t.Errorf("Resources: %+v", rs)
|
||||
@@ -508,7 +529,7 @@ func testCallCheckResourceRelease(t *testing.T) {
|
||||
|
||||
func testCallCheckThreshold1001After(t *testing.T) {
|
||||
var td engine.Threshold
|
||||
if err := tutFsCallsRpc.Call(utils.ThresholdSv1GetThreshold,
|
||||
if err := tutorialCallsRpc.Call(utils.ThresholdSv1GetThreshold,
|
||||
&utils.TenantID{Tenant: "cgrates.org", ID: "THD_ACNT_1001"}, &td); err != nil &&
|
||||
err.Error() != utils.ErrNotFound.Error() {
|
||||
t.Error(err)
|
||||
@@ -518,7 +539,7 @@ func testCallCheckThreshold1001After(t *testing.T) {
|
||||
func testCallCheckThreshold1002After(t *testing.T) {
|
||||
var td engine.Threshold
|
||||
eTd := engine.Threshold{Tenant: "cgrates.org", ID: "THD_ACNT_1002", Hits: 4}
|
||||
if err := tutFsCallsRpc.Call(utils.ThresholdSv1GetThreshold,
|
||||
if err := tutorialCallsRpc.Call(utils.ThresholdSv1GetThreshold,
|
||||
&utils.TenantID{Tenant: "cgrates.org", ID: "THD_ACNT_1002"}, &td); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eTd.Tenant, td.Tenant) {
|
||||
@@ -531,8 +552,8 @@ func testCallCheckThreshold1002After(t *testing.T) {
|
||||
}
|
||||
|
||||
func testCallStopPjsuaListener(t *testing.T) {
|
||||
tutFsCallsPjSuaListener.Write([]byte("q\n")) // Close pjsua
|
||||
time.Sleep(time.Duration(1) * time.Second) // Allow pjsua to finish it's tasks, eg un-REGISTER
|
||||
tutorialCallsPjSuaListener.Write([]byte("q\n")) // Close pjsua
|
||||
time.Sleep(time.Duration(1) * time.Second) // Allow pjsua to finish it's tasks, eg un-REGISTER
|
||||
}
|
||||
|
||||
func testCallStopCgrEngine(t *testing.T) {
|
||||
@@ -548,5 +569,7 @@ func testCallStopFS(t *testing.T) {
|
||||
engine.KillProcName(utils.Kamailio, 1000)
|
||||
} else if optConf == utils.Opensips {
|
||||
engine.KillProcName(utils.Opensips, 1000)
|
||||
} else if optConf == utils.Asterisk {
|
||||
engine.KillProcName(utils.Asterisk, 1000)
|
||||
}
|
||||
}
|
||||
@@ -1,497 +0,0 @@
|
||||
// +build calls
|
||||
|
||||
/*
|
||||
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 general_tests
|
||||
|
||||
import (
|
||||
"net/rpc"
|
||||
"net/rpc/jsonrpc"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/apier/v1"
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
var tutFsCallsCfg *config.CGRConfig
|
||||
var tutFsCallsRpc *rpc.Client
|
||||
var tutFsCallsPjSuaListener *os.File
|
||||
|
||||
func TestTutFsCallsInitCfg(t *testing.T) {
|
||||
// Init config first
|
||||
var err error
|
||||
tutFsCallsCfg, err = config.NewCGRConfigFromFolder(path.Join(*dataDir, "tutorials", "fs_evsock", "cgrates", "etc", "cgrates"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
tutFsCallsCfg.DataFolderPath = *dataDir // Share DataFolderPath through config towards StoreDb for Flush()
|
||||
config.SetCgrConfig(tutFsCallsCfg)
|
||||
}
|
||||
|
||||
// Remove data in both rating and accounting db
|
||||
func TestTutFsCallsResetDataDb(t *testing.T) {
|
||||
if err := engine.InitDataDb(tutFsCallsCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Wipe out the cdr database
|
||||
func TestTutFsCallsResetStorDb(t *testing.T) {
|
||||
if err := engine.InitStorDb(tutFsCallsCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// start FS server
|
||||
func TestTutFsCallsStartFS(t *testing.T) {
|
||||
engine.KillProcName("freeswitch", 5000)
|
||||
if err := engine.CallScript(path.Join(*dataDir, "tutorials", "fs_evsock", "freeswitch", "etc", "init.d", "freeswitch"), "start", 3000); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Start CGR Engine
|
||||
func TestTutFsCallsStartEngine(t *testing.T) {
|
||||
engine.KillProcName("cgr-engine", *waitRater)
|
||||
if err := engine.CallScript(path.Join(*dataDir, "tutorials", "fs_evsock", "cgrates", "etc", "init.d", "cgrates"), "start", 100); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Restart FS so we make sure reconnects are working
|
||||
func TestTutFsCallsRestartFS(t *testing.T) {
|
||||
if err := engine.CallScript(path.Join(*dataDir, "tutorials", "fs_evsock", "freeswitch", "etc", "init.d", "freeswitch"), "restart", 5000); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Connect rpc client to rater
|
||||
func TestTutFsCallsRpcConn(t *testing.T) {
|
||||
var err error
|
||||
tutFsCallsRpc, err = jsonrpc.Dial("tcp", tutFsCallsCfg.RPCJSONListen) // 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 TestTutFsCallsLoadTariffPlanFromFolder(t *testing.T) {
|
||||
reply := ""
|
||||
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "tutorial")}
|
||||
if err := tutFsCallsRpc.Call("ApierV1.LoadTariffPlanFromFolder", attrs, &reply); err != nil {
|
||||
t.Error(err)
|
||||
} else if reply != "OK" {
|
||||
t.Error(reply)
|
||||
}
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for scheduler to execute topups
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutFsCallsAccountsBefore(t *testing.T) {
|
||||
var reply *engine.Account
|
||||
attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"}
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() != 10.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
}
|
||||
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1002"}
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() != 10.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
}
|
||||
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1003"}
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() != 10.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
}
|
||||
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1004"}
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() != 10.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
}
|
||||
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1007"}
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() != 0.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
}
|
||||
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1005"}
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err == nil || err.Error() != utils.ErrNotFound.Error() {
|
||||
t.Errorf("Got error on ApierV2.GetAccount: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure all stats queues are in place
|
||||
func TestTutFsCallsCdrStatsBefore(t *testing.T) {
|
||||
//eQueueIds := []string{"*default", "CDRST1", "CDRST_1001", "CDRST_1002", "CDRST_1003", "STATS_SUPPL1", "STATS_SUPPL2"}
|
||||
var statMetrics map[string]float64
|
||||
eMetrics := map[string]float64{engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1, engine.ACC: -1}
|
||||
if err := tutFsCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "CDRST1"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
eMetrics = map[string]float64{engine.ACC: -1, engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1}
|
||||
if err := tutFsCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "CDRST_1001"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
eMetrics = map[string]float64{engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1, engine.ACC: -1}
|
||||
if err := tutFsCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "CDRST_1002"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
eMetrics = map[string]float64{engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1, engine.ACC: -1}
|
||||
if err := tutFsCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "CDRST_1003"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
eMetrics = map[string]float64{engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1, engine.ACC: -1}
|
||||
if err := tutFsCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "STATS_SUPPL1"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
eMetrics = map[string]float64{engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1, engine.ACC: -1}
|
||||
if err := tutFsCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "STATS_SUPPL2"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
}
|
||||
|
||||
// Start Pjsua as listener and register it to receive calls
|
||||
func TestTutFsCallsStartPjsuaListener(t *testing.T) {
|
||||
var err error
|
||||
acnts := []*engine.PjsuaAccount{
|
||||
&engine.PjsuaAccount{Id: "sip:1001@127.0.0.1", Username: "1001", Password: "1234", Realm: "*", Registrar: "sip:127.0.0.1:5060"},
|
||||
&engine.PjsuaAccount{Id: "sip:1002@127.0.0.1", Username: "1002", Password: "1234", Realm: "*", Registrar: "sip:127.0.0.1:5060"},
|
||||
&engine.PjsuaAccount{Id: "sip:1003@127.0.0.1", Username: "1003", Password: "1234", Realm: "*", Registrar: "sip:127.0.0.1:5060"},
|
||||
&engine.PjsuaAccount{Id: "sip:1004@127.0.0.1", Username: "1004", Password: "1234", Realm: "*", Registrar: "sip:127.0.0.1:5060"},
|
||||
&engine.PjsuaAccount{Id: "sip:1006@127.0.0.1", Username: "1006", Password: "1234", Realm: "*", Registrar: "sip:127.0.0.1:5060"},
|
||||
&engine.PjsuaAccount{Id: "sip:1007@127.0.0.1", Username: "1007", Password: "1234", Realm: "*", Registrar: "sip:127.0.0.1:5060"}}
|
||||
if tutFsCallsPjSuaListener, err = engine.StartPjsuaListener(acnts, 5070, time.Duration(*waitRater)*time.Millisecond); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Call from 1001 (prepaid) to 1002
|
||||
func TestTutFsCallsCall1001To1002(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1001@127.0.0.1", Username: "1001", Password: "1234", Realm: "*"}, "sip:1002@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(67)*time.Second, 5071); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Call from 1001 (prepaid) to 1003
|
||||
func TestTutFsCallsCall1001To1003(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1001@127.0.0.1", Username: "1001", Password: "1234", Realm: "*"}, "sip:1003@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(65)*time.Second, 5072); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutFsCallsCall1002To1001(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1002@127.0.0.1", Username: "1002", Password: "1234", Realm: "*"}, "sip:1001@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(61)*time.Second, 5073); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutFsCallsCall1003To1001(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1003@127.0.0.1", Username: "1003", Password: "1234", Realm: "*"}, "sip:1001@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(63)*time.Second, 5074); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutFsCallsCall1004To1001(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1004@127.0.0.1", Username: "1004", Password: "1234", Realm: "*"}, "sip:1001@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(62)*time.Second, 5075); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutFsCallsCall1006To1002(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1006@127.0.0.1", Username: "1006", Password: "1234", Realm: "*"}, "sip:1002@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(64)*time.Second, 5076); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutFsCallsCall1007To1002(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1007@127.0.0.1", Username: "1007", Password: "1234", Realm: "*"}, "sip:1002@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(66)*time.Second, 5077); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutFsCallsAccount1001(t *testing.T) {
|
||||
time.Sleep(time.Duration(80) * time.Second) // Allow calls to finish before start querying the results
|
||||
var reply *engine.Account
|
||||
attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"}
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() == 10.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
} else if reply.Disabled == true {
|
||||
t.Error("Account disabled")
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutFsCalls1001Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
//var CGRID string // Share with getCostDetails
|
||||
//var cCost engine.CallCost
|
||||
req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}, DestinationPrefixes: []string{"1002"}}
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
//CGRID = reply[0].CGRID
|
||||
if reply[0].Source != "freeswitch_json" {
|
||||
t.Errorf("Unexpected Source for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].RequestType != utils.META_PREPAID {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "67" && reply[0].Usage != "68" { // Usage as seconds
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Cost == -1.0 { // Cost was not calculated
|
||||
t.Errorf("Unexpected Cost for CDR: %+v", reply[0])
|
||||
}
|
||||
//if reply[0].Supplier != "suppl2" { // Usage as seconds
|
||||
// t.Errorf("Unexpected Supplier for CDR: %+v", reply[0])
|
||||
//}
|
||||
}
|
||||
/*
|
||||
// Make sure call cost contains the matched information
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetCallCostLog", utils.AttrGetCallCost{CgrId: CGRID}, &cCost); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if utils.IsSliceMember([]string{cCost.Timespans[0].MatchedSubject, cCost.Timespans[0].MatchedPrefix, cCost.Timespans[0].MatchedDestId}, "") {
|
||||
t.Errorf("Unexpected Matched* for CallCost: %+v", cCost.Timespans[0])
|
||||
}
|
||||
*/
|
||||
|
||||
req = utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}, DestinationPrefixes: []string{"1003"}}
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
//CGRID = reply[0].CGRID
|
||||
if reply[0].RequestType != utils.META_PREPAID {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "65" && reply[0].Usage != "66" { // Usage as seconds
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Cost != 0 { // Cost was not calculated
|
||||
t.Errorf("Unexpected Cost for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
/*
|
||||
// Make sure call cost contains the matched information
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetCallCostLog", utils.AttrGetCallCost{CgrId: CGRID}, &cCost); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if utils.IsSliceMember([]string{cCost.Timespans[0].MatchedSubject, cCost.Timespans[0].MatchedPrefix, cCost.Timespans[0].MatchedDestId}, "") {
|
||||
t.Errorf("Unexpected Matched* for CallCost: %+v", cCost.Timespans[0])
|
||||
}
|
||||
*/
|
||||
req = utils.RPCCDRsFilter{Accounts: []string{"1001"}, RunIDs: []string{"derived_run1"}}
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 2 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
if reply[0].RequestType != utils.META_RATED {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Subject != "1002" {
|
||||
t.Errorf("Unexpected Subject for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutFsCalls1002Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{Accounts: []string{"1002"}, RunIDs: []string{utils.META_DEFAULT}}
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 2 { // Should be counted here also call originated form 1006 which is aliased to 1002
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
if reply[0].Source != "freeswitch_json" {
|
||||
t.Errorf("Unexpected Source for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].RequestType != utils.META_POSTPAID {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Destination != "1001" {
|
||||
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "61" { // Usage as seconds
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutFsCalls1003Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{Accounts: []string{"1003"}, RunIDs: []string{utils.META_DEFAULT}}
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
if reply[0].Source != "freeswitch_json" {
|
||||
t.Errorf("Unexpected Source for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].RequestType != utils.META_PSEUDOPREPAID {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Destination != "1001" {
|
||||
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "63" && reply[0].Usage != "64" { // Usage as seconds, sometimes takes a second longer to disconnect
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutFsCalls1004Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{Accounts: []string{"1004"}, RunIDs: []string{utils.META_DEFAULT}}
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
if reply[0].Source != "freeswitch_json" {
|
||||
t.Errorf("Unexpected Source for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].RequestType != utils.META_RATED {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Destination != "1001" {
|
||||
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "62" && reply[0].Usage != "63" { // Usage as seconds
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Make sure we don't have any CDRs for 1006 since it should have been aliased to 1002
|
||||
func TestTutFsCalls1006Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{Accounts: []string{"1006"}, RunIDs: []string{utils.META_DEFAULT}}
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 0 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutFsCalls1007Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{Accounts: []string{"1007"}, RunIDs: []string{utils.META_DEFAULT}}
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
if reply[0].Source != "freeswitch_json" {
|
||||
t.Errorf("Unexpected Source for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].RequestType != utils.META_PREPAID {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Destination != "1002" {
|
||||
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "66" && reply[0].Usage != "67" { // Usage as seconds
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Cost == -1.0 { // Cost was not calculated
|
||||
t.Errorf("Unexpected Cost for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutFsCallsAccountFraud1001(t *testing.T) {
|
||||
var reply string
|
||||
attrAddBlnc := &v1.AttrAddBalance{Tenant: "cgrates.org", Account: "1001", BalanceType: "*monetary", Value: 101}
|
||||
if err := tutFsCallsRpc.Call("ApierV1.AddBalance", attrAddBlnc, &reply); err != nil {
|
||||
t.Error("Got error on ApierV1.AddBalance: ", err.Error())
|
||||
} else if reply != "OK" {
|
||||
t.Errorf("Calling ApierV1.AddBalance received: %s", reply)
|
||||
}
|
||||
}
|
||||
|
||||
// Based on Fraud automatic mitigation, our account should be disabled
|
||||
func TestTutFsCallsAccountDisabled1001(t *testing.T) {
|
||||
var reply *engine.Account
|
||||
attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"}
|
||||
if err := tutFsCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.Disabled == false {
|
||||
t.Error("Account should be disabled per fraud detection rules.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutFsCallsStopPjsuaListener(t *testing.T) {
|
||||
tutFsCallsPjSuaListener.Write([]byte("q\n")) // Close pjsua
|
||||
time.Sleep(time.Duration(1) * time.Second) // Allow pjsua to finish it's tasks, eg un-REGISTER
|
||||
}
|
||||
|
||||
func TestTutFsCallsStopCgrEngine(t *testing.T) {
|
||||
if err := engine.KillEngine(100); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutFsCallsStopFS(t *testing.T) {
|
||||
engine.KillProcName("freeswitch", 1000)
|
||||
}
|
||||
@@ -1,496 +0,0 @@
|
||||
// +build calls
|
||||
|
||||
/*
|
||||
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 general_tests
|
||||
|
||||
import (
|
||||
"net/rpc"
|
||||
"net/rpc/jsonrpc"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/apier/v1"
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
var tutKamCallsCfg *config.CGRConfig
|
||||
var tutKamCallsRpc *rpc.Client
|
||||
var tutKamCallsPjSuaListener *os.File
|
||||
|
||||
func TestTutKamCallsInitCfg(t *testing.T) {
|
||||
// Init config first
|
||||
var err error
|
||||
tutKamCallsCfg, err = config.NewCGRConfigFromFolder(path.Join(*dataDir, "tutorials", "kamevapi", "cgrates", "etc", "cgrates"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
tutKamCallsCfg.DataFolderPath = *dataDir // Share DataFolderPath through config towards StoreDb for Flush()
|
||||
config.SetCgrConfig(tutKamCallsCfg)
|
||||
}
|
||||
|
||||
// Remove data in both rating and accounting db
|
||||
func TestTutKamCallsResetDataDb(t *testing.T) {
|
||||
if err := engine.InitDataDb(tutKamCallsCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Wipe out the cdr database
|
||||
func TestTutKamCallsResetStorDb(t *testing.T) {
|
||||
if err := engine.InitStorDb(tutKamCallsCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// start FS server
|
||||
func TestTutKamCallsStartKamailio(t *testing.T) {
|
||||
engine.KillProcName("kamailio", 3000)
|
||||
if err := engine.CallScript(path.Join(*dataDir, "tutorials", "kamevapi", "kamailio", "etc", "init.d", "kamailio"), "start", 2000); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Start CGR Engine
|
||||
func TestTutKamCallsStartEngine(t *testing.T) {
|
||||
engine.KillProcName("cgr-engine", *waitRater)
|
||||
if err := engine.CallScript(path.Join(*dataDir, "tutorials", "kamevapi", "cgrates", "etc", "init.d", "cgrates"), "start", 100); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Restart FS so we make sure reconnects are working
|
||||
func TestTutKamCallsRestartKamailio(t *testing.T) {
|
||||
if err := engine.CallScript(path.Join(*dataDir, "tutorials", "kamevapi", "kamailio", "etc", "init.d", "kamailio"), "restart", 3000); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Connect rpc client to rater
|
||||
func TestTutKamCallsRpcConn(t *testing.T) {
|
||||
var err error
|
||||
tutKamCallsRpc, err = jsonrpc.Dial("tcp", tutKamCallsCfg.RPCJSONListen) // 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 TestTutKamCallsLoadTariffPlanFromFolder(t *testing.T) {
|
||||
reply := ""
|
||||
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "tutorial")}
|
||||
if err := tutKamCallsRpc.Call("ApierV1.LoadTariffPlanFromFolder", attrs, &reply); err != nil {
|
||||
t.Error(err)
|
||||
} else if reply != "OK" {
|
||||
t.Error(reply)
|
||||
}
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for scheduler to execute topups
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutKamCallsAccountsBefore(t *testing.T) {
|
||||
var reply *engine.Account
|
||||
attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"}
|
||||
if err := tutKamCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() != 10.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
}
|
||||
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1002"}
|
||||
if err := tutKamCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() != 10.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
}
|
||||
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1003"}
|
||||
if err := tutKamCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() != 10.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
}
|
||||
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1004"}
|
||||
if err := tutKamCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() != 10.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
}
|
||||
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1007"}
|
||||
if err := tutKamCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() != 0.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
}
|
||||
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1005"}
|
||||
if err := tutKamCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err == nil || err.Error() != utils.ErrNotFound.Error() {
|
||||
t.Errorf("Got error on ApierV2.GetAccount: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure all stats queues are in place
|
||||
func TestTutKamCallsCdrStatsBefore(t *testing.T) {
|
||||
//eQueueIds := []string{"*default", "CDRST1", "CDRST_1001", "CDRST_1002", "CDRST_1003", "STATS_SUPPL1", "STATS_SUPPL2"}
|
||||
var statMetrics map[string]float64
|
||||
eMetrics := map[string]float64{engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1, engine.ACC: -1}
|
||||
if err := tutKamCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "CDRST1"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
eMetrics = map[string]float64{engine.ACC: -1, engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1}
|
||||
if err := tutKamCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "CDRST_1001"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
eMetrics = map[string]float64{engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1, engine.ACC: -1}
|
||||
if err := tutKamCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "CDRST_1002"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
eMetrics = map[string]float64{engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1, engine.ACC: -1}
|
||||
if err := tutKamCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "CDRST_1003"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
eMetrics = map[string]float64{engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1, engine.ACC: -1}
|
||||
if err := tutKamCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "STATS_SUPPL1"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
eMetrics = map[string]float64{engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1, engine.ACC: -1}
|
||||
if err := tutKamCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "STATS_SUPPL2"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
}
|
||||
|
||||
// Start Pjsua as listener and register it to receive calls
|
||||
func TestTutKamCallsStartPjsuaListener(t *testing.T) {
|
||||
var err error
|
||||
acnts := []*engine.PjsuaAccount{
|
||||
&engine.PjsuaAccount{Id: "sip:1001@127.0.0.1", Username: "1001", Password: "CGRateS.org", Realm: "*", Registrar: "sip:127.0.0.1:5060"},
|
||||
&engine.PjsuaAccount{Id: "sip:1002@127.0.0.1", Username: "1002", Password: "CGRateS.org", Realm: "*", Registrar: "sip:127.0.0.1:5060"},
|
||||
&engine.PjsuaAccount{Id: "sip:1003@127.0.0.1", Username: "1003", Password: "CGRateS.org", Realm: "*", Registrar: "sip:127.0.0.1:5060"},
|
||||
&engine.PjsuaAccount{Id: "sip:1004@127.0.0.1", Username: "1004", Password: "CGRateS.org", Realm: "*", Registrar: "sip:127.0.0.1:5060"},
|
||||
&engine.PjsuaAccount{Id: "sip:1006@127.0.0.1", Username: "1006", Password: "CGRateS.org", Realm: "*", Registrar: "sip:127.0.0.1:5060"},
|
||||
&engine.PjsuaAccount{Id: "sip:1007@127.0.0.1", Username: "1007", Password: "CGRateS.org", Realm: "*", Registrar: "sip:127.0.0.1:5060"}}
|
||||
if tutKamCallsPjSuaListener, err = engine.StartPjsuaListener(acnts, 5070, time.Duration(*waitRater)*time.Millisecond); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Call from 1001 (prepaid) to 1002
|
||||
func TestTutKamCallsCall1001To1002(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1001@127.0.0.1", Username: "1001", Password: "CGRateS.org", Realm: "*"}, "sip:1002@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(67)*time.Second, 5071); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Call from 1001 (prepaid) to 1003
|
||||
func TestTutKamCallsCall1001To1003(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1001@127.0.0.1", Username: "1001", Password: "CGRateS.org", Realm: "*"}, "sip:1003@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(65)*time.Second, 5072); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutKamCallsCall1002To1001(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1002@127.0.0.1", Username: "1002", Password: "CGRateS.org", Realm: "*"}, "sip:1001@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(61)*time.Second, 5073); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutKamCallsCall1003To1001(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1003@127.0.0.1", Username: "1003", Password: "CGRateS.org", Realm: "*"}, "sip:1001@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(63)*time.Second, 5074); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutKamCallsCall1004To1001(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1004@127.0.0.1", Username: "1004", Password: "CGRateS.org", Realm: "*"}, "sip:1001@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(62)*time.Second, 5075); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutKamCallsCall1006To1002(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1006@127.0.0.1", Username: "1006", Password: "CGRateS.org", Realm: "*"}, "sip:1002@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(64)*time.Second, 5076); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutKamCallsCall1007To1002(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1007@127.0.0.1", Username: "1007", Password: "CGRateS.org", Realm: "*"}, "sip:1002@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(66)*time.Second, 5077); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutKamCallsAccount1001(t *testing.T) {
|
||||
time.Sleep(time.Duration(70) * time.Second) // Allow calls to finish before start querying the results
|
||||
var reply *engine.Account
|
||||
attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"}
|
||||
if err := tutKamCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() == 10.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
} else if reply.Disabled == true {
|
||||
t.Error("Account disabled")
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutKamCalls1001Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
//var cgrId string // Share with getCostDetails
|
||||
//var cCost engine.CallCost
|
||||
req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}, DestinationPrefixes: []string{"1002"}}
|
||||
if err := tutKamCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
//cgrId = reply[0].CGRID
|
||||
if reply[0].Source != "KAMAILIO_CGR_CALL_END" {
|
||||
t.Errorf("Unexpected Source for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].RequestType != utils.META_PREPAID {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "67" { // Usage as seconds
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Cost == -1.0 { // Cost was not calculated
|
||||
t.Errorf("Unexpected Cost for CDR: %+v", reply[0])
|
||||
}
|
||||
//if reply[0].Supplier != "suppl2" { // Usage as seconds
|
||||
// t.Errorf("Unexpected Supplier for CDR: %+v", reply[0])
|
||||
//}
|
||||
}
|
||||
/*
|
||||
// Make sure call cost contains the matched information
|
||||
if err := tutKamCallsRpc.Call("ApierV2.GetCallCostLog", utils.AttrGetCallCost{CgrId: cgrId}, &cCost); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if utils.IsSliceMember([]string{cCost.Timespans[0].MatchedSubject, cCost.Timespans[0].MatchedPrefix, cCost.Timespans[0].MatchedDestId}, "") {
|
||||
t.Errorf("Unexpected Matched* for CallCost: %+v", cCost.Timespans[0])
|
||||
}
|
||||
*/
|
||||
req = utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}, DestinationPrefixes: []string{"1003"}}
|
||||
if err := tutKamCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
//cgrId = reply[0].CGRID
|
||||
if reply[0].RequestType != utils.META_PREPAID {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "65" && reply[0].Usage != "66" { // Usage as seconds
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Cost != 0 { // Cost was not calculated
|
||||
t.Errorf("Unexpected Cost for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
/*
|
||||
// Make sure call cost contains the matched information
|
||||
if err := tutKamCallsRpc.Call("ApierV2.GetCallCostLog", utils.AttrGetCallCost{CgrId: cgrId}, &cCost); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if utils.IsSliceMember([]string{cCost.Timespans[0].MatchedSubject, cCost.Timespans[0].MatchedPrefix, cCost.Timespans[0].MatchedDestId}, "") {
|
||||
t.Errorf("Unexpected Matched* for CallCost: %+v", cCost.Timespans[0])
|
||||
}
|
||||
*/
|
||||
req = utils.RPCCDRsFilter{Accounts: []string{"1001"}, RunIDs: []string{"derived_run1"}}
|
||||
if err := tutKamCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 2 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
if reply[0].RequestType != utils.META_RATED {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Subject != "1002" {
|
||||
t.Errorf("Unexpected Subject for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutKamCalls1002Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{Accounts: []string{"1002"}, RunIDs: []string{utils.META_DEFAULT}}
|
||||
if err := tutKamCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 2 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
if reply[0].Source != "KAMAILIO_CGR_CALL_END" {
|
||||
t.Errorf("Unexpected Source for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].RequestType != utils.META_POSTPAID {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Destination != "1001" {
|
||||
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "61" { // Usage as seconds
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutKamCalls1003Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{Accounts: []string{"1003"}, RunIDs: []string{utils.META_DEFAULT}}
|
||||
if err := tutKamCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
if reply[0].Source != "KAMAILIO_CGR_CALL_END" {
|
||||
t.Errorf("Unexpected Source for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].RequestType != utils.META_PSEUDOPREPAID {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Destination != "1001" {
|
||||
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "63" && reply[0].Usage != "64" { // Usage as seconds, sometimes takes a second longer to disconnect
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutKamCalls1004Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{Accounts: []string{"1004"}, RunIDs: []string{utils.META_DEFAULT}}
|
||||
if err := tutKamCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
if reply[0].Source != "KAMAILIO_CGR_CALL_END" {
|
||||
t.Errorf("Unexpected Source for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].RequestType != utils.META_RATED {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Destination != "1001" {
|
||||
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "62" && reply[0].Usage != "63" { // Usage as seconds
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutKamCalls1006Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{Accounts: []string{"1006"}, RunIDs: []string{utils.META_DEFAULT}}
|
||||
if err := tutKamCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 0 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutKamCalls1007Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{Accounts: []string{"1007"}, RunIDs: []string{utils.META_DEFAULT}}
|
||||
if err := tutKamCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
if reply[0].Source != "KAMAILIO_CGR_CALL_END" {
|
||||
t.Errorf("Unexpected Source for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].RequestType != utils.META_PREPAID {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Destination != "1002" {
|
||||
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "66" && reply[0].Usage != "67" { // Usage as seconds
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Cost == -1.0 { // Cost was not calculated
|
||||
t.Errorf("Unexpected Cost for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutKamCallsAccountFraud1001(t *testing.T) {
|
||||
var reply string
|
||||
attrAddBlnc := &v1.AttrAddBalance{Tenant: "cgrates.org", Account: "1001", BalanceType: "*monetary", Value: 101}
|
||||
if err := tutKamCallsRpc.Call("ApierV1.AddBalance", attrAddBlnc, &reply); err != nil {
|
||||
t.Error("Got error on ApierV1.AddBalance: ", err.Error())
|
||||
} else if reply != "OK" {
|
||||
t.Errorf("Calling ApierV1.AddBalance received: %s", reply)
|
||||
}
|
||||
}
|
||||
|
||||
// Based on Fraud automatic mitigation, our account should be disabled
|
||||
func TestTutKamCallsAccountDisabled1001(t *testing.T) {
|
||||
var reply *engine.Account
|
||||
attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"}
|
||||
if err := tutKamCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.Disabled == false {
|
||||
t.Error("Account should be disabled per fraud detection rules.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutKamCallsStopPjsuaListener(t *testing.T) {
|
||||
tutKamCallsPjSuaListener.Write([]byte("q\n")) // Close pjsua
|
||||
time.Sleep(time.Duration(1) * time.Second) // Allow pjsua to finish it's tasks, eg un-REGISTER
|
||||
}
|
||||
|
||||
func TestTutKamCallsStopCgrEngine(t *testing.T) {
|
||||
if err := engine.KillEngine(100); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutKamCallsStopKam(t *testing.T) {
|
||||
engine.KillProcName("kamailio", 1000)
|
||||
}
|
||||
@@ -1,496 +0,0 @@
|
||||
// +build calls
|
||||
|
||||
/*
|
||||
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 general_tests
|
||||
|
||||
import (
|
||||
"net/rpc"
|
||||
"net/rpc/jsonrpc"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/apier/v1"
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
var tutOsipsCallsCfg *config.CGRConfig
|
||||
var tutOsipsCallsRpc *rpc.Client
|
||||
var tutOsipsCallsPjSuaListener *os.File
|
||||
|
||||
func TestTutOsipsCallsInitCfg(t *testing.T) {
|
||||
// Init config first
|
||||
var err error
|
||||
tutOsipsCallsCfg, err = config.NewCGRConfigFromFolder(path.Join(*dataDir, "tutorials", "osips_async", "cgrates", "etc", "cgrates"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
tutOsipsCallsCfg.DataFolderPath = *dataDir // Share DataFolderPath through config towards StoreDb for Flush()
|
||||
config.SetCgrConfig(tutOsipsCallsCfg)
|
||||
}
|
||||
|
||||
// Remove data in both rating and accounting db
|
||||
func TestTutOsipsCallsResetDataDb(t *testing.T) {
|
||||
if err := engine.InitDataDb(tutOsipsCallsCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Wipe out the cdr database
|
||||
func TestTutOsipsCallsResetStorDb(t *testing.T) {
|
||||
if err := engine.InitStorDb(tutOsipsCallsCfg); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// start FS server
|
||||
func TestTutOsipsCallsStartOsips(t *testing.T) {
|
||||
engine.KillProcName("opensips", 3000)
|
||||
if err := engine.CallScript(path.Join(*dataDir, "tutorials", "osips_async", "opensips", "etc", "init.d", "opensips"), "start", 3000); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Start CGR Engine
|
||||
func TestTutOsipsCallsStartEngine(t *testing.T) {
|
||||
engine.KillProcName("cgr-engine", *waitRater)
|
||||
if err := engine.CallScript(path.Join(*dataDir, "tutorials", "osips_async", "cgrates", "etc", "init.d", "cgrates"), "start", 100); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Restart FS so we make sure reconnects are working
|
||||
func TestTutOsipsCallsRestartOsips(t *testing.T) {
|
||||
if err := engine.CallScript(path.Join(*dataDir, "tutorials", "osips_async", "opensips", "etc", "init.d", "opensips"), "restart", 3000); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Connect rpc client to rater
|
||||
func TestTutOsipsCallsRpcConn(t *testing.T) {
|
||||
var err error
|
||||
tutOsipsCallsRpc, err = jsonrpc.Dial("tcp", tutOsipsCallsCfg.RPCJSONListen) // 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 TestTutOsipsCallsLoadTariffPlanFromFolder(t *testing.T) {
|
||||
reply := ""
|
||||
attrs := &utils.AttrLoadTpFromFolder{FolderPath: path.Join(*dataDir, "tariffplans", "tutorial")}
|
||||
if err := tutOsipsCallsRpc.Call("ApierV1.LoadTariffPlanFromFolder", attrs, &reply); err != nil {
|
||||
t.Error(err)
|
||||
} else if reply != "OK" {
|
||||
t.Error(reply)
|
||||
}
|
||||
time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for scheduler to execute topups
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutOsipsCallsAccountsBefore(t *testing.T) {
|
||||
var reply *engine.Account
|
||||
attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"}
|
||||
if err := tutOsipsCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() != 10.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
}
|
||||
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1002"}
|
||||
if err := tutOsipsCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() != 10.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
}
|
||||
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1003"}
|
||||
if err := tutOsipsCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() != 10.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
}
|
||||
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1004"}
|
||||
if err := tutOsipsCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() != 10.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
}
|
||||
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1007"}
|
||||
if err := tutOsipsCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() != 0.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
}
|
||||
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1005"}
|
||||
if err := tutOsipsCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err == nil || err.Error() != utils.ErrNotFound.Error() {
|
||||
t.Error("Got error on ApierV2.GetAccount: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure all stats queues are in place
|
||||
func TestTutOsipsCallsCdrStatsBefore(t *testing.T) {
|
||||
//eQueueIds := []string{"*default", "CDRST1", "CDRST_1001", "CDRST_1002", "CDRST_1003", "STATS_SUPPL1", "STATS_SUPPL2"}
|
||||
var statMetrics map[string]float64
|
||||
eMetrics := map[string]float64{engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1, engine.ACC: -1}
|
||||
if err := tutOsipsCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "CDRST1"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
eMetrics = map[string]float64{engine.ACC: -1, engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1}
|
||||
if err := tutOsipsCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "CDRST_1001"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
eMetrics = map[string]float64{engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1, engine.ACC: -1}
|
||||
if err := tutOsipsCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "CDRST_1002"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
eMetrics = map[string]float64{engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1, engine.ACC: -1}
|
||||
if err := tutOsipsCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "CDRST_1003"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
eMetrics = map[string]float64{engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1, engine.ACC: -1}
|
||||
if err := tutOsipsCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "STATS_SUPPL1"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
eMetrics = map[string]float64{engine.ACD: -1, engine.ASR: -1, engine.TCC: -1, engine.TCD: -1, engine.ACC: -1}
|
||||
if err := tutOsipsCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: "STATS_SUPPL2"}, &statMetrics); err != nil {
|
||||
t.Error("Calling CDRStatsV1.GetMetrics, got error: ", err.Error())
|
||||
} else if !reflect.DeepEqual(eMetrics, statMetrics) {
|
||||
t.Errorf("Expecting: %v, received: %v", eMetrics, statMetrics)
|
||||
}
|
||||
}
|
||||
|
||||
// Start Pjsua as listener and register it to receive calls
|
||||
func TestTutOsipsCallsStartPjsuaListener(t *testing.T) {
|
||||
var err error
|
||||
acnts := []*engine.PjsuaAccount{
|
||||
&engine.PjsuaAccount{Id: "sip:1001@127.0.0.1", Username: "1001", Password: "1234", Realm: "*", Registrar: "sip:127.0.0.1:5060"},
|
||||
&engine.PjsuaAccount{Id: "sip:1002@127.0.0.1", Username: "1002", Password: "1234", Realm: "*", Registrar: "sip:127.0.0.1:5060"},
|
||||
&engine.PjsuaAccount{Id: "sip:1003@127.0.0.1", Username: "1003", Password: "1234", Realm: "*", Registrar: "sip:127.0.0.1:5060"},
|
||||
&engine.PjsuaAccount{Id: "sip:1004@127.0.0.1", Username: "1004", Password: "1234", Realm: "*", Registrar: "sip:127.0.0.1:5060"},
|
||||
&engine.PjsuaAccount{Id: "sip:1006@127.0.0.1", Username: "1006", Password: "1234", Realm: "*", Registrar: "sip:127.0.0.1:5060"},
|
||||
&engine.PjsuaAccount{Id: "sip:1007@127.0.0.1", Username: "1007", Password: "1234", Realm: "*", Registrar: "sip:127.0.0.1:5060"}}
|
||||
if tutOsipsCallsPjSuaListener, err = engine.StartPjsuaListener(acnts, 5070, time.Duration(*waitRater)*time.Millisecond); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Call from 1001 (prepaid) to 1002
|
||||
func TestTutOsipsCallsCall1001To1002(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1001@127.0.0.1", Username: "1001", Password: "1234", Realm: "*"}, "sip:1002@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(67)*time.Second, 5071); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Call from 1001 (prepaid) to 1003
|
||||
func TestTutOsipsCallsCall1001To1003(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1001@127.0.0.1", Username: "1001", Password: "1234", Realm: "*"}, "sip:1003@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(65)*time.Second, 5072); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutOsipsCallsCall1002To1001(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1002@127.0.0.1", Username: "1002", Password: "1234", Realm: "*"}, "sip:1001@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(61)*time.Second, 5073); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutOsipsCallsCall1003To1001(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1003@127.0.0.1", Username: "1003", Password: "1234", Realm: "*"}, "sip:1001@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(63)*time.Second, 5074); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutOsipsCallsCall1004To1001(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1004@127.0.0.1", Username: "1004", Password: "1234", Realm: "*"}, "sip:1001@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(62)*time.Second, 5075); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutOsipsCallsCall1006To1002(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1006@127.0.0.1", Username: "1006", Password: "1234", Realm: "*"}, "sip:1002@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(64)*time.Second, 5076); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutOsipsCallsCall1007To1002(t *testing.T) {
|
||||
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1007@127.0.0.1", Username: "1007", Password: "1234", Realm: "*"}, "sip:1002@127.0.0.1",
|
||||
"sip:127.0.0.1:5060", time.Duration(66)*time.Second, 5077); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutOsipsCallsAccount1001(t *testing.T) {
|
||||
time.Sleep(time.Duration(70) * time.Second) // Allow calls to finish before start querying the results
|
||||
var reply *engine.Account
|
||||
attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"}
|
||||
if err := tutOsipsCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.BalanceMap[utils.MONETARY].GetTotalValue() == 10.0 { // Make sure we debitted
|
||||
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY].GetTotalValue())
|
||||
} else if reply.Disabled == true {
|
||||
t.Error("Account disabled")
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutOsipsCalls1001Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
//var cgrId string // Share with getCostDetails
|
||||
//var cCost engine.CallCost
|
||||
req := utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}, DestinationPrefixes: []string{"1002"}}
|
||||
if err := tutOsipsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
//cgrId = reply[0].CGRID
|
||||
if reply[0].Source != "OSIPS_E_ACC_EVENT" {
|
||||
t.Errorf("Unexpected Source for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].RequestType != utils.META_PREPAID {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "67" { // Usage as seconds
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Cost == -1.0 { // Cost was not calculated
|
||||
t.Errorf("Unexpected Cost for CDR: %+v", reply[0])
|
||||
}
|
||||
//if reply[0].Supplier != "suppl2" { // Usage as seconds
|
||||
// t.Errorf("Unexpected Supplier for CDR: %+v", reply[0])
|
||||
//}
|
||||
}
|
||||
/*
|
||||
// Make sure call cost contains the matched information
|
||||
if err := tutOsipsCallsRpc.Call("ApierV2.GetCallCostLog", utils.AttrGetCallCost{CgrId: cgrId}, &cCost); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if utils.IsSliceMember([]string{cCost.Timespans[0].MatchedSubject, cCost.Timespans[0].MatchedPrefix, cCost.Timespans[0].MatchedDestId}, "") {
|
||||
t.Errorf("Unexpected Matched* for CallCost: %+v", cCost.Timespans[0])
|
||||
}
|
||||
*/
|
||||
req = utils.RPCCDRsFilter{RunIDs: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}, DestinationPrefixes: []string{"1003"}}
|
||||
if err := tutOsipsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
//cgrId = reply[0].CGRID
|
||||
if reply[0].RequestType != utils.META_PREPAID {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "65" && reply[0].Usage != "66" { // Usage as seconds
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Cost != 0 { // Cost was not calculated
|
||||
t.Errorf("Unexpected Cost for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
/*
|
||||
// Make sure call cost contains the matched information
|
||||
if err := tutOsipsCallsRpc.Call("ApierV2.GetCallCostLog", utils.AttrGetCallCost{CgrId: cgrId}, &cCost); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if utils.IsSliceMember([]string{cCost.Timespans[0].MatchedSubject, cCost.Timespans[0].MatchedPrefix, cCost.Timespans[0].MatchedDestId}, "") {
|
||||
t.Errorf("Unexpected Matched* for CallCost: %+v", cCost.Timespans[0])
|
||||
}
|
||||
*/
|
||||
req = utils.RPCCDRsFilter{Accounts: []string{"1001"}, RunIDs: []string{"derived_run1"}}
|
||||
if err := tutOsipsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 2 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
if reply[0].RequestType != utils.META_RATED {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Subject != "1002" {
|
||||
t.Errorf("Unexpected Subject for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutOsipsCalls1002Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{Accounts: []string{"1002"}, RunIDs: []string{utils.META_DEFAULT}}
|
||||
if err := tutOsipsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 2 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
if reply[0].Source != "OSIPS_E_ACC_EVENT" {
|
||||
t.Errorf("Unexpected Source for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].RequestType != utils.META_POSTPAID {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Destination != "1001" {
|
||||
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "61" { // Usage as seconds
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutOsipsCalls1003Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{Accounts: []string{"1003"}, RunIDs: []string{utils.META_DEFAULT}}
|
||||
if err := tutOsipsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
if reply[0].Source != "OSIPS_E_ACC_EVENT" {
|
||||
t.Errorf("Unexpected Source for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].RequestType != utils.META_PSEUDOPREPAID {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Destination != "1001" {
|
||||
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "63" && reply[0].Usage != "64" { // Usage as seconds, sometimes takes a second longer to disconnect
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutOsipsCalls1004Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{Accounts: []string{"1004"}, RunIDs: []string{utils.META_DEFAULT}}
|
||||
if err := tutOsipsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
if reply[0].Source != "OSIPS_E_ACC_EVENT" {
|
||||
t.Errorf("Unexpected Source for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].RequestType != utils.META_RATED {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Destination != "1001" {
|
||||
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "62" && reply[0].Usage != "63" { // Usage as seconds
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Make sure aliasing was done for 1006 and we have no CDRs for it
|
||||
func TestTutOsipsCalls1006Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{Accounts: []string{"1006"}, RunIDs: []string{utils.META_DEFAULT}}
|
||||
if err := tutOsipsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 0 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutOsipsCalls1007Cdrs(t *testing.T) {
|
||||
var reply []*engine.ExternalCDR
|
||||
req := utils.RPCCDRsFilter{Accounts: []string{"1007"}, RunIDs: []string{utils.META_DEFAULT}}
|
||||
if err := tutOsipsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
|
||||
t.Error("Unexpected error: ", err.Error())
|
||||
} else if len(reply) != 1 {
|
||||
t.Error("Unexpected number of CDRs returned: ", len(reply))
|
||||
} else {
|
||||
if reply[0].Source != "OSIPS_E_ACC_EVENT" {
|
||||
t.Errorf("Unexpected Source for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].RequestType != utils.META_PREPAID {
|
||||
t.Errorf("Unexpected RequestType for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Destination != "1002" {
|
||||
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Usage != "66" && reply[0].Usage != "67" { // Usage as seconds
|
||||
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
|
||||
}
|
||||
if reply[0].Cost == -1.0 { // Cost was not calculated
|
||||
t.Errorf("Unexpected Cost for CDR: %+v", reply[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure account was debited properly
|
||||
func TestTutOsipsCallsAccountFraud1001(t *testing.T) {
|
||||
var reply string
|
||||
attrAddBlnc := &v1.AttrAddBalance{Tenant: "cgrates.org", Account: "1001", BalanceType: "*monetary", Value: 101}
|
||||
if err := tutOsipsCallsRpc.Call("ApierV1.AddBalance", attrAddBlnc, &reply); err != nil {
|
||||
t.Error("Got error on ApierV1.AddBalance: ", err.Error())
|
||||
} else if reply != "OK" {
|
||||
t.Errorf("Calling ApierV1.AddBalance received: %s", reply)
|
||||
}
|
||||
}
|
||||
|
||||
// Based on Fraud automatic mitigation, our account should be disabled
|
||||
func TestTutOsipsCallsAccountDisabled1001(t *testing.T) {
|
||||
var reply *engine.Account
|
||||
attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001"}
|
||||
if err := tutOsipsCallsRpc.Call("ApierV2.GetAccount", attrs, &reply); err != nil {
|
||||
t.Error("Got error on ApierV2.GetAccount: ", err.Error())
|
||||
} else if reply.Disabled == false {
|
||||
t.Error("Account should be disabled per fraud detection rules.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutOsipsCallsStopPjsuaListener(t *testing.T) {
|
||||
tutOsipsCallsPjSuaListener.Write([]byte("q\n")) // Close pjsua
|
||||
time.Sleep(time.Duration(1) * time.Second) // Allow pjsua to finish it's tasks, eg un-REGISTER
|
||||
}
|
||||
|
||||
func TestTutOsipsCallsStopCgrEngine(t *testing.T) {
|
||||
if err := engine.KillEngine(100); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTutOsipsCallsStopOpensips(t *testing.T) {
|
||||
engine.KillProcName("opensips", 100)
|
||||
}
|
||||
@@ -102,6 +102,42 @@ func TestAccountITMove(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccountITMoveEncoding(t *testing.T) {
|
||||
var err error
|
||||
accPathIn = path.Join(*dataDir, "conf", "samples", "tutmongojson")
|
||||
accCfgIn, err = config.NewCGRConfigFromFolder(accPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
accPathOut = path.Join(*dataDir, "conf", "samples", "tutmongomsgpack")
|
||||
accCfgOut, err = config.NewCGRConfigFromFolder(accPathOut)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
accAction = utils.Move
|
||||
for _, stest := range sTestsAccIT {
|
||||
t.Run("TestAccountITMove", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccountITMoveEncoding2(t *testing.T) {
|
||||
var err error
|
||||
accPathIn = path.Join(*dataDir, "conf", "samples", "tutmysqljson")
|
||||
accCfgIn, err = config.NewCGRConfigFromFolder(accPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
accPathOut = path.Join(*dataDir, "conf", "samples", "tutmysqlmsgpack")
|
||||
accCfgOut, err = config.NewCGRConfigFromFolder(accPathOut)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
accAction = utils.Move
|
||||
for _, stest := range sTestsAccIT {
|
||||
t.Run("TestAccountITMove", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func testAccITConnect(t *testing.T) {
|
||||
dataDBIn, err := NewMigratorDataDB(accCfgIn.DataDbType,
|
||||
accCfgIn.DataDbHost, accCfgIn.DataDbPort, accCfgIn.DataDbName,
|
||||
|
||||
249
migrator/action_it_test.go
Normal file
249
migrator/action_it_test.go
Normal file
@@ -0,0 +1,249 @@
|
||||
// +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 migrator
|
||||
|
||||
import (
|
||||
"log"
|
||||
"path"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
actPathIn string
|
||||
actPathOut string
|
||||
actCfgIn *config.CGRConfig
|
||||
actCfgOut *config.CGRConfig
|
||||
actMigrator *Migrator
|
||||
actAction string
|
||||
)
|
||||
|
||||
var sTestsActIT = []func(t *testing.T){
|
||||
testActITConnect,
|
||||
testActITFlush,
|
||||
testActITMigrateAndMove,
|
||||
}
|
||||
|
||||
func TestActionITRedis(t *testing.T) {
|
||||
var err error
|
||||
actPathIn = path.Join(*dataDir, "conf", "samples", "tutmysql")
|
||||
actCfgIn, err = config.NewCGRConfigFromFolder(actPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actCfgOut, err = config.NewCGRConfigFromFolder(actPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actAction = utils.Migrate
|
||||
for _, stest := range sTestsActIT {
|
||||
t.Run("TestActionITMigrateRedis", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestActionITMongo(t *testing.T) {
|
||||
var err error
|
||||
actPathIn = path.Join(*dataDir, "conf", "samples", "tutmongo")
|
||||
actCfgIn, err = config.NewCGRConfigFromFolder(actPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actCfgOut, err = config.NewCGRConfigFromFolder(actPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actAction = utils.Migrate
|
||||
for _, stest := range sTestsActIT {
|
||||
t.Run("TestActionITMigrateMongo", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestActionITMove(t *testing.T) {
|
||||
var err error
|
||||
actPathIn = path.Join(*dataDir, "conf", "samples", "tutmongo")
|
||||
actCfgIn, err = config.NewCGRConfigFromFolder(actPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actPathOut = path.Join(*dataDir, "conf", "samples", "tutmysql")
|
||||
actCfgOut, err = config.NewCGRConfigFromFolder(actPathOut)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actAction = utils.Move
|
||||
for _, stest := range sTestsActIT {
|
||||
t.Run("TestActionITMove", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestActionITMoveEncoding(t *testing.T) {
|
||||
var err error
|
||||
actPathIn = path.Join(*dataDir, "conf", "samples", "tutmongojson")
|
||||
actCfgIn, err = config.NewCGRConfigFromFolder(actPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actPathOut = path.Join(*dataDir, "conf", "samples", "tutmongomsgpack")
|
||||
actCfgOut, err = config.NewCGRConfigFromFolder(actPathOut)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actAction = utils.Move
|
||||
for _, stest := range sTestsActIT {
|
||||
t.Run("TestActionITMoveEncoding", stest)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func TestActionITMoveEncoding2(t *testing.T) {
|
||||
var err error
|
||||
actPathIn = path.Join(*dataDir, "conf", "samples", "tutmysqljson")
|
||||
actCfgIn, err = config.NewCGRConfigFromFolder(actPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actPathOut = path.Join(*dataDir, "conf", "samples", "tutmysqlmsgpack")
|
||||
actCfgOut, err = config.NewCGRConfigFromFolder(actPathOut)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actAction = utils.Move
|
||||
for _, stest := range sTestsActIT {
|
||||
t.Run("TestActionITMoveEncoding2", stest)
|
||||
}
|
||||
}*/
|
||||
|
||||
func testActITConnect(t *testing.T) {
|
||||
dataDBIn, err := NewMigratorDataDB(actCfgIn.DataDbType,
|
||||
actCfgIn.DataDbHost, actCfgIn.DataDbPort, actCfgIn.DataDbName,
|
||||
actCfgIn.DataDbUser, actCfgIn.DataDbPass, actCfgIn.DBDataEncoding,
|
||||
config.CgrConfig().CacheCfg(), *loadHistorySize)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
dataDBOut, err := NewMigratorDataDB(actCfgOut.DataDbType,
|
||||
actCfgOut.DataDbHost, actCfgOut.DataDbPort, actCfgOut.DataDbName,
|
||||
actCfgOut.DataDbUser, actCfgOut.DataDbPass, actCfgOut.DBDataEncoding,
|
||||
config.CgrConfig().CacheCfg(), *loadHistorySize)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
actMigrator, err = NewMigrator(dataDBIn, dataDBOut,
|
||||
nil, nil,
|
||||
false, false, false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testActITFlush(t *testing.T) {
|
||||
actMigrator.dmOut.DataManager().DataDB().Flush("")
|
||||
if err := engine.SetDBVersions(actMigrator.dmOut.DataManager().DataDB()); err != nil {
|
||||
t.Error("Error ", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func testActITMigrateAndMove(t *testing.T) {
|
||||
timingSlice := []*engine.RITiming{
|
||||
&engine.RITiming{
|
||||
Years: utils.Years{},
|
||||
Months: utils.Months{},
|
||||
MonthDays: utils.MonthDays{},
|
||||
WeekDays: utils.WeekDays{},
|
||||
},
|
||||
}
|
||||
|
||||
v1act := &v1Action{
|
||||
Id: "test",
|
||||
ActionType: "",
|
||||
BalanceType: "",
|
||||
Direction: "INBOUND",
|
||||
ExtraParameters: "",
|
||||
ExpirationString: "",
|
||||
Balance: &v1Balance{
|
||||
Timings: timingSlice,
|
||||
},
|
||||
}
|
||||
|
||||
v1acts := &v1Actions{
|
||||
v1act,
|
||||
}
|
||||
|
||||
act := &engine.Actions{
|
||||
&engine.Action{
|
||||
Id: "test",
|
||||
ActionType: "",
|
||||
ExtraParameters: "",
|
||||
ExpirationString: "",
|
||||
Weight: 0.00,
|
||||
Balance: &engine.BalanceFilter{
|
||||
Timings: timingSlice,
|
||||
},
|
||||
},
|
||||
}
|
||||
switch actAction {
|
||||
case utils.Migrate:
|
||||
err := actMigrator.dmIN.setV1Actions(v1acts)
|
||||
if err != nil {
|
||||
t.Error("Error when setting v1 Actions ", err.Error())
|
||||
}
|
||||
currentVersion := engine.Versions{utils.StatS: 2, utils.Thresholds: 2, utils.Accounts: 2, utils.Actions: 1, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2}
|
||||
err = actMigrator.dmOut.DataManager().DataDB().SetVersions(currentVersion, false)
|
||||
if err != nil {
|
||||
t.Error("Error when setting version for Actions ", err.Error())
|
||||
}
|
||||
err, _ = actMigrator.Migrate([]string{utils.MetaActions})
|
||||
if err != nil {
|
||||
t.Error("Error when migrating Actions ", err.Error())
|
||||
}
|
||||
result, err := actMigrator.dmOut.DataManager().GetActions(v1act.Id, true, utils.NonTransactional)
|
||||
if err != nil {
|
||||
t.Error("Error when getting Actions ", err.Error())
|
||||
}
|
||||
if !reflect.DeepEqual(act, &result) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", act, &result)
|
||||
}
|
||||
case utils.Move:
|
||||
if err := actMigrator.dmIN.DataManager().SetActions(v1act.Id, *act, utils.NonTransactional); err != nil {
|
||||
t.Error("Error when setting ActionPlan ", err.Error())
|
||||
}
|
||||
currentVersion := engine.CurrentDataDBVersions()
|
||||
err := actMigrator.dmOut.DataManager().DataDB().SetVersions(currentVersion, false)
|
||||
if err != nil {
|
||||
t.Error("Error when setting version for Actions ", err.Error())
|
||||
}
|
||||
err, _ = actMigrator.Migrate([]string{utils.MetaActions})
|
||||
if err != nil {
|
||||
t.Error("Error when migrating Actions ", err.Error())
|
||||
}
|
||||
result, err := actMigrator.dmOut.DataManager().GetActions(v1act.Id, true, utils.NonTransactional)
|
||||
if err != nil {
|
||||
t.Error("Error when getting Actions ", err.Error())
|
||||
}
|
||||
if !reflect.DeepEqual(act, &result) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", act, &result)
|
||||
}
|
||||
}
|
||||
}
|
||||
250
migrator/action_plan_it_test.go
Normal file
250
migrator/action_plan_it_test.go
Normal file
@@ -0,0 +1,250 @@
|
||||
// +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 migrator
|
||||
|
||||
import (
|
||||
"log"
|
||||
"path"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
actPlnPathIn string
|
||||
actPlnPathOut string
|
||||
actPlnCfgIn *config.CGRConfig
|
||||
actPlnCfgOut *config.CGRConfig
|
||||
actPlnMigrator *Migrator
|
||||
actActionPlan string
|
||||
)
|
||||
|
||||
var sTestsActPlnIT = []func(t *testing.T){
|
||||
testActPlnITConnect,
|
||||
testActPlnITFlush,
|
||||
testActPlnITMigrateAndMove,
|
||||
}
|
||||
|
||||
func TestActionPlanITRedis(t *testing.T) {
|
||||
var err error
|
||||
actPlnPathIn = path.Join(*dataDir, "conf", "samples", "tutmysql")
|
||||
actPlnCfgIn, err = config.NewCGRConfigFromFolder(actPlnPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actPlnCfgOut, err = config.NewCGRConfigFromFolder(actPlnPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actActionPlan = utils.Migrate
|
||||
for _, stest := range sTestsActPlnIT {
|
||||
t.Run("TestActionPlanITMigrateRedis", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestActionPlanITMongo(t *testing.T) {
|
||||
var err error
|
||||
actPlnPathIn = path.Join(*dataDir, "conf", "samples", "tutmongo")
|
||||
actPlnCfgIn, err = config.NewCGRConfigFromFolder(actPlnPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actPlnCfgOut, err = config.NewCGRConfigFromFolder(actPlnPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actActionPlan = utils.Migrate
|
||||
for _, stest := range sTestsActPlnIT {
|
||||
t.Run("TestActionPlanITMigrateMongo", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestActionPlanITMove(t *testing.T) {
|
||||
var err error
|
||||
actPlnPathIn = path.Join(*dataDir, "conf", "samples", "tutmongo")
|
||||
actPlnCfgIn, err = config.NewCGRConfigFromFolder(actPlnPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actPlnPathOut = path.Join(*dataDir, "conf", "samples", "tutmysql")
|
||||
actPlnCfgOut, err = config.NewCGRConfigFromFolder(actPlnPathOut)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actActionPlan = utils.Move
|
||||
for _, stest := range sTestsActPlnIT {
|
||||
t.Run("TestActionPlanITMove", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestActionPlanITMoveEncoding(t *testing.T) {
|
||||
var err error
|
||||
actPlnPathIn = path.Join(*dataDir, "conf", "samples", "tutmongojson")
|
||||
actPlnCfgIn, err = config.NewCGRConfigFromFolder(actPlnPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actPlnPathOut = path.Join(*dataDir, "conf", "samples", "tutmongomsgpack")
|
||||
actPlnCfgOut, err = config.NewCGRConfigFromFolder(actPlnPathOut)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actActionPlan = utils.Move
|
||||
for _, stest := range sTestsActPlnIT {
|
||||
t.Run("TestActionPlanITMoveEncoding", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestActionPlanITMoveEncoding2(t *testing.T) {
|
||||
var err error
|
||||
actPlnPathIn = path.Join(*dataDir, "conf", "samples", "tutmysqljson")
|
||||
actPlnCfgIn, err = config.NewCGRConfigFromFolder(actPlnPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actPlnPathOut = path.Join(*dataDir, "conf", "samples", "tutmysqlmsgpack")
|
||||
actPlnCfgOut, err = config.NewCGRConfigFromFolder(actPlnPathOut)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actActionPlan = utils.Move
|
||||
for _, stest := range sTestsActPlnIT {
|
||||
t.Run("TestActionPlanITMoveEncoding2", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func testActPlnITConnect(t *testing.T) {
|
||||
dataDBIn, err := NewMigratorDataDB(actPlnCfgIn.DataDbType,
|
||||
actPlnCfgIn.DataDbHost, actPlnCfgIn.DataDbPort, actPlnCfgIn.DataDbName,
|
||||
actPlnCfgIn.DataDbUser, actPlnCfgIn.DataDbPass, actPlnCfgIn.DBDataEncoding,
|
||||
config.CgrConfig().CacheCfg(), *loadHistorySize)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
dataDBOut, err := NewMigratorDataDB(actPlnCfgOut.DataDbType,
|
||||
actPlnCfgOut.DataDbHost, actPlnCfgOut.DataDbPort, actPlnCfgOut.DataDbName,
|
||||
actPlnCfgOut.DataDbUser, actPlnCfgOut.DataDbPass, actPlnCfgOut.DBDataEncoding,
|
||||
config.CgrConfig().CacheCfg(), *loadHistorySize)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
actPlnMigrator, err = NewMigrator(dataDBIn, dataDBOut,
|
||||
nil, nil,
|
||||
false, false, false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testActPlnITFlush(t *testing.T) {
|
||||
actPlnMigrator.dmOut.DataManager().DataDB().Flush("")
|
||||
if err := engine.SetDBVersions(actPlnMigrator.dmOut.DataManager().DataDB()); err != nil {
|
||||
t.Error("Error ", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func testActPlnITMigrateAndMove(t *testing.T) {
|
||||
timingSlice := &engine.RITiming{
|
||||
Years: utils.Years{},
|
||||
Months: utils.Months{},
|
||||
MonthDays: utils.MonthDays{},
|
||||
WeekDays: utils.WeekDays{},
|
||||
}
|
||||
|
||||
v1actPln := &v1ActionPlans{
|
||||
&v1ActionPlan{
|
||||
Id: "test",
|
||||
AccountIds: []string{"one"},
|
||||
Timing: &engine.RateInterval{
|
||||
Timing: timingSlice,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
actPln := &engine.ActionPlan{
|
||||
Id: "test",
|
||||
AccountIDs: utils.StringMap{"one": true},
|
||||
ActionTimings: []*engine.ActionTiming{
|
||||
&engine.ActionTiming{
|
||||
Timing: &engine.RateInterval{
|
||||
Timing: timingSlice,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
switch actActionPlan {
|
||||
case utils.Migrate:
|
||||
err := actPlnMigrator.dmIN.setV1ActionPlans(v1actPln)
|
||||
if err != nil {
|
||||
t.Error("Error when setting v1 ActionPlan ", err.Error())
|
||||
}
|
||||
currentVersion := engine.Versions{utils.StatS: 2, utils.Thresholds: 2, utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 1, utils.SharedGroups: 2}
|
||||
err = actPlnMigrator.dmOut.DataManager().DataDB().SetVersions(currentVersion, false)
|
||||
if err != nil {
|
||||
t.Error("Error when setting version for ActionPlan ", err.Error())
|
||||
}
|
||||
err, _ = actPlnMigrator.Migrate([]string{utils.MetaActionPlans})
|
||||
if err != nil {
|
||||
t.Error("Error when migrating ActionPlan ", err.Error())
|
||||
}
|
||||
result, err := actPlnMigrator.dmOut.DataManager().DataDB().GetActionPlan((*v1actPln)[0].Id, true, utils.NonTransactional)
|
||||
if err != nil {
|
||||
t.Error("Error when getting ActionPlan ", err.Error())
|
||||
}
|
||||
// compared fields, uuid is generated in ActionTiming
|
||||
if !reflect.DeepEqual(actPln.Id, result.Id) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", actPln.Id, result.Id)
|
||||
} else if !reflect.DeepEqual(actPln.AccountIDs, result.AccountIDs) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", actPln.AccountIDs, result.AccountIDs)
|
||||
} else if !reflect.DeepEqual(actPln.ActionTimings[0].Timing, result.ActionTimings[0].Timing) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", actPln.ActionTimings[0].Timing, result.ActionTimings[0].Timing)
|
||||
}
|
||||
case utils.Move:
|
||||
if err := actPlnMigrator.dmIN.DataManager().DataDB().SetActionPlan((*v1actPln)[0].Id, actPln, true, utils.NonTransactional); err != nil {
|
||||
t.Error("Error when setting ActionPlan ", err.Error())
|
||||
}
|
||||
currentVersion := engine.CurrentDataDBVersions()
|
||||
err := actPlnMigrator.dmOut.DataManager().DataDB().SetVersions(currentVersion, false)
|
||||
if err != nil {
|
||||
t.Error("Error when setting version for ActionPlan ", err.Error())
|
||||
}
|
||||
err, _ = actPlnMigrator.Migrate([]string{utils.MetaActionPlans})
|
||||
if err != nil {
|
||||
t.Error("Error when migrating ActionPlan ", err.Error())
|
||||
}
|
||||
result, err := actPlnMigrator.dmOut.DataManager().DataDB().GetActionPlan((*v1actPln)[0].Id, true, utils.NonTransactional)
|
||||
if err != nil {
|
||||
t.Error("Error when getting ActionPlan ", err.Error())
|
||||
}
|
||||
// compared fields, uuid is generated in ActionTiming
|
||||
if !reflect.DeepEqual(actPln.Id, result.Id) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", actPln.Id, result.Id)
|
||||
} else if !reflect.DeepEqual(actPln.AccountIDs, result.AccountIDs) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", actPln.AccountIDs, result.AccountIDs)
|
||||
} else if !reflect.DeepEqual(actPln.ActionTimings[0].Timing, result.ActionTimings[0].Timing) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", actPln.ActionTimings[0].Timing, result.ActionTimings[0].Timing)
|
||||
}
|
||||
}
|
||||
}
|
||||
248
migrator/action_trigger_it_test.go
Normal file
248
migrator/action_trigger_it_test.go
Normal file
@@ -0,0 +1,248 @@
|
||||
// +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 migrator
|
||||
|
||||
/*
|
||||
import (
|
||||
//"flag"
|
||||
"log"
|
||||
"path"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
actTrgPathIn string
|
||||
actTrgPathOut string
|
||||
actTrgCfgIn *config.CGRConfig
|
||||
actTrgCfgOut *config.CGRConfig
|
||||
actTrgMigrator *Migrator
|
||||
actActionTrigger string
|
||||
)
|
||||
|
||||
var sTestsActTrgIT = []func(t *testing.T){
|
||||
testActTrgITConnect,
|
||||
testActTrgITFlush,
|
||||
testActTrgITMigrateAndMove,
|
||||
}
|
||||
|
||||
func TestActionTriggerITRedis(t *testing.T) {
|
||||
var err error
|
||||
actTrgPathIn = path.Join(*dataDir, "conf", "samples", "tutmysql")
|
||||
actTrgCfgIn, err = config.NewCGRConfigFromFolder(actTrgPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actTrgCfgOut, err = config.NewCGRConfigFromFolder(actTrgPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actActionTrigger = utils.Migrate
|
||||
for _, stest := range sTestsActTrgIT {
|
||||
t.Run("TestActionTriggerITMigrateRedis", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestActionTriggerITMongo(t *testing.T) {
|
||||
var err error
|
||||
actTrgPathIn = path.Join(*dataDir, "conf", "samples", "tutmongo")
|
||||
actTrgCfgIn, err = config.NewCGRConfigFromFolder(actTrgPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actTrgCfgOut, err = config.NewCGRConfigFromFolder(actTrgPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actActionTrigger = utils.Migrate
|
||||
for _, stest := range sTestsActTrgIT {
|
||||
t.Run("TestActionTriggerITMigrateMongo", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestActionTriggerITMove(t *testing.T) {
|
||||
var err error
|
||||
actTrgPathIn = path.Join(*dataDir, "conf", "samples", "tutmongo")
|
||||
actTrgCfgIn, err = config.NewCGRConfigFromFolder(actTrgPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actTrgPathOut = path.Join(*dataDir, "conf", "samples", "tutmysql")
|
||||
actTrgCfgOut, err = config.NewCGRConfigFromFolder(actTrgPathOut)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actActionTrigger = utils.Move
|
||||
for _, stest := range sTestsActTrgIT {
|
||||
t.Run("TestActionTriggerITMove", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestActionTriggerITMoveEncoding(t *testing.T) {
|
||||
var err error
|
||||
actTrgPathIn = path.Join(*dataDir, "conf", "samples", "tutmongojson")
|
||||
actTrgCfgIn, err = config.NewCGRConfigFromFolder(actTrgPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actTrgPathOut = path.Join(*dataDir, "conf", "samples", "tutmongomsgpack")
|
||||
actTrgCfgOut, err = config.NewCGRConfigFromFolder(actTrgPathOut)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actActionTrigger = utils.Move
|
||||
for _, stest := range sTestsActTrgIT {
|
||||
t.Run("TestActionTriggerITMoveEncoding", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestActionTriggerITMoveEncoding2(t *testing.T) {
|
||||
var err error
|
||||
actTrgPathIn = path.Join(*dataDir, "conf", "samples", "tutmysqljson")
|
||||
actTrgCfgIn, err = config.NewCGRConfigFromFolder(actTrgPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actTrgPathOut = path.Join(*dataDir, "conf", "samples", "tutmysqlmsgpack")
|
||||
actTrgCfgOut, err = config.NewCGRConfigFromFolder(actTrgPathOut)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
actActionTrigger = utils.Move
|
||||
for _, stest := range sTestsActTrgIT {
|
||||
t.Run("TestActionTriggerITMoveEncoding2", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func testActTrgITConnect(t *testing.T) {
|
||||
dataDBIn, err := NewMigratorDataDB(actTrgCfgIn.DataDbType,
|
||||
actTrgCfgIn.DataDbHost, actTrgCfgIn.DataDbPort, actTrgCfgIn.DataDbName,
|
||||
actTrgCfgIn.DataDbUser, actTrgCfgIn.DataDbPass, actTrgCfgIn.DBDataEncoding,
|
||||
config.CgrConfig().CacheCfg(), *loadHistorySize)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
dataDBOut, err := NewMigratorDataDB(actTrgCfgOut.DataDbType,
|
||||
actTrgCfgOut.DataDbHost, actTrgCfgOut.DataDbPort, actTrgCfgOut.DataDbName,
|
||||
actTrgCfgOut.DataDbUser, actTrgCfgOut.DataDbPass, actTrgCfgOut.DBDataEncoding,
|
||||
config.CgrConfig().CacheCfg(), *loadHistorySize)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
actTrgMigrator, err = NewMigrator(dataDBIn, dataDBOut,
|
||||
nil, nil,
|
||||
false, false, false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testActTrgITFlush(t *testing.T) {
|
||||
actTrgMigrator.dmOut.DataManager().DataDB().Flush("")
|
||||
if err := engine.SetDBVersions(actTrgMigrator.dmOut.DataManager().DataDB()); err != nil {
|
||||
t.Error("Error ", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func testActTrgITMigrateAndMove(t *testing.T) {
|
||||
tim := time.Date(2012, time.February, 27, 23, 59, 59, 0, time.UTC)
|
||||
v1actTrg := &v1ActionTriggers{
|
||||
&v1ActionTrigger{
|
||||
Id: "Test",
|
||||
BalanceType: "*monetary",
|
||||
BalanceDirection: "*out",
|
||||
ThresholdType: "*max_balance",
|
||||
ThresholdValue: 2,
|
||||
ActionsId: "TEST_ACTIONS",
|
||||
Executed: true,
|
||||
BalanceExpirationDate: tim,
|
||||
},
|
||||
}
|
||||
actTrg := engine.ActionTriggers{
|
||||
&engine.ActionTrigger{
|
||||
ID: "Test",
|
||||
Balance: &engine.BalanceFilter{
|
||||
Timings: []*engine.RITiming{},
|
||||
ExpirationDate: utils.TimePointer(tim),
|
||||
Type: utils.StringPointer(utils.MONETARY),
|
||||
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
|
||||
},
|
||||
ExpirationDate: tim,
|
||||
LastExecutionTime: tim,
|
||||
ActivationDate: tim,
|
||||
ThresholdType: utils.TRIGGER_MAX_BALANCE,
|
||||
ThresholdValue: 2,
|
||||
ActionsID: "TEST_ACTIONS",
|
||||
Executed: true,
|
||||
},
|
||||
}
|
||||
|
||||
switch actActionTrigger {
|
||||
case utils.Migrate:
|
||||
err := actTrgMigrator.dmIN.setV2ActionTrigger(v1actTrg)
|
||||
if err != nil {
|
||||
t.Error("Error when setting v1 ActionTriggers ", err.Error())
|
||||
}
|
||||
currentVersion := engine.Versions{utils.StatS: 2, utils.Thresholds: 2, utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 1, utils.ActionPlans: 2, utils.SharedGroups: 2}
|
||||
err = actTrgMigrator.dmOut.DataManager().DataDB().SetVersions(currentVersion, false)
|
||||
if err != nil {
|
||||
t.Error("Error when setting version for ActionTriggers ", err.Error())
|
||||
}
|
||||
err, _ = actTrgMigrator.Migrate([]string{utils.MetaActionTriggers})
|
||||
if err != nil {
|
||||
t.Error("Error when migrating ActionTriggers ", err.Error())
|
||||
}
|
||||
result, err := actTrgMigrator.dmOut.DataManager().GetActionTriggers((*v1actTrg)[0].Id, false, utils.NonTransactional)
|
||||
if err != nil {
|
||||
t.Error("Error when getting ActionTriggers ", err.Error())
|
||||
}
|
||||
if !reflect.DeepEqual(actTrg, result) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", actTrg, result)
|
||||
}
|
||||
// utils.tojson si verificat
|
||||
case utils.Move:
|
||||
if err := actTrgMigrator.dmIN.DataManager().SetActionTriggers((*v1actTrg)[0].Id, actTrg, utils.NonTransactional); err != nil {
|
||||
t.Error("Error when setting ActionTriggers ", err.Error())
|
||||
}
|
||||
currentVersion := engine.CurrentDataDBVersions()
|
||||
err := actTrgMigrator.dmOut.DataManager().DataDB().SetVersions(currentVersion, false)
|
||||
if err != nil {
|
||||
t.Error("Error when setting version for ActionTriggers ", err.Error())
|
||||
}
|
||||
err, _ = actTrgMigrator.Migrate([]string{utils.MetaActionTriggers})
|
||||
if err != nil {
|
||||
t.Error("Error when migrating ActionTriggers ", err.Error())
|
||||
}
|
||||
result, err := actTrgMigrator.dmOut.DataManager().GetActionTriggers((*v1actTrg)[0].Id, false, utils.NonTransactional)
|
||||
if err != nil {
|
||||
t.Error("Error when getting ActionTriggers ", err.Error())
|
||||
}
|
||||
if !reflect.DeepEqual(actTrg, result) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", actTrg, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
File diff suppressed because it is too large
Load Diff
@@ -25,6 +25,8 @@ import (
|
||||
type MigratorStorDB interface {
|
||||
getV1CDR() (v1Cdr *v1Cdrs, err error)
|
||||
setV1CDR(v1Cdr *v1Cdrs) (err error)
|
||||
createV1SMCosts() (err error)
|
||||
renameV1SMCosts() (err error)
|
||||
getV2SMCost() (v2Cost *v2SessionsCost, err error)
|
||||
setV2SMCost(v2Cost *v2SessionsCost) (err error)
|
||||
remV2SMCost(v2Cost *v2SessionsCost) (err error)
|
||||
@@ -64,31 +64,12 @@ func NewMigratorStorDB(db_type, host, port, name, user, pass string,
|
||||
case utils.MYSQL:
|
||||
d = newMigratorSQL(storDb)
|
||||
db = d.(MigratorStorDB)
|
||||
case utils.POSTGRES:
|
||||
d = newMigratorSQL(storDb)
|
||||
db = d.(MigratorStorDB)
|
||||
default:
|
||||
err = errors.New(fmt.Sprintf("Unknown db '%s' valid options are '%s' or '%s'",
|
||||
db_type, utils.MONGO, utils.MYSQL))
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
func ConfigureV1StorDB(db_type, host, port, name, user, pass string) (db MigratorStorDB, err error) {
|
||||
var d MigratorStorDB
|
||||
switch db_type {
|
||||
case utils.MONGO:
|
||||
d, err = newv1MongoStorage(host, port, name, user, pass, utils.StorDB, nil)
|
||||
db = d.(MigratorStorDB)
|
||||
case utils.MYSQL:
|
||||
d, err = newSqlStorage(host, port, name, user, pass)
|
||||
db = d.(MigratorStorDB)
|
||||
default:
|
||||
err = errors.New(fmt.Sprintf("Unknown db '%s' valid options are '%s'",
|
||||
db_type, utils.MONGO))
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
*/
|
||||
@@ -19,7 +19,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
package migrator
|
||||
|
||||
import (
|
||||
//"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
@@ -63,30 +62,10 @@ func (m *Migrator) migrateSessionSCosts() (err error) {
|
||||
"version number is not defined for SessionsCosts model")
|
||||
}
|
||||
switch vrs[utils.SessionSCosts] {
|
||||
// case 0, 1:
|
||||
// var isPostGres bool
|
||||
// var storSQL *sql.DB
|
||||
// switch m.storDBType {
|
||||
// case utils.MYSQL:
|
||||
// isPostGres = false
|
||||
// storSQL = m.storDBOut.(*engine.SQLStorage).Db
|
||||
// case utils.POSTGRES:
|
||||
// isPostGres = true
|
||||
// storSQL = m.storDBOut.(*engine.SQLStorage).Db
|
||||
// default:
|
||||
// return utils.NewCGRError(utils.Migrator,
|
||||
// utils.MandatoryIEMissingCaps,
|
||||
// utils.UnsupportedDB,
|
||||
// fmt.Sprintf("unsupported database type: <%s>", m.storDBType))
|
||||
// }
|
||||
// qry := "RENAME TABLE sm_costs TO sessions_costs;"
|
||||
// if isPostGres {
|
||||
// qry = "ALTER TABLE sm_costs RENAME TO sessions_costs"
|
||||
// }
|
||||
// if _, err := storSQL.Exec(qry); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// fallthrough // incremental updates
|
||||
case 0, 1:
|
||||
if err := m.migrateV1SessionSCosts(); err != nil {
|
||||
return err
|
||||
}
|
||||
case 2:
|
||||
if err := m.migrateV2SessionSCosts(); err != nil {
|
||||
return err
|
||||
@@ -99,6 +78,22 @@ func (m *Migrator) migrateSessionSCosts() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Migrator) migrateV1SessionSCosts() (err error) {
|
||||
if err = m.storDBIn.renameV1SMCosts(); err != nil {
|
||||
return err
|
||||
}
|
||||
if m.dryRun != true {
|
||||
vrs := engine.Versions{utils.SessionSCosts: 2}
|
||||
if err = m.storDBOut.StorDB().SetVersions(vrs, false); err != nil {
|
||||
return utils.NewCGRError(utils.Migrator,
|
||||
utils.ServerErrorCaps,
|
||||
err.Error(),
|
||||
fmt.Sprintf("error: <%s> when updating SessionSCosts version into StorDB", err.Error()))
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (m *Migrator) migrateV2SessionSCosts() (err error) {
|
||||
var v2Cost *v2SessionsCost
|
||||
for {
|
||||
|
||||
@@ -20,9 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
package migrator
|
||||
|
||||
/*
|
||||
import (
|
||||
"log"
|
||||
"path"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -42,67 +40,46 @@ var (
|
||||
)
|
||||
|
||||
var sTestssCostIT = []func(t *testing.T){
|
||||
testSessionCostITConnect,
|
||||
testSessionCostITRename,
|
||||
testSessionCostITFlush,
|
||||
testSessionCostITMigrateAndMove,
|
||||
testSessionCostITMigrate,
|
||||
}
|
||||
|
||||
func TestSessionCostITMongoConnection(t *testing.T) {
|
||||
func TestSessionCostITMongo(t *testing.T) {
|
||||
var err error
|
||||
sCostPathIn = path.Join(*dataDir, "conf", "samples", "tutmongo")
|
||||
sCostCfgIn, err = config.NewCGRConfigFromFolder(sCostPathIn)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
storDBIn, err := engine.ConfigureStorDB(sCostCfgIn.StorDBType, sCostCfgIn.StorDBHost,
|
||||
sCostCfgIn.StorDBPort, sCostCfgIn.StorDBName,
|
||||
sCostCfgIn.StorDBUser, sCostCfgIn.StorDBPass,
|
||||
config.CgrConfig().StorDBMaxOpenConns,
|
||||
config.CgrConfig().StorDBMaxIdleConns,
|
||||
config.CgrConfig().StorDBConnMaxLifetime,
|
||||
config.CgrConfig().StorDBCDRSIndexes)
|
||||
sCostCfgOut, err = config.NewCGRConfigFromFolder(sCostPathIn)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
storDBOut, err := engine.ConfigureStorDB(sCostCfgIn.StorDBType,
|
||||
sCostCfgIn.StorDBHost, sCostCfgIn.StorDBPort, sCostCfgIn.StorDBName,
|
||||
sCostCfgIn.StorDBUser, sCostCfgIn.StorDBPass,
|
||||
config.CgrConfig().StorDBMaxOpenConns,
|
||||
config.CgrConfig().StorDBMaxIdleConns,
|
||||
config.CgrConfig().StorDBConnMaxLifetime,
|
||||
config.CgrConfig().StorDBCDRSIndexes)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
oldStorDB, err := ConfigureV1StorDB(sCostCfgIn.StorDBType,
|
||||
sCostCfgIn.StorDBHost, sCostCfgIn.StorDBPort, sCostCfgIn.StorDBName,
|
||||
sCostCfgIn.StorDBUser, sCostCfgIn.StorDBPass)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
sCostMigrator, err = NewMigrator(nil, nil, sCostCfgIn.DataDbType,
|
||||
sCostCfgIn.DBDataEncoding, storDBIn, storDBOut, sCostCfgIn.StorDBType, nil,
|
||||
sCostCfgIn.DataDbType, sCostCfgIn.DBDataEncoding, oldStorDB, sCostCfgIn.StorDBType,
|
||||
false, false, false, false, false)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSessionCostITMongo(t *testing.T) {
|
||||
for _, stest := range sTestssCostIT {
|
||||
t.Run("TestSessionSCostITMigrateMongo", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSessionCostITMySqlConnection(t *testing.T) {
|
||||
func TestSessionCostITMySql(t *testing.T) {
|
||||
var err error
|
||||
sCostPathIn = path.Join(*dataDir, "conf", "samples", "tutmysql")
|
||||
sCostCfgIn, err = config.NewCGRConfigFromFolder(sCostPathIn)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
storDBIn, err := engine.ConfigureStorDB(sCostCfgIn.StorDBType, sCostCfgIn.StorDBHost,
|
||||
sCostCfgOut, err = config.NewCGRConfigFromFolder(sCostPathIn)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
for _, stest := range sTestssCostIT {
|
||||
t.Run("TestSessionSCostITMigrateMySql", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func testSessionCostITConnect(t *testing.T) {
|
||||
storDBIn, err := NewMigratorStorDB(sCostCfgIn.StorDBType, sCostCfgIn.StorDBHost,
|
||||
sCostCfgIn.StorDBPort, sCostCfgIn.StorDBName,
|
||||
sCostCfgIn.StorDBUser, sCostCfgIn.StorDBPass,
|
||||
config.CgrConfig().StorDBMaxOpenConns,
|
||||
@@ -112,9 +89,9 @@ func TestSessionCostITMySqlConnection(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
storDBOut, err := engine.ConfigureStorDB(sCostCfgIn.StorDBType,
|
||||
sCostCfgIn.StorDBHost, sCostCfgIn.StorDBPort, sCostCfgIn.StorDBName,
|
||||
sCostCfgIn.StorDBUser, sCostCfgIn.StorDBPass,
|
||||
storDBOut, err := NewMigratorStorDB(sCostCfgOut.StorDBType,
|
||||
sCostCfgOut.StorDBHost, sCostCfgOut.StorDBPort, sCostCfgOut.StorDBName,
|
||||
sCostCfgOut.StorDBUser, sCostCfgOut.StorDBPass,
|
||||
config.CgrConfig().StorDBMaxOpenConns,
|
||||
config.CgrConfig().StorDBMaxIdleConns,
|
||||
config.CgrConfig().StorDBConnMaxLifetime,
|
||||
@@ -122,36 +99,51 @@ func TestSessionCostITMySqlConnection(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
oldStorDB, err := ConfigureV1StorDB(sCostCfgIn.StorDBType,
|
||||
sCostCfgIn.StorDBHost, sCostCfgIn.StorDBPort, sCostCfgIn.StorDBName,
|
||||
sCostCfgIn.StorDBUser, sCostCfgIn.StorDBPass)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
sCostMigrator, err = NewMigrator(nil, nil, sCostCfgIn.DataDbType,
|
||||
sCostCfgIn.DBDataEncoding, storDBIn, storDBOut, sCostCfgIn.StorDBType, nil,
|
||||
sCostCfgIn.DataDbType, sCostCfgIn.DBDataEncoding, oldStorDB, sCostCfgIn.StorDBType,
|
||||
false, false, false, false, false)
|
||||
sCostMigrator, err = NewMigrator(nil, nil,
|
||||
storDBIn, storDBOut,
|
||||
false, false, false)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSessionCostITMySql(t *testing.T) {
|
||||
for _, stest := range sTestssCostIT {
|
||||
t.Run("TestSessionSCostITMigrateMySql", stest)
|
||||
func testSessionCostITRename(t *testing.T) {
|
||||
var err error
|
||||
if err = sCostMigrator.storDBIn.createV1SMCosts(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
currentVersion := engine.Versions{
|
||||
utils.SessionSCosts: 1,
|
||||
}
|
||||
err = sCostMigrator.storDBOut.StorDB().SetVersions(currentVersion, false)
|
||||
if err != nil {
|
||||
t.Error("Error when setting version for SessionsCosts ", err.Error())
|
||||
}
|
||||
if vrs, err := sCostMigrator.storDBOut.StorDB().GetVersions(""); err != nil {
|
||||
t.Error(err)
|
||||
} else if vrs[utils.SessionSCosts] != 1 {
|
||||
t.Errorf("Unexpected version returned: %d", vrs[utils.SessionSCosts])
|
||||
}
|
||||
err, _ = sCostMigrator.Migrate([]string{utils.MetaSessionsCosts})
|
||||
if err != nil {
|
||||
t.Error("Error when migrating SessionsCosts ", err.Error())
|
||||
}
|
||||
if vrs, err := sCostMigrator.storDBOut.StorDB().GetVersions(""); err != nil {
|
||||
t.Error(err)
|
||||
} else if vrs[utils.SessionSCosts] != 2 {
|
||||
t.Errorf("Unexpected version returned: %d", vrs[utils.SessionSCosts])
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func testSessionCostITFlush(t *testing.T) {
|
||||
if err := sCostMigrator.storDBOut.Flush(
|
||||
if err := sCostMigrator.storDBOut.StorDB().Flush(
|
||||
path.Join(sCostCfgIn.DataFolderPath, "storage", sCostCfgIn.StorDBType)); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testSessionCostITMigrateAndMove(t *testing.T) {
|
||||
func testSessionCostITMigrate(t *testing.T) {
|
||||
cc := &engine.CallCost{
|
||||
Direction: utils.OUT,
|
||||
Cost: 1.23,
|
||||
@@ -187,17 +179,17 @@ func testSessionCostITMigrateAndMove(t *testing.T) {
|
||||
CostDetails: cc,
|
||||
}
|
||||
var err error
|
||||
if err = sCostMigrator.oldStorDB.setSMCost(v2Cost); err != nil {
|
||||
if err = sCostMigrator.storDBIn.setV2SMCost(v2Cost); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
currentVersion := engine.Versions{
|
||||
utils.SessionSCosts: 2,
|
||||
}
|
||||
err = sCostMigrator.storDBOut.SetVersions(currentVersion, false)
|
||||
err = sCostMigrator.storDBOut.StorDB().SetVersions(currentVersion, false)
|
||||
if err != nil {
|
||||
t.Error("Error when setting version for SessionsCosts ", err.Error())
|
||||
}
|
||||
if vrs, err := sCostMigrator.storDBOut.GetVersions(""); err != nil {
|
||||
if vrs, err := sCostMigrator.storDBOut.StorDB().GetVersions(""); err != nil {
|
||||
t.Error(err)
|
||||
} else if vrs[utils.SessionSCosts] != 2 {
|
||||
t.Errorf("Unexpected version returned: %d", vrs[utils.SessionSCosts])
|
||||
@@ -206,15 +198,14 @@ func testSessionCostITMigrateAndMove(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error("Error when migrating SessionsCosts ", err.Error())
|
||||
}
|
||||
if rcvCosts, err := sCostMigrator.storDBOut.GetSMCosts("", utils.DEFAULT_RUNID, "", ""); err != nil {
|
||||
if rcvCosts, err := sCostMigrator.storDBOut.StorDB().GetSMCosts("", utils.DEFAULT_RUNID, "", ""); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(rcvCosts) != 1 {
|
||||
t.Errorf("Unexpected number of SessionsCosts returned: %d", len(rcvCosts))
|
||||
}
|
||||
if vrs, err := sCostMigrator.storDBOut.GetVersions(""); err != nil {
|
||||
if vrs, err := sCostMigrator.storDBOut.StorDB().GetVersions(""); err != nil {
|
||||
t.Error(err)
|
||||
} else if vrs[utils.SessionSCosts] != 3 {
|
||||
t.Errorf("Unexpected version returned: %d", vrs[utils.SessionSCosts])
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
226
migrator/sharedgroup_it_test.go
Normal file
226
migrator/sharedgroup_it_test.go
Normal file
@@ -0,0 +1,226 @@
|
||||
// +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 migrator
|
||||
|
||||
import (
|
||||
"log"
|
||||
"path"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
shrGrpPathIn string
|
||||
shrGrpPathOut string
|
||||
shrGrpCfgIn *config.CGRConfig
|
||||
shrGrpCfgOut *config.CGRConfig
|
||||
shrGrpMigrator *Migrator
|
||||
shrSharedGroup string
|
||||
)
|
||||
|
||||
var sTestsShrGrpIT = []func(t *testing.T){
|
||||
testShrGrpITConnect,
|
||||
testShrGrpITFlush,
|
||||
testShrGrpITMigrateAndMove,
|
||||
}
|
||||
|
||||
func TestSharedGroupITRedis(t *testing.T) {
|
||||
var err error
|
||||
shrGrpPathIn = path.Join(*dataDir, "conf", "samples", "tutmysql")
|
||||
shrGrpCfgIn, err = config.NewCGRConfigFromFolder(shrGrpPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
shrGrpCfgOut, err = config.NewCGRConfigFromFolder(shrGrpPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
shrSharedGroup = utils.Migrate
|
||||
for _, stest := range sTestsShrGrpIT {
|
||||
t.Run("TestSharedGroupITMigrateRedis", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSharedGroupITMongo(t *testing.T) {
|
||||
var err error
|
||||
shrGrpPathIn = path.Join(*dataDir, "conf", "samples", "tutmongo")
|
||||
shrGrpCfgIn, err = config.NewCGRConfigFromFolder(shrGrpPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
shrGrpCfgOut, err = config.NewCGRConfigFromFolder(shrGrpPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
shrSharedGroup = utils.Migrate
|
||||
for _, stest := range sTestsShrGrpIT {
|
||||
t.Run("TestSharedGroupITMigrateMongo", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSharedGroupITMove(t *testing.T) {
|
||||
var err error
|
||||
shrGrpPathIn = path.Join(*dataDir, "conf", "samples", "tutmongo")
|
||||
shrGrpCfgIn, err = config.NewCGRConfigFromFolder(shrGrpPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
shrGrpPathOut = path.Join(*dataDir, "conf", "samples", "tutmysql")
|
||||
shrGrpCfgOut, err = config.NewCGRConfigFromFolder(shrGrpPathOut)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
shrSharedGroup = utils.Move
|
||||
for _, stest := range sTestsShrGrpIT {
|
||||
t.Run("TestSharedGroupITMove", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSharedGroupITMoveEncoding(t *testing.T) {
|
||||
var err error
|
||||
shrGrpPathIn = path.Join(*dataDir, "conf", "samples", "tutmongojson")
|
||||
shrGrpCfgIn, err = config.NewCGRConfigFromFolder(shrGrpPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
shrGrpPathOut = path.Join(*dataDir, "conf", "samples", "tutmongomsgpack")
|
||||
shrGrpCfgOut, err = config.NewCGRConfigFromFolder(shrGrpPathOut)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
shrSharedGroup = utils.Move
|
||||
for _, stest := range sTestsShrGrpIT {
|
||||
t.Run("TestSharedGroupITMoveEncoding", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSharedGroupITMoveEncoding2(t *testing.T) {
|
||||
var err error
|
||||
shrGrpPathIn = path.Join(*dataDir, "conf", "samples", "tutmysqljson")
|
||||
shrGrpCfgIn, err = config.NewCGRConfigFromFolder(shrGrpPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
shrGrpPathOut = path.Join(*dataDir, "conf", "samples", "tutmysqlmsgpack")
|
||||
shrGrpCfgOut, err = config.NewCGRConfigFromFolder(shrGrpPathOut)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
shrSharedGroup = utils.Move
|
||||
for _, stest := range sTestsShrGrpIT {
|
||||
t.Run("TestSharedGroupITMoveEncoding2", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func testShrGrpITConnect(t *testing.T) {
|
||||
dataDBIn, err := NewMigratorDataDB(shrGrpCfgIn.DataDbType,
|
||||
shrGrpCfgIn.DataDbHost, shrGrpCfgIn.DataDbPort, shrGrpCfgIn.DataDbName,
|
||||
shrGrpCfgIn.DataDbUser, shrGrpCfgIn.DataDbPass, shrGrpCfgIn.DBDataEncoding,
|
||||
config.CgrConfig().CacheCfg(), *loadHistorySize)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
dataDBOut, err := NewMigratorDataDB(shrGrpCfgOut.DataDbType,
|
||||
shrGrpCfgOut.DataDbHost, shrGrpCfgOut.DataDbPort, shrGrpCfgOut.DataDbName,
|
||||
shrGrpCfgOut.DataDbUser, shrGrpCfgOut.DataDbPass, shrGrpCfgOut.DBDataEncoding,
|
||||
config.CgrConfig().CacheCfg(), *loadHistorySize)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
shrGrpMigrator, err = NewMigrator(dataDBIn, dataDBOut,
|
||||
nil, nil,
|
||||
false, false, false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testShrGrpITFlush(t *testing.T) {
|
||||
shrGrpMigrator.dmOut.DataManager().DataDB().Flush("")
|
||||
if err := engine.SetDBVersions(shrGrpMigrator.dmOut.DataManager().DataDB()); err != nil {
|
||||
t.Error("Error ", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func testShrGrpITMigrateAndMove(t *testing.T) {
|
||||
v1shrGrp := &v1SharedGroup{
|
||||
Id: "Test",
|
||||
AccountParameters: map[string]*engine.SharingParameters{
|
||||
"test": &engine.SharingParameters{Strategy: "*highest"},
|
||||
},
|
||||
MemberIds: []string{"1", "2", "3"},
|
||||
}
|
||||
shrGrp := &engine.SharedGroup{
|
||||
Id: "Test",
|
||||
AccountParameters: map[string]*engine.SharingParameters{
|
||||
"test": &engine.SharingParameters{Strategy: "*highest"},
|
||||
},
|
||||
MemberIds: utils.NewStringMap("1", "2", "3"),
|
||||
}
|
||||
|
||||
switch shrSharedGroup {
|
||||
case utils.Migrate:
|
||||
err := shrGrpMigrator.dmIN.setV1SharedGroup(v1shrGrp)
|
||||
if err != nil {
|
||||
t.Error("Error when setting v1 SharedGroup ", err.Error())
|
||||
}
|
||||
currentVersion := engine.Versions{utils.StatS: 2, utils.Thresholds: 2, utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 1}
|
||||
err = shrGrpMigrator.dmOut.DataManager().DataDB().SetVersions(currentVersion, false)
|
||||
if err != nil {
|
||||
t.Error("Error when setting version for SharedGroup ", err.Error())
|
||||
}
|
||||
err, _ = shrGrpMigrator.Migrate([]string{utils.MetaSharedGroups})
|
||||
if err != nil {
|
||||
t.Error("Error when migrating SharedGroup ", err.Error())
|
||||
}
|
||||
result, err := shrGrpMigrator.dmOut.DataManager().GetSharedGroup(v1shrGrp.Id, true, utils.NonTransactional)
|
||||
if err != nil {
|
||||
t.Error("Error when getting SharedGroup ", err.Error())
|
||||
}
|
||||
if !reflect.DeepEqual(shrGrp, result) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", shrGrp, result)
|
||||
}
|
||||
case utils.Move:
|
||||
if err := shrGrpMigrator.dmIN.DataManager().SetSharedGroup(shrGrp, utils.NonTransactional); err != nil {
|
||||
t.Error("Error when setting SharedGroup ", err.Error())
|
||||
}
|
||||
currentVersion := engine.CurrentDataDBVersions()
|
||||
err := shrGrpMigrator.dmOut.DataManager().DataDB().SetVersions(currentVersion, false)
|
||||
if err != nil {
|
||||
t.Error("Error when setting version for SharedGroup ", err.Error())
|
||||
}
|
||||
err, _ = shrGrpMigrator.Migrate([]string{utils.MetaSharedGroups})
|
||||
if err != nil {
|
||||
t.Error("Error when migrating SharedGroup ", err.Error())
|
||||
}
|
||||
result, err := shrGrpMigrator.dmOut.DataManager().GetSharedGroup(v1shrGrp.Id, true, utils.NonTransactional)
|
||||
if err != nil {
|
||||
t.Error("Error when getting SharedGroup ", err.Error())
|
||||
}
|
||||
if !reflect.DeepEqual(shrGrp, result) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", shrGrp, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
package migrator
|
||||
|
||||
/*
|
||||
import (
|
||||
"log"
|
||||
"path"
|
||||
@@ -102,38 +101,31 @@ func TestStatsQueueITMove(t *testing.T) {
|
||||
}
|
||||
|
||||
func testStsITConnect(t *testing.T) {
|
||||
dataDBIn, err := engine.ConfigureDataStorage(stsCfgIn.DataDbType,
|
||||
dataDBIn, err := NewMigratorDataDB(stsCfgIn.DataDbType,
|
||||
stsCfgIn.DataDbHost, stsCfgIn.DataDbPort, stsCfgIn.DataDbName,
|
||||
stsCfgIn.DataDbUser, stsCfgIn.DataDbPass, stsCfgIn.DBDataEncoding,
|
||||
config.CgrConfig().CacheCfg(), *loadHistorySize)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
dataDBOut, err := engine.ConfigureDataStorage(stsCfgOut.DataDbType,
|
||||
dataDBOut, err := NewMigratorDataDB(stsCfgOut.DataDbType,
|
||||
stsCfgOut.DataDbHost, stsCfgOut.DataDbPort, stsCfgOut.DataDbName,
|
||||
stsCfgOut.DataDbUser, stsCfgOut.DataDbPass, stsCfgOut.DBDataEncoding,
|
||||
config.CgrConfig().CacheCfg(), *loadHistorySize)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
oldDataDB, err := ConfigureV1DataStorage(stsCfgIn.DataDbType,
|
||||
stsCfgIn.DataDbHost, stsCfgIn.DataDbPort, stsCfgIn.DataDbName,
|
||||
stsCfgIn.DataDbUser, stsCfgIn.DataDbPass, stsCfgIn.DBDataEncoding)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
stsMigrator, err = NewMigrator(dataDBIn, dataDBOut, stsCfgIn.DataDbType,
|
||||
stsCfgIn.DBDataEncoding, nil, nil, stsCfgIn.StorDBType, oldDataDB,
|
||||
stsCfgIn.DataDbType, stsCfgIn.DBDataEncoding, nil, stsCfgIn.StorDBType,
|
||||
false, false, false, false, false)
|
||||
stsMigrator, err = NewMigrator(dataDBIn, dataDBOut,
|
||||
nil, nil,
|
||||
false, false, false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testStsITFlush(t *testing.T) {
|
||||
stsMigrator.dmOut.DataDB().Flush("")
|
||||
if err := engine.SetDBVersions(stsMigrator.dmOut.DataDB()); err != nil {
|
||||
stsMigrator.dmOut.DataManager().DataDB().Flush("")
|
||||
if err := engine.SetDBVersions(stsMigrator.dmOut.DataManager().DataDB()); err != nil {
|
||||
t.Error("Error ", err.Error())
|
||||
}
|
||||
}
|
||||
@@ -237,7 +229,7 @@ func testStsITMigrateAndMove(t *testing.T) {
|
||||
}
|
||||
switch stsAction {
|
||||
case utils.Migrate:
|
||||
err := stsMigrator.oldDataDB.setV1Stats(v1Sts)
|
||||
err := stsMigrator.dmIN.setV1Stats(v1Sts)
|
||||
if err != nil {
|
||||
t.Error("Error when setting v1Stat ", err.Error())
|
||||
}
|
||||
@@ -249,7 +241,7 @@ func testStsITMigrateAndMove(t *testing.T) {
|
||||
utils.ActionTriggers: 2,
|
||||
utils.ActionPlans: 2,
|
||||
utils.SharedGroups: 2}
|
||||
err = stsMigrator.dmOut.DataDB().SetVersions(currentVersion, false)
|
||||
err = stsMigrator.dmOut.DataManager().DataDB().SetVersions(currentVersion, false)
|
||||
if err != nil {
|
||||
t.Error("Error when setting version for stats ", err.Error())
|
||||
}
|
||||
@@ -258,8 +250,7 @@ func testStsITMigrateAndMove(t *testing.T) {
|
||||
t.Error("Error when migrating Stats ", err.Error())
|
||||
}
|
||||
|
||||
result, err := stsMigrator.dmOut.GetStatQueueProfile("cgrates.org",
|
||||
v1Sts.Id, true, utils.NonTransactional)
|
||||
result, err := stsMigrator.dmOut.DataManager().DataDB().GetStatQueueProfileDrv("cgrates.org", v1Sts.Id)
|
||||
if err != nil {
|
||||
t.Error("Error when getting Stats ", err.Error())
|
||||
}
|
||||
@@ -267,8 +258,7 @@ func testStsITMigrateAndMove(t *testing.T) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", sqp, result)
|
||||
}
|
||||
|
||||
result1, err := stsMigrator.dmOut.GetFilter("cgrates.org",
|
||||
v1Sts.Id, true, utils.NonTransactional)
|
||||
result1, err := stsMigrator.dmOut.DataManager().DataDB().GetFilterDrv("cgrates.org", v1Sts.Id)
|
||||
if err != nil {
|
||||
t.Error("Error when getting Stats ", err.Error())
|
||||
}
|
||||
@@ -278,7 +268,7 @@ func testStsITMigrateAndMove(t *testing.T) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", len(filter.Rules), len(result1.Rules))
|
||||
}
|
||||
|
||||
result2, err := stsMigrator.dmOut.GetStatQueue("cgrates.org", sq.ID, true, utils.NonTransactional)
|
||||
result2, err := stsMigrator.dmOut.DataManager().GetStatQueue("cgrates.org", sq.ID, true, utils.NonTransactional)
|
||||
if err != nil {
|
||||
t.Error("Error when getting Stats ", err.Error())
|
||||
}
|
||||
@@ -287,14 +277,14 @@ func testStsITMigrateAndMove(t *testing.T) {
|
||||
}
|
||||
|
||||
case utils.Move:
|
||||
if err := stsMigrator.dmIN.SetStatQueueProfile(sqp, true); err != nil {
|
||||
if err := stsMigrator.dmIN.DataManager().DataDB().SetStatQueueProfileDrv(sqp); err != nil {
|
||||
t.Error("Error when setting Stats ", err.Error())
|
||||
}
|
||||
if err := stsMigrator.dmIN.SetStatQueue(sq); err != nil {
|
||||
if err := stsMigrator.dmIN.DataManager().SetStatQueue(sq); err != nil {
|
||||
t.Error("Error when setting Stats ", err.Error())
|
||||
}
|
||||
currentVersion := engine.CurrentDataDBVersions()
|
||||
err := stsMigrator.dmOut.DataDB().SetVersions(currentVersion, false)
|
||||
err := stsMigrator.dmOut.DataManager().DataDB().SetVersions(currentVersion, false)
|
||||
if err != nil {
|
||||
t.Error("Error when setting version for stats ", err.Error())
|
||||
}
|
||||
@@ -302,11 +292,11 @@ func testStsITMigrateAndMove(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error("Error when migrating Stats ", err.Error())
|
||||
}
|
||||
result, err := stsMigrator.dmOut.GetStatQueueProfile(sqp.Tenant, sqp.ID, true, utils.NonTransactional)
|
||||
result, err := stsMigrator.dmOut.DataManager().DataDB().GetStatQueueProfileDrv(sqp.Tenant, sqp.ID)
|
||||
if err != nil {
|
||||
t.Error("Error when getting Stats ", err.Error())
|
||||
}
|
||||
result1, err := stsMigrator.dmOut.GetStatQueue(sq.Tenant, sq.ID, true, utils.NonTransactional)
|
||||
result1, err := stsMigrator.dmOut.DataManager().GetStatQueue(sq.Tenant, sq.ID, true, utils.NonTransactional)
|
||||
if err != nil {
|
||||
t.Error("Error when getting Stats ", err.Error())
|
||||
}
|
||||
@@ -319,4 +309,3 @@ func testStsITMigrateAndMove(t *testing.T) {
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"github.com/cgrates/mgo"
|
||||
"github.com/cgrates/mgo/bson"
|
||||
)
|
||||
|
||||
func newMongoStorDBMigrator(stor engine.StorDB) (mgoMig *mongoStorDBMigrator) {
|
||||
@@ -67,6 +68,23 @@ func (v1ms *mongoStorDBMigrator) setV1CDR(v1Cdr *v1Cdrs) (err error) {
|
||||
}
|
||||
|
||||
//SMCost methods
|
||||
//rename
|
||||
func (v1ms *mongoStorDBMigrator) renameV1SMCosts() (err error) {
|
||||
if err = v1ms.mgoDB.DB().C(utils.OldSMCosts).DropCollection(); err != nil {
|
||||
return err
|
||||
}
|
||||
result := make(map[string]string)
|
||||
return v1ms.mgoDB.DB().Run(bson.D{{"create", utils.SessionsCostsTBL}}, result)
|
||||
}
|
||||
|
||||
func (v1ms *mongoStorDBMigrator) createV1SMCosts() (err error) {
|
||||
err = v1ms.mgoDB.DB().C(utils.OldSMCosts).DropCollection()
|
||||
err = v1ms.mgoDB.DB().C(utils.SessionsCostsTBL).DropCollection()
|
||||
result := make(map[string]string)
|
||||
return v1ms.mgoDB.DB().Run(bson.D{{"create", utils.OldSMCosts},
|
||||
{"size", 1024}}, result)
|
||||
}
|
||||
|
||||
//get
|
||||
func (v1ms *mongoStorDBMigrator) getV2SMCost() (v2Cost *v2SessionsCost, err error) {
|
||||
if v1ms.qryIter == nil {
|
||||
@@ -20,6 +20,7 @@ package migrator
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
@@ -75,6 +76,48 @@ func (mgSQL *migratorSQL) setV1CDR(v1Cdr *v1Cdrs) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (mgSQL *migratorSQL) renameV1SMCosts() (err error) {
|
||||
qry := "RENAME TABLE sm_costs TO sessions_costs;"
|
||||
if mgSQL.StorDB().GetStorageType() == utils.POSTGRES {
|
||||
qry = "ALTER TABLE sm_costs RENAME TO sessions_costs"
|
||||
}
|
||||
if _, err := mgSQL.sqlStorage.Db.Exec(qry); err != nil {
|
||||
return err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (mgSQL *migratorSQL) createV1SMCosts() (err error) {
|
||||
qry := fmt.Sprint("CREATE TABLE sm_costs ( id int(11) NOT NULL AUTO_INCREMENT, cgrid varchar(40) NOT NULL, run_id varchar(64) NOT NULL, origin_host varchar(64) NOT NULL, origin_id varchar(128) NOT NULL, cost_source varchar(64) NOT NULL, `usage` BIGINT NOT NULL, cost_details MEDIUMTEXT, created_at TIMESTAMP NULL,deleted_at TIMESTAMP NULL, PRIMARY KEY (`id`),UNIQUE KEY costid (cgrid, run_id),KEY origin_idx (origin_host, origin_id),KEY run_origin_idx (run_id, origin_id),KEY deleted_at_idx (deleted_at));")
|
||||
if mgSQL.StorDB().GetStorageType() == utils.POSTGRES {
|
||||
qry = `
|
||||
CREATE TABLE sm_costs (
|
||||
id SERIAL PRIMARY KEY,
|
||||
cgrid VARCHAR(40) NOT NULL,
|
||||
run_id VARCHAR(64) NOT NULL,
|
||||
origin_host VARCHAR(64) NOT NULL,
|
||||
origin_id VARCHAR(128) NOT NULL,
|
||||
cost_source VARCHAR(64) NOT NULL,
|
||||
usage BIGINT NOT NULL,
|
||||
cost_details jsonb,
|
||||
created_at TIMESTAMP WITH TIME ZONE,
|
||||
deleted_at TIMESTAMP WITH TIME ZONE NULL,
|
||||
UNIQUE (cgrid, run_id)
|
||||
);
|
||||
`
|
||||
}
|
||||
if _, err := mgSQL.sqlStorage.Db.Exec("DROP TABLE IF EXISTS sessions_costs;"); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := mgSQL.sqlStorage.Db.Exec("DROP TABLE IF EXISTS sm_costs;"); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := mgSQL.sqlStorage.Db.Exec(qry); err != nil {
|
||||
return err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (mgSQL *migratorSQL) getV2SMCost() (v2Cost *v2SessionsCost, err error) {
|
||||
if mgSQL.rowIter == nil {
|
||||
mgSQL.rowIter, err = mgSQL.sqlStorage.Db.Query("SELECT * FROM sessions_costs")
|
||||
265
migrator/thresholds_it_test.go
Normal file
265
migrator/thresholds_it_test.go
Normal file
@@ -0,0 +1,265 @@
|
||||
// +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 migrator
|
||||
|
||||
import (
|
||||
"log"
|
||||
"path"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
trsPathIn string
|
||||
trsPathOut string
|
||||
trsCfgIn *config.CGRConfig
|
||||
trsCfgOut *config.CGRConfig
|
||||
trsMigrator *Migrator
|
||||
trsThresholds string
|
||||
)
|
||||
|
||||
var sTestsTrsIT = []func(t *testing.T){
|
||||
testTrsITConnect,
|
||||
testTrsITFlush,
|
||||
testTrsITMigrateAndMove,
|
||||
}
|
||||
|
||||
func TestThresholdsITRedis(t *testing.T) {
|
||||
var err error
|
||||
trsPathIn = path.Join(*dataDir, "conf", "samples", "tutmysql")
|
||||
trsCfgIn, err = config.NewCGRConfigFromFolder(trsPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
trsCfgOut, err = config.NewCGRConfigFromFolder(trsPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
trsThresholds = utils.Migrate
|
||||
for _, stest := range sTestsTrsIT {
|
||||
t.Run("TestThresholdsITMigrateRedis", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestThresholdsITMongo(t *testing.T) {
|
||||
var err error
|
||||
trsPathIn = path.Join(*dataDir, "conf", "samples", "tutmongo")
|
||||
trsCfgIn, err = config.NewCGRConfigFromFolder(trsPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
trsCfgOut, err = config.NewCGRConfigFromFolder(trsPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
trsThresholds = utils.Migrate
|
||||
for _, stest := range sTestsTrsIT {
|
||||
t.Run("TestThresholdsITMigrateMongo", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestThresholdsITMove(t *testing.T) {
|
||||
var err error
|
||||
trsPathIn = path.Join(*dataDir, "conf", "samples", "tutmongo")
|
||||
trsCfgIn, err = config.NewCGRConfigFromFolder(trsPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
trsPathOut = path.Join(*dataDir, "conf", "samples", "tutmysql")
|
||||
trsCfgOut, err = config.NewCGRConfigFromFolder(trsPathOut)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
trsThresholds = utils.Move
|
||||
for _, stest := range sTestsTrsIT {
|
||||
t.Run("TestThresholdsITMove", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestThresholdsITMoveEncoding(t *testing.T) {
|
||||
var err error
|
||||
trsPathIn = path.Join(*dataDir, "conf", "samples", "tutmongojson")
|
||||
trsCfgIn, err = config.NewCGRConfigFromFolder(trsPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
trsPathOut = path.Join(*dataDir, "conf", "samples", "tutmongomsgpack")
|
||||
trsCfgOut, err = config.NewCGRConfigFromFolder(trsPathOut)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
trsThresholds = utils.Move
|
||||
for _, stest := range sTestsTrsIT {
|
||||
t.Run("TestThresholdsITMoveEncoding", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func TestThresholdsITMoveEncoding2(t *testing.T) {
|
||||
var err error
|
||||
trsPathIn = path.Join(*dataDir, "conf", "samples", "tutmysqljson")
|
||||
trsCfgIn, err = config.NewCGRConfigFromFolder(trsPathIn)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
trsPathOut = path.Join(*dataDir, "conf", "samples", "tutmysqlmsgpack")
|
||||
trsCfgOut, err = config.NewCGRConfigFromFolder(trsPathOut)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
trsThresholds = utils.Move
|
||||
for _, stest := range sTestsTrsIT {
|
||||
t.Run("TestThresholdsITMoveEncoding2", stest)
|
||||
}
|
||||
}
|
||||
|
||||
func testTrsITConnect(t *testing.T) {
|
||||
dataDBIn, err := NewMigratorDataDB(trsCfgIn.DataDbType,
|
||||
trsCfgIn.DataDbHost, trsCfgIn.DataDbPort, trsCfgIn.DataDbName,
|
||||
trsCfgIn.DataDbUser, trsCfgIn.DataDbPass, trsCfgIn.DBDataEncoding,
|
||||
config.CgrConfig().CacheCfg(), *loadHistorySize)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
dataDBOut, err := NewMigratorDataDB(trsCfgOut.DataDbType,
|
||||
trsCfgOut.DataDbHost, trsCfgOut.DataDbPort, trsCfgOut.DataDbName,
|
||||
trsCfgOut.DataDbUser, trsCfgOut.DataDbPass, trsCfgOut.DBDataEncoding,
|
||||
config.CgrConfig().CacheCfg(), *loadHistorySize)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
trsMigrator, err = NewMigrator(dataDBIn, dataDBOut,
|
||||
nil, nil,
|
||||
false, false, false)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func testTrsITFlush(t *testing.T) {
|
||||
trsMigrator.dmOut.DataManager().DataDB().Flush("")
|
||||
if err := engine.SetDBVersions(trsMigrator.dmOut.DataManager().DataDB()); err != nil {
|
||||
t.Error("Error ", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func testTrsITMigrateAndMove(t *testing.T) {
|
||||
tim := time.Date(2012, time.February, 27, 23, 59, 59, 0, time.UTC)
|
||||
var filters []*engine.FilterRule
|
||||
v1trs := &v2ActionTrigger{
|
||||
ID: "test2", // original csv tag
|
||||
UniqueID: "testUUID", // individual id
|
||||
ThresholdType: "*min_event_counter", //*min_event_counter, *max_event_counter, *min_balance_counter, *max_balance_counter, *min_balance, *max_balance, *balance_expired
|
||||
ThresholdValue: 5.32,
|
||||
Recurrent: false, // reset excuted flag each run
|
||||
MinSleep: time.Duration(5) * time.Second, // Minimum duration between two executions in case of recurrent triggers
|
||||
ExpirationDate: tim,
|
||||
ActivationDate: tim,
|
||||
Balance: &engine.BalanceFilter{
|
||||
ID: utils.StringPointer("TESTZ"),
|
||||
Timings: []*engine.RITiming{},
|
||||
ExpirationDate: utils.TimePointer(tim),
|
||||
Type: utils.StringPointer(utils.MONETARY),
|
||||
Directions: utils.StringMapPointer(utils.NewStringMap(utils.OUT)),
|
||||
},
|
||||
Weight: 0,
|
||||
ActionsID: "Action1",
|
||||
MinQueuedItems: 10, // Trigger actions only if this number is hit (stats only)
|
||||
Executed: false,
|
||||
LastExecutionTime: time.Now(),
|
||||
}
|
||||
x, err := engine.NewFilterRule(engine.MetaRSR, "Directions", v1trs.Balance.Directions.Slice())
|
||||
if err != nil {
|
||||
t.Error("Error when creating new NewFilterRule", err.Error())
|
||||
}
|
||||
filters = append(filters, x)
|
||||
|
||||
tresProf := &engine.ThresholdProfile{
|
||||
ID: v1trs.ID,
|
||||
Tenant: config.CgrConfig().DefaultTenant,
|
||||
Weight: v1trs.Weight,
|
||||
ActivationInterval: &utils.ActivationInterval{v1trs.ExpirationDate, v1trs.ActivationDate},
|
||||
MinSleep: v1trs.MinSleep,
|
||||
}
|
||||
switch trsThresholds {
|
||||
case utils.Migrate:
|
||||
err := trsMigrator.dmIN.setV2ActionTrigger(v1trs)
|
||||
if err != nil {
|
||||
t.Error("Error when setting v1 Thresholds ", err.Error())
|
||||
}
|
||||
currentVersion := engine.Versions{utils.StatS: 2, utils.Thresholds: 1, utils.Accounts: 2, utils.Actions: 2, utils.ActionTriggers: 2, utils.ActionPlans: 2, utils.SharedGroups: 2}
|
||||
err = trsMigrator.dmOut.DataManager().DataDB().SetVersions(currentVersion, false)
|
||||
if err != nil {
|
||||
t.Error("Error when setting version for Thresholds ", err.Error())
|
||||
}
|
||||
err, _ = trsMigrator.Migrate([]string{utils.MetaThresholds})
|
||||
if err != nil {
|
||||
t.Error("Error when migrating Thresholds ", err.Error())
|
||||
}
|
||||
result, err := trsMigrator.dmOut.DataManager().GetThresholdProfile(tresProf.Tenant, tresProf.ID, false, utils.NonTransactional)
|
||||
if err != nil {
|
||||
t.Error("Error when getting Thresholds ", err.Error())
|
||||
}
|
||||
if !reflect.DeepEqual(tresProf.ID, result.ID) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", tresProf.ID, result.ID)
|
||||
} else if !reflect.DeepEqual(tresProf.Tenant, result.Tenant) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", tresProf.Tenant, result.Tenant)
|
||||
} else if !reflect.DeepEqual(tresProf.Weight, result.Weight) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", tresProf.Weight, result.Weight)
|
||||
} else if !reflect.DeepEqual(tresProf.ActivationInterval, result.ActivationInterval) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", tresProf.ActivationInterval, result.ActivationInterval)
|
||||
} else if !reflect.DeepEqual(tresProf.MinSleep, result.MinSleep) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", tresProf.MinSleep, result.MinSleep)
|
||||
}
|
||||
case utils.Move:
|
||||
if err := trsMigrator.dmIN.DataManager().SetThresholdProfile(tresProf, false); err != nil {
|
||||
t.Error("Error when setting Thresholds ", err.Error())
|
||||
}
|
||||
currentVersion := engine.CurrentDataDBVersions()
|
||||
err := trsMigrator.dmOut.DataManager().DataDB().SetVersions(currentVersion, false)
|
||||
if err != nil {
|
||||
t.Error("Error when setting version for Thresholds ", err.Error())
|
||||
}
|
||||
err, _ = trsMigrator.Migrate([]string{utils.MetaSharedGroups})
|
||||
if err != nil {
|
||||
t.Error("Error when migrating Thresholds ", err.Error())
|
||||
}
|
||||
result, err := trsMigrator.dmOut.DataManager().GetThresholdProfile(tresProf.Tenant, tresProf.ID, false, utils.NonTransactional)
|
||||
if err != nil {
|
||||
t.Error("Error when getting Thresholds ", err.Error())
|
||||
}
|
||||
if !reflect.DeepEqual(tresProf.ID, result.ID) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", tresProf.ID, result.ID)
|
||||
} else if !reflect.DeepEqual(tresProf.Tenant, result.Tenant) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", tresProf.Tenant, result.Tenant)
|
||||
} else if !reflect.DeepEqual(tresProf.Weight, result.Weight) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", tresProf.Weight, result.Weight)
|
||||
} else if !reflect.DeepEqual(tresProf.ActivationInterval, result.ActivationInterval) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", tresProf.ActivationInterval, result.ActivationInterval)
|
||||
} else if !reflect.DeepEqual(tresProf.MinSleep, result.MinSleep) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", tresProf.MinSleep, result.MinSleep)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -535,6 +535,7 @@ const (
|
||||
Freeswitch = "freeswitch"
|
||||
Kamailio = "kamailio"
|
||||
Opensips = "opensips"
|
||||
Asterisk = "asterisk"
|
||||
)
|
||||
|
||||
// Migrator Action
|
||||
@@ -778,6 +779,7 @@ const (
|
||||
TBLTPSuppliers = "tp_suppliers"
|
||||
TBLTPAttributes = "tp_attributes"
|
||||
TBLVersions = "versions"
|
||||
OldSMCosts = "sm_costs"
|
||||
)
|
||||
|
||||
// Cache Name
|
||||
@@ -841,6 +843,7 @@ const (
|
||||
RadiusAgent = "RadiusAgent"
|
||||
DiameterAgent = "DiameterAgent"
|
||||
FreeSWITCHAgent = "FreeSWITCHAgent"
|
||||
AsteriskAgent = "AsteriskAgent"
|
||||
)
|
||||
|
||||
func buildCacheInstRevPrefixes() {
|
||||
|
||||
Reference in New Issue
Block a user