mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-13 19:56:38 +05:00
Update Asterisk Agent and add it in /general_tests/tutorial_calls_test.go
This commit is contained in:
committed by
Dan Christian Bogos
parent
64426affc4
commit
94fbf5650b
@@ -175,85 +175,12 @@ func (smaEv *SMAsteriskEvent) ExtraParameters() (extraParams map[string]string)
|
||||
return
|
||||
}
|
||||
|
||||
func (smaEv *SMAsteriskEvent) AsSMGenericEvent() *sessions.SMGenericEvent {
|
||||
var evName string
|
||||
switch smaEv.EventType() {
|
||||
case ARIStasisStart:
|
||||
evName = SMAAuthorization
|
||||
case ARIChannelStateChange:
|
||||
evName = SMASessionStart
|
||||
case ARIChannelDestroyed:
|
||||
evName = SMASessionTerminate
|
||||
}
|
||||
smgEv := sessions.SMGenericEvent{utils.EVENT_NAME: evName}
|
||||
smgEv[utils.OriginID] = smaEv.ChannelID()
|
||||
if smaEv.RequestType() != "" {
|
||||
smgEv[utils.RequestType] = smaEv.RequestType()
|
||||
}
|
||||
if smaEv.Tenant() != "" {
|
||||
smgEv[utils.Tenant] = smaEv.Tenant()
|
||||
}
|
||||
if smaEv.Category() != "" {
|
||||
smgEv[utils.Category] = smaEv.Category()
|
||||
}
|
||||
if smaEv.Subject() != "" {
|
||||
smgEv[utils.Subject] = smaEv.Subject()
|
||||
}
|
||||
smgEv[utils.OriginHost] = smaEv.OriginatorIP()
|
||||
smgEv[utils.Account] = smaEv.Account()
|
||||
smgEv[utils.Destination] = smaEv.Destination()
|
||||
smgEv[utils.SetupTime] = smaEv.Timestamp()
|
||||
if smaEv.Supplier() != "" {
|
||||
smgEv[utils.SUPPLIER] = smaEv.Supplier()
|
||||
}
|
||||
for extraKey, extraVal := range smaEv.ExtraParameters() { // Append extraParameters
|
||||
smgEv[extraKey] = extraVal
|
||||
}
|
||||
return &smgEv
|
||||
}
|
||||
|
||||
// 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()
|
||||
}
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
*smgEv = resSMGEv
|
||||
return nil
|
||||
}
|
||||
|
||||
func (smaEv *SMAsteriskEvent) UpdateCGREvent(cgrEv *utils.CGREvent) error {
|
||||
resCGREv := *cgrEv
|
||||
switch smaEv.EventType() {
|
||||
case ARIChannelStateChange:
|
||||
if smaEv.ChannelState() == channelUp {
|
||||
resCGREv.Event[utils.EVENT_NAME] = SMASessionStart
|
||||
resCGREv.Event[utils.AnswerTime] = smaEv.Timestamp()
|
||||
}
|
||||
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()
|
||||
@@ -305,7 +232,7 @@ func (smaEv *SMAsteriskEvent) AsMapStringInterface() (mp map[string]interface{})
|
||||
mp[utils.OriginHost] = smaEv.OriginatorIP()
|
||||
mp[utils.Account] = smaEv.Account()
|
||||
mp[utils.Destination] = smaEv.Destination()
|
||||
mp[utils.SetupTime] = smaEv.Timestamp()
|
||||
mp[utils.SetupTime] = smaEv.SetupTime()
|
||||
if smaEv.Supplier() != "" {
|
||||
mp[utils.SUPPLIER] = smaEv.Supplier()
|
||||
}
|
||||
@@ -375,14 +302,10 @@ func (smaEv *SMAsteriskEvent) V1AuthorizeArgs() (args *sessions.V1AuthorizeArgs)
|
||||
return
|
||||
}
|
||||
|
||||
func (smaEv *SMAsteriskEvent) V1InitSessionArgs() (args *sessions.V1InitSessionArgs) {
|
||||
cgrEv, err := smaEv.AsCGREvent(config.CgrConfig().DefaultTimezone)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
func (smaEv *SMAsteriskEvent) V1InitSessionArgs(cgrEv utils.CGREvent) (args *sessions.V1InitSessionArgs) {
|
||||
args = &sessions.V1InitSessionArgs{ // defaults
|
||||
InitSession: true,
|
||||
CGREvent: *cgrEv,
|
||||
CGREvent: cgrEv,
|
||||
}
|
||||
/*
|
||||
subsystems, has := kev[KamCGRSubsystems]
|
||||
@@ -408,14 +331,10 @@ func (smaEv *SMAsteriskEvent) V1InitSessionArgs() (args *sessions.V1InitSessionA
|
||||
return
|
||||
}
|
||||
|
||||
func (smaEv *SMAsteriskEvent) V1TerminateSessionArgs() (args *sessions.V1TerminateSessionArgs) {
|
||||
cgrEv, err := smaEv.AsCGREvent(config.CgrConfig().DefaultTimezone)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
func (smaEv *SMAsteriskEvent) V1TerminateSessionArgs(cgrEv utils.CGREvent) (args *sessions.V1TerminateSessionArgs) {
|
||||
args = &sessions.V1TerminateSessionArgs{ // defaults
|
||||
TerminateSession: true,
|
||||
CGREvent: *cgrEv,
|
||||
CGREvent: cgrEv,
|
||||
}
|
||||
/*
|
||||
subsystems, has := kev[KamCGRSubsystems]
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,8 +136,6 @@ func (sma *AsteriskAgent) handleStasisStart(ev *SMAsteriskEvent) {
|
||||
utils.AsteriskAgent, ev.ChannelID()))
|
||||
return
|
||||
}
|
||||
// var maxUsage float64
|
||||
// smgEv := ev.AsSMGenericEvent()
|
||||
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",
|
||||
@@ -161,7 +159,7 @@ func (sma *AsteriskAgent) handleStasisStart(ev *SMAsteriskEvent) {
|
||||
sma.cgrCfg.AsteriskAgentCfg().AsteriskConns[sma.astConnIdx].Address,
|
||||
ev.ChannelID(), CGRMaxSessionTime),
|
||||
url.Values{"value": {strconv.FormatFloat(
|
||||
float64(authReply.MaxUsage.Nanoseconds())*1000, 'f', -1, 64)}}); err != nil { // Asterisk expects value in ms
|
||||
float64(authReply.MaxUsage.Miliseconds(), '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
|
||||
@@ -190,18 +188,33 @@ func (sma *AsteriskAgent) handleChannelStateChange(ev *SMAsteriskEvent) {
|
||||
return
|
||||
}
|
||||
sma.evCacheMux.RLock()
|
||||
_, hasIt := sma.eventsCache[ev.ChannelID()]
|
||||
cgrEv, hasIt := sma.eventsCache[ev.ChannelID()]
|
||||
sma.evCacheMux.RUnlock()
|
||||
if !hasIt { // Not handled by us
|
||||
return
|
||||
}
|
||||
|
||||
initSessionArgs := ev.V1InitSessionArgs()
|
||||
sma.evCacheMux.Lock()
|
||||
err := ev.UpdateCGREvent(cgrEv) // Updates the event directly in the cache
|
||||
sma.evCacheMux.Unlock()
|
||||
if err != nil {
|
||||
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("<%s> Error: %s when attempting to disconnect channelID: %s",
|
||||
utils.AsteriskAgent, err.Error(), ev.ChannelID()))
|
||||
}
|
||||
return
|
||||
}
|
||||
// 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,
|
||||
@@ -223,63 +236,19 @@ func (sma *AsteriskAgent) handleChannelStateChange(ev *SMAsteriskEvent) {
|
||||
}
|
||||
return
|
||||
}
|
||||
sma.evCacheMux.Lock()
|
||||
err := ev.UpdateCGREvent(&initSessionArgs.CGREvent) // Updates the event directly in the cache
|
||||
sma.evCacheMux.Unlock()
|
||||
if err != nil {
|
||||
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("<%s> Error: %s when attempting to disconnect channelID: %s",
|
||||
utils.AsteriskAgent, err.Error(), ev.ChannelID()))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Channel disconnect
|
||||
func (sma *AsteriskAgent) handleChannelDestroyed(ev *SMAsteriskEvent) {
|
||||
sma.evCacheMux.RLock()
|
||||
_, hasIt := sma.eventsCache[ev.ChannelID()]
|
||||
cgrEv, hasIt := sma.eventsCache[ev.ChannelID()]
|
||||
sma.evCacheMux.RUnlock()
|
||||
if !hasIt { // Not handled by us
|
||||
return
|
||||
}
|
||||
|
||||
//terminate session
|
||||
tsArgs := ev.V1TerminateSessionArgs()
|
||||
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(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 {
|
||||
setupTime, err := utils.ParseTimeDetectLayout(
|
||||
ev.SetupTime(), config.CgrConfig().DefaultTimezone)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cgrEv := utils.CGREvent{
|
||||
Tenant: ev.Tenant(),
|
||||
ID: utils.UUIDSha1Prefix(),
|
||||
Time: &setupTime,
|
||||
Event: ev.AsMapStringInterface(),
|
||||
}
|
||||
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()))
|
||||
}
|
||||
}
|
||||
sma.evCacheMux.Lock()
|
||||
err := ev.UpdateCGREvent(&tsArgs.CGREvent) // 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("<%s> Error: %s when attempting to initiate session for channelID: %s",
|
||||
@@ -290,6 +259,27 @@ func (sma *AsteriskAgent) handleChannelDestroyed(ev *SMAsteriskEvent) {
|
||||
}
|
||||
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(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(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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[simpletrans]
|
||||
type=transport
|
||||
protocol=udp
|
||||
bind=192.168.56.203
|
||||
bind=0.0.0.0
|
||||
|
||||
[1001]
|
||||
type = endpoint
|
||||
|
||||
@@ -4,28 +4,24 @@
|
||||
// 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,
|
||||
},
|
||||
|
||||
|
||||
"stor_db": { // database used to store offline tariff plans and CDRs
|
||||
"db_password": "CGRateS.org", // password to use when connecting to stordb
|
||||
"listen": {
|
||||
"rpc_json": ":2012",
|
||||
"rpc_gob": ":2013",
|
||||
"http": ":2080",
|
||||
},
|
||||
|
||||
|
||||
"stor_db": {
|
||||
"db_password": "CGRateS.org",
|
||||
},
|
||||
|
||||
|
||||
"scheduler": {
|
||||
"enabled": true,
|
||||
},
|
||||
|
||||
|
||||
@@ -84,9 +80,6 @@
|
||||
"debit_interval": "10s",
|
||||
},
|
||||
|
||||
"scheduler": {
|
||||
"enabled": true,
|
||||
},
|
||||
|
||||
"cdre": {
|
||||
"*default": {
|
||||
|
||||
@@ -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,73 @@ 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)
|
||||
}
|
||||
}
|
||||
|
||||
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 +168,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 +191,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 +212,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 +233,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 +243,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 +263,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 +282,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 +298,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 +309,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 +328,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 +357,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 +402,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 +420,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 +433,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 +465,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 +492,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 +512,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 +527,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 +537,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 +550,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 +567,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)
|
||||
}
|
||||
@@ -535,6 +535,7 @@ const (
|
||||
Freeswitch = "freeswitch"
|
||||
Kamailio = "kamailio"
|
||||
Opensips = "opensips"
|
||||
Asterisk = "asterisk"
|
||||
)
|
||||
|
||||
// Migrator Action
|
||||
|
||||
Reference in New Issue
Block a user