Merge branch 'master' into aliases

This commit is contained in:
Radu Ioan Fericean
2015-08-18 20:13:14 +03:00
21 changed files with 569 additions and 239 deletions

View File

@@ -168,8 +168,7 @@ func (self *ApierV1) SetAccount(attr utils.AttrSetAccount, reply *string) error
ub = bal
} else { // Not found in db, create it here
ub = &engine.Account{
Id: balanceId,
AllowNegative: attr.AllowNegative,
Id: balanceId,
}
}
@@ -183,6 +182,12 @@ func (self *ApierV1) SetAccount(attr utils.AttrSetAccount, reply *string) error
at.AccountIds = append(at.AccountIds, balanceId)
}
}
if attr.AllowNegative != nil {
ub.AllowNegative = *attr.AllowNegative
}
if attr.Disabled != nil {
ub.Disabled = *attr.Disabled
}
// All prepared, save account
if err := self.AccountDb.SetAccount(ub); err != nil {
return 0, err

View File

@@ -68,9 +68,11 @@ func (self *ApierV1) GetLcrSuppliers(lcrReq engine.LcrRequest, suppliers *string
if err := self.Responder.GetLCR(&engine.AttrGetLcr{CallDescriptor: cd, Paginator: lcrReq.Paginator}, &lcrQried); err != nil {
return utils.NewErrServerError(err)
}
if lcrQried.HasErrors() && !lcrReq.IgnoreErrors {
if lcrQried.HasErrors() {
lcrQried.LogErrors()
return fmt.Errorf("%s:%s", utils.ErrServerError.Error(), "LCR_ERRORS")
if !lcrReq.IgnoreErrors {
return fmt.Errorf("%s:%s", utils.ErrServerError.Error(), "LCR_COMPUTE_ERRORS")
}
}
if suppliersStr, err := lcrQried.SuppliersString(); err != nil {
return utils.NewErrServerError(err)

View File

@@ -60,7 +60,7 @@ loadmodule "jsonrpc-s.so"
# ----------------- setting module-specific parameters ---------------
# ----- mi_fifo params -----
modparam("mi_fifo", "fifo_name", "/tmp/cgr_kamevapi/kamailio/run/kamailio_fifo")
modparam("mi_fifo", "fifo_name", "/tmp/kamailio_fifo")
# ----- tm params -----
modparam("tm", "failure_reply_mode", 3)

View File

@@ -45,18 +45,20 @@ Database setup
~~~~~~~~~~~~~~
For it's operation CGRateS uses more database types, depending on it's nature, install and configuration being further necessary.
At present we support the following databases:
As DataDB types (rating and accounting subsystems):
- Redis_
As StorDB (persistent storage for CDRs and tariff plan versions).
Used as DataDb, optimized for real-time information access.
Once installed there should be no special requirements in terms of setup since no schema is necessary.
- MySQL_
Used as StorDb, optimized for CDR archiving and offline Tariff Plan versioning.
Once database is installed, CGRateS database needs to be set-up out of provided scripts (example for the paths set-up by debian package)
::
@@ -66,12 +68,13 @@ Once database is installed, CGRateS database needs to be set-up out of provided
- PostgreSQL_
Used as StorDb, optimized for CDR archiving and offline Tariff Plan versioning.
Once database is installed, CGRateS database needs to be set-up out of provided scripts (example for the paths set-up by debian package)
::
cd /usr/share/cgrates/storage/postgres/
./setup_cgr_db.sh root CGRateS.org localhost
./setup_cgr_db.sh
.. _Redis: http://redis.io/
.. _MySQL: http://www.mysql.org/

View File

@@ -1,7 +1,7 @@
sFreeSWITCH Integration Tutorials
FreeSWITCH Integration Tutorials
================================
In these tutorials we exemplify few cases of integration between FreeSWITCH_ and **CGRateS**. We start with common steps, installation and postinstall processes then we dive into particular configurations, depending on the case we run.
In these tutorials we exemplify few cases of integration between FreeSWITCH_ and **CGRateS**. We start with common steps, installation and postinstall processes then we dive into particular configurations.
.. toctree::
@@ -10,7 +10,6 @@ In these tutorials we exemplify few cases of integration between FreeSWITCH_ and
tut_freeswitch_installs
tut_cgrates_installs
tut_jitsi_installs
tut_freeswitch_csv
tut_freeswitch_json
tut_cgrates_usage

View File

@@ -4,7 +4,7 @@ FreeSWITCH_ generating *http-json* CDRs
Scenario
--------
- FreeSWITCH with *vanilla* configuration, replacing *mod_cdr_csv* with *mod_json_cdr*.
- FreeSWITCH with *vanilla* configuration adding *mod_json_cdr* for CDR generation.
- Modified following users (with configs in *etc/freeswitch/directory/default*): 1001-prepaid, 1002-postpaid, 1003-pseudoprepaid, 1004-rated, 1006-prepaid, 1007-rated.
- Have added inside default dialplan CGR own extensions just before routing towards users (*etc/freeswitch/dialplan/default.xml*).
@@ -13,8 +13,8 @@ Scenario
- **CGRateS** with following components:
- CGR-SM started as prepaid controller, with debits taking place at 5s intervals.
- CGR-Mediator component attaching costs to the raw CDRs from FreeSWITCH_ inside CGR StorDB.
- CGR-CDRE exporting mediated CDRs from CGR StorDB (export path: */tmp*).
- CGR-CDRS component receiving raw CDRs from FreeSWITCH, storing them and attaching costs inside CGR StorDB.
- CGR-CDRE exporting processed CDRs from CGR StorDB (export path: */tmp*).
- CGR-History component keeping the archive of the rates modifications (path browsable with git client at */tmp/cgr_history*).
@@ -23,7 +23,7 @@ Starting FreeSWITCH_ with custom configuration
::
/usr/share/cgrates/tutorials/fs_json/freeswitch/etc/init.d/freeswitch start
/usr/share/cgrates/tutorials/fs_evsock/freeswitch/etc/init.d/freeswitch start
To verify that FreeSWITCH_ is running we run the console command:
@@ -37,7 +37,7 @@ Starting **CGRateS** with custom configuration
::
/usr/share/cgrates/tutorials/fs_json/cgrates/etc/init.d/cgrates start
/usr/share/cgrates/tutorials/fs_evsock/cgrates/etc/init.d/cgrates start
Check that cgrates is running
@@ -49,7 +49,7 @@ Check that cgrates is running
CDR processing
--------------
At the end of each call FreeSWITCH_ will issue a http post with the CDR. This will reach inside **CGRateS** through the *CDRS* component (close to real-time). Once in-there it will be instantly mediated and it is ready to be exported:
At the end of each call FreeSWITCH_ will issue a http post with the CDR. This will reach inside **CGRateS** through the *CDRS* component (close to real-time). Once in-there it will be instantly rated and it is ready to be exported:
::

18
docs/tut_kamailio.rst Normal file
View File

@@ -0,0 +1,18 @@
Kamailio_ Integration Tutorials
===============================
In these tutorials we exemplify few cases of integration between Kamailio_ and CGRateS_. We start with common steps, installation and postinstall processes then we dive into particular configurations, depending on the case we run.
.. toctree::
:maxdepth: 2
tut_kamailio_installs
tut_cgrates_installs
tut_jitsi_installs
tut_kamailio_evapi
tut_cgrates_usage
.. _Kamailio: http://www.kamailio.org/
.. _CGRateS: http://www.cgrates.org/

View File

@@ -0,0 +1,59 @@
Kamailio_ interaction via *evapi* module
=========================================
Scenario
--------
- Kamailio default configuration modified for **CGRateS** interaction. For script maintainability and simplicity we have separated CGRateS specific routes in *kamailio-cgrates.cfg* file which is included in main *kamailio.cfg* via include directive.
- Considering the following users (with configs hardcoded in the *kamailio.cfg* configuration script and loaded in htable): 1001-prepaid, 1002-postpaid, 1003-pseudoprepaid, 1004-rated, 1005-rated, 1006-prepaid, 1007-prepaid.
- **CGRateS** with following components:
- CGR-SM started as translator between Kamailio_ and CGR-Rater for both authorization events as well as accounting ones.
- CGR-CDRS component processing raw CDRs from CGR-SM component and storing them inside CGR StorDB.
- CGR-CDRE exporting rated CDRs from CGR StorDB (export path: */tmp*).
- CGR-History component keeping the archive of the rates modifications (path browsable with git client at */tmp/cgr_history*).
Starting Kamailio_ with custom configuration
----------------------------------------------
::
/usr/share/cgrates/tutorials/kamevapi/kamailio/etc/init.d/kamailio start
To verify that Kamailio_ is running we run the console command:
::
kamctl moni
Starting **CGRateS** with custom configuration
----------------------------------------------
::
/usr/share/cgrates/tutorials/kamevapi/cgrates/etc/init.d/cgrates start
Make sure that cgrates is running
::
cgr-console status
CDR processing
--------------
At the end of each call Kamailio_ will generate an CDR event via *evapi* and this will be directed towards the port configured inside *cgrates.json*. This event will reach inside **CGRateS** through the *SM* component (close to real-time). Once in-there it will be instantly rated and be ready for export.
**CGRateS** Usage
-----------------
Since it is common to most of the tutorials, the example for **CGRateS** usage is provided in a separate page `here <http://cgrates.readthedocs.org/en/latest/tut_cgrates_usage.html>`_
.. _Kamailio: http://www.kamailio.org/

View File

@@ -0,0 +1,20 @@
Software installation
=====================
As operating system we have choosen Debian Wheezy, since all the software components we use provide packaging for it.
Kamailio_
---------
We got Kamailio_ installed via following commands:
::
apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xfb40d3e6508ea4c8
cd /etc/apt/sources.list.d/
wget http://apt.itsyscom.com/conf/kamailio.apt.list .
apt-get update
apt-get install kamailio kamailio-extra-modules kamailio-json-modules
Once installed we proceed with loading the configuration out of specific tutorial cases bellow.
.. _Kamailio: http://www.kamailio.org/

View File

@@ -12,8 +12,8 @@ Scenario
- **CGRateS** with following components:
- CGR-SM started as translator between OpenSIPS_ and **cgr-rater** for both authorization events (pseudoprepaid) as well as CDR ones.
- CGR-Mediator component attaching costs to the raw CDRs from OpenSIPS_ inside CGR StorDB.
- CGR-CDRE exporting mediated CDRs from CGR StorDB (export path: */tmp*).
- CGR-CDRS component processing raw CDRs from CGR-SM component and storing them inside CGR StorDB.
- CGR-CDRE exporting rated CDRs from CGR StorDB (export path: */tmp*).
- CGR-History component keeping the archive of the rates modifications (path browsable with git client at */tmp/cgr_history*).
@@ -22,7 +22,7 @@ Starting OpenSIPS_ with custom configuration
::
/usr/share/cgrates/tutorials/osips_event/opensips/etc/init.d/opensips start
/usr/share/cgrates/tutorials/osips_async/opensips/etc/init.d/opensips start
To verify that OpenSIPS_ is running we run the console command:
@@ -36,9 +36,9 @@ Starting **CGRateS** with custom configuration
::
/usr/share/cgrates/tutorials/osips_event/cgrates/etc/init.d/cgrates start
/usr/share/cgrates/tutorials/osips_async/cgrates/etc/init.d/cgrates start
Check that cgrates is running
Make sure that cgrates is running
::
@@ -48,7 +48,7 @@ Check that cgrates is running
CDR processing
--------------
At the end of each call OpenSIPS_ will generate an CDR event and due to automatic handler registration built in **CGRateS-SM** component, this will be directed towards the port configured inside *cgrates.cfg*. This event will reach inside **CGRateS** through the *SM* component (close to real-time). Once in-there it will be instantly mediated and it is ready to be exported.
At the end of each call OpenSIPS_ will generate an CDR event and due to automatic handler registration built in **CGRateS-SM** component, this will be directed towards the port configured inside *cgrates.json*. This event will reach inside **CGRateS** through the *SM* component (close to real-time). Once in-there it will be instantly rated and be ready for export.
**CGRateS** Usage

View File

@@ -12,9 +12,9 @@ We got OpenSIPS_ installed via following commands:
wget http://apt.opensips.org/key.asc
apt-key add key.asc
cd /etc/apt/sources.list.d/
wget http://apt.itsyscom.com/conf/opensips.apt.list
wget http://apt.itsyscom.com/conf/opensips.wheezy.apt.list
apt-get update
apt-get install
apt-get install opensips opensips-json-module opensips-restclient-module
Once installed we proceed with loading the configuration out of specific tutorial cases bellow.

View File

@@ -5,4 +5,5 @@
:maxdepth: 2
tut_freeswitch
tut_kamailio
tut_opensips

View File

@@ -54,7 +54,7 @@ type LcrRequest struct {
Account string
Subject string
Destination string
StartTime string
SetupTime string
Duration string
IgnoreErrors bool
*utils.Paginator
@@ -79,9 +79,9 @@ func (self *LcrRequest) AsCallDescriptor() (*CallDescriptor, error) {
}
var timeStart time.Time
var err error
if len(self.StartTime) == 0 {
if len(self.SetupTime) == 0 {
timeStart = time.Now()
} else if timeStart, err = utils.ParseTimeDetectLayout(self.StartTime); err != nil {
} else if timeStart, err = utils.ParseTimeDetectLayout(self.SetupTime); err != nil {
return nil, err
}
var callDur time.Duration

View File

@@ -215,11 +215,11 @@ func TestLcrGet(t *testing.T) {
func TestLcrRequestAsCallDescriptor(t *testing.T) {
sTime := time.Date(2015, 04, 06, 17, 40, 0, 0, time.UTC)
callDur := time.Duration(1) * time.Minute
lcrReq := &LcrRequest{Account: "2001", StartTime: sTime.String()}
lcrReq := &LcrRequest{Account: "2001", SetupTime: sTime.String()}
if _, err := lcrReq.AsCallDescriptor(); err == nil || err != utils.ErrMandatoryIeMissing {
t.Error("Unexpected error received: %v", err)
}
lcrReq = &LcrRequest{Account: "2001", Destination: "2002", StartTime: sTime.String()}
lcrReq = &LcrRequest{Account: "2001", Destination: "2002", SetupTime: sTime.String()}
eCd := &CallDescriptor{
Direction: utils.OUT,
Tenant: config.CgrConfig().DefaultTenant,

View File

@@ -23,6 +23,7 @@ import (
"net/rpc/jsonrpc"
"os"
"path"
"reflect"
"strings"
"testing"
"time"
@@ -94,13 +95,11 @@ func TestTutFsCallsStartEngine(t *testing.T) {
}
// Restart FS so we make sure reconnects are working
func TestTutFsCallsRestartFS(t *testing.T) {
if !*testCalls {
return
}
engine.KillProcName("freeswitch", 5000)
if err := engine.CallScript(path.Join(*dataDir, "tutorials", "fs_evsock", "freeswitch", "etc", "init.d", "freeswitch"), "start", 3000); err != nil {
if err := engine.CallScript(path.Join(*dataDir, "tutorials", "fs_evsock", "freeswitch", "etc", "init.d", "freeswitch"), "restart", 5000); err != nil {
t.Fatal(err)
}
}
@@ -174,6 +173,51 @@ func TestTutFsCallsAccountsBefore(t *testing.T) {
}
}
// Make sure all stats queues are in place
func TestTutFsCallsCdrStatsBefore(t *testing.T) {
if !*testCalls {
return
}
//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) {
if !*testCalls {
@@ -181,12 +225,12 @@ 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:25060"},
&engine.PjsuaAccount{Id: "sip:1002@127.0.0.1", Username: "1002", Password: "1234", Realm: "*", Registrar: "sip:127.0.0.1:25060"},
&engine.PjsuaAccount{Id: "sip:1003@127.0.0.1", Username: "1003", Password: "1234", Realm: "*", Registrar: "sip:127.0.0.1:25060"},
&engine.PjsuaAccount{Id: "sip:1004@127.0.0.1", Username: "1004", Password: "1234", Realm: "*", Registrar: "sip:127.0.0.1:25060"},
&engine.PjsuaAccount{Id: "sip:1006@127.0.0.1", Username: "1006", Password: "1234", Realm: "*", Registrar: "sip:127.0.0.1:25060"},
&engine.PjsuaAccount{Id: "sip:1007@127.0.0.1", Username: "1007", Password: "1234", Realm: "*", Registrar: "sip:127.0.0.1:25060"}}
&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, *waitRater); err != nil {
t.Fatal(err)
}
@@ -198,7 +242,7 @@ func TestTutFsCallsCall1001To1002(t *testing.T) {
return
}
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:25060", time.Duration(67)*time.Second, 5071); err != nil {
"sip:127.0.0.1:5060", time.Duration(67)*time.Second, 5071); err != nil {
t.Fatal(err)
}
}
@@ -209,7 +253,7 @@ func TestTutFsCallsCall1001To1003(t *testing.T) {
return
}
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:25060", time.Duration(65)*time.Second, 5072); err != nil {
"sip:127.0.0.1:5060", time.Duration(65)*time.Second, 5072); err != nil {
t.Fatal(err)
}
}
@@ -219,7 +263,7 @@ func TestTutFsCallsCall1002To1001(t *testing.T) {
return
}
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:25060", time.Duration(61)*time.Second, 5073); err != nil {
"sip:127.0.0.1:5060", time.Duration(61)*time.Second, 5073); err != nil {
t.Fatal(err)
}
}
@@ -229,7 +273,7 @@ func TestTutFsCallsCall1003To1001(t *testing.T) {
return
}
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:25060", time.Duration(63)*time.Second, 5074); err != nil {
"sip:127.0.0.1:5060", time.Duration(63)*time.Second, 5074); err != nil {
t.Fatal(err)
}
}
@@ -239,7 +283,7 @@ func TestTutFsCallsCall1004To1001(t *testing.T) {
return
}
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:25060", time.Duration(62)*time.Second, 5075); err != nil {
"sip:127.0.0.1:5060", time.Duration(62)*time.Second, 5075); err != nil {
t.Fatal(err)
}
}
@@ -249,7 +293,7 @@ func TestTutFsCallsCall1006To1002(t *testing.T) {
return
}
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:25060", time.Duration(64)*time.Second, 5076); err != nil {
"sip:127.0.0.1:5060", time.Duration(64)*time.Second, 5076); err != nil {
t.Fatal(err)
}
}
@@ -259,7 +303,7 @@ func TestTutFsCallsCall1007To1002(t *testing.T) {
return
}
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:25060", time.Duration(66)*time.Second, 5077); err != nil {
"sip:127.0.0.1:5060", time.Duration(66)*time.Second, 5077); err != nil {
t.Fatal(err)
}
}
@@ -282,7 +326,7 @@ func TestTutFsCallsAccount1001(t *testing.T) {
}
// Make sure account was debited properly
func TestTutFsCallsCdrs(t *testing.T) {
func TestTutFsCalls1001Cdrs(t *testing.T) {
if !*testCalls {
return
}
@@ -308,6 +352,9 @@ func TestTutFsCallsCdrs(t *testing.T) {
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 {
@@ -352,7 +399,16 @@ func TestTutFsCallsCdrs(t *testing.T) {
t.Errorf("Unexpected Subject for CDR: %+v", reply[0])
}
}
req = utils.RpcCdrsFilter{Accounts: []string{"1002"}, RunIds: []string{utils.META_DEFAULT}}
}
// Make sure account was debited properly
func TestTutFsCalls1002Cdrs(t *testing.T) {
if !*testCalls {
return
}
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) != 1 {
@@ -371,7 +427,15 @@ func TestTutFsCallsCdrs(t *testing.T) {
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
}
}
req = utils.RpcCdrsFilter{Accounts: []string{"1003"}, RunIds: []string{utils.META_DEFAULT}}
}
// Make sure account was debited properly
func TestTutFsCalls1003Cdrs(t *testing.T) {
if !*testCalls {
return
}
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 {
@@ -390,7 +454,16 @@ func TestTutFsCallsCdrs(t *testing.T) {
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
}
}
req = utils.RpcCdrsFilter{Accounts: []string{"1004"}, RunIds: []string{utils.META_DEFAULT}}
}
// Make sure account was debited properly
func TestTutFsCalls1004Cdrs(t *testing.T) {
if !*testCalls {
return
}
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 {
@@ -409,7 +482,16 @@ func TestTutFsCallsCdrs(t *testing.T) {
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
}
}
req = utils.RpcCdrsFilter{Accounts: []string{"1006"}, RunIds: []string{utils.META_DEFAULT}}
}
// Make sure account was debited properly
func TestTutFsCalls1006Cdrs(t *testing.T) {
if !*testCalls {
return
}
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) != 1 {
@@ -431,7 +513,15 @@ func TestTutFsCallsCdrs(t *testing.T) {
t.Errorf("Unexpected Cost for CDR: %+v", reply[0])
}
}
req = utils.RpcCdrsFilter{Accounts: []string{"1007"}, RunIds: []string{utils.META_DEFAULT}}
}
// Make sure account was debited properly
func TestTutFsCalls1007Cdrs(t *testing.T) {
if !*testCalls {
return
}
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 {

View File

@@ -72,13 +72,13 @@ func TestTutKamCallsResetStorDb(t *testing.T) {
}
}
// start Kam server
func TestTutKamCallsStartKam(t *testing.T) {
// start FS server
func TestTutKamCallsStartKamailio(t *testing.T) {
if !*testCalls {
return
}
engine.KillProcName("kamailio", *waitRater)
if err := engine.CallScript(path.Join(*dataDir, "tutorials", "kamevapi", "kamailio", "etc", "init.d", "kamailio"), "start", 3000); err != nil {
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)
}
}
@@ -94,12 +94,12 @@ func TestTutKamCallsStartEngine(t *testing.T) {
}
}
// Restart Kam so we make sure reconnects are working
func TestTutKamCallsRestartKam(t *testing.T) {
// Restart FS so we make sure reconnects are working
func TestTutKamCallsRestartKamailio(t *testing.T) {
if !*testCalls {
return
}
if err := engine.CallScript(path.Join(*dataDir, "tutorials", "kamevapi", "kamailio", "etc", "init.d", "kamailio"), "restart", 4000); err != nil {
if err := engine.CallScript(path.Join(*dataDir, "tutorials", "kamevapi", "kamailio", "etc", "init.d", "kamailio"), "restart", 3000); err != nil {
t.Fatal(err)
}
}
@@ -131,7 +131,7 @@ func TestTutKamCallsLoadTariffPlanFromFolder(t *testing.T) {
time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for scheduler to execute topups
}
// Make sure account was topped-up properly
// Make sure account was debited properly
func TestTutKamCallsAccountsBefore(t *testing.T) {
if !*testCalls {
return
@@ -180,13 +180,7 @@ 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.ACC: -1, engine.ACD: -1, engine.ASR: -1}
if err := tutKamCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: utils.META_DEFAULT}, &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}
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) {
@@ -253,12 +247,23 @@ func TestTutKamCallsCall1001To1002(t *testing.T) {
}
}
// Call from 1001 (prepaid) to 1003
func TestTutKamCallsCall1001To1003(t *testing.T) {
if !*testCalls {
return
}
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 !*testCalls {
return
}
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, 5072); err != nil {
"sip:127.0.0.1:5060", time.Duration(61)*time.Second, 5073); err != nil {
t.Fatal(err)
}
}
@@ -268,7 +273,7 @@ func TestTutKamCallsCall1003To1001(t *testing.T) {
return
}
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, 5073); err != nil {
"sip:127.0.0.1:5060", time.Duration(63)*time.Second, 5074); err != nil {
t.Fatal(err)
}
}
@@ -278,7 +283,7 @@ func TestTutKamCallsCall1004To1001(t *testing.T) {
return
}
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, 5074); err != nil {
"sip:127.0.0.1:5060", time.Duration(62)*time.Second, 5075); err != nil {
t.Fatal(err)
}
}
@@ -288,7 +293,7 @@ func TestTutKamCallsCall1006To1002(t *testing.T) {
return
}
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, 5075); err != nil {
"sip:127.0.0.1:5060", time.Duration(64)*time.Second, 5076); err != nil {
t.Fatal(err)
}
}
@@ -298,42 +303,7 @@ func TestTutKamCallsCall1007To1002(t *testing.T) {
return
}
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, 5076); err != nil {
t.Fatal(err)
}
}
/*
// Should hangup at 62 seconds, disconnect from SM
func TestTutKamCallsCall1007To1007(t *testing.T) {
if !*testCalls {
return
}
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1007@127.0.0.1", Username: "1007", Password: "CGRateS.org", Realm: "*"}, "sip:1007@127.0.0.1",
"sip:127.0.0.1:5060", time.Duration(75)*time.Second, 5077); err != nil {
t.Fatal(err)
}
}
// Should hangup at 62 seconds, disconnect from Kamailio
func TestTutKamCallsCall1003To1007(t *testing.T) {
if !*testCalls {
return
}
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1003@127.0.0.1", Username: "1003", Password: "CGRateS.org", Realm: "*"}, "sip:1007@127.0.0.1",
"sip:127.0.0.1:5060", time.Duration(73)*time.Second, 5078); err != nil {
t.Fatal(err)
}
}
*/
// Call from 1001 (prepaid) to 1007, should not cost more than 62 which is MaxCallCost
func TestTutKamCallsCall1001To1007(t *testing.T) {
if !*testCalls {
return
}
if err := engine.PjsuaCallUri(&engine.PjsuaAccount{Id: "sip:1001@127.0.0.1", Username: "1001", Password: "CGRateS.org", Realm: "*"}, "sip:1007@127.0.0.1",
"sip:127.0.0.1:5060", time.Duration(70)*time.Second, 5079); err != nil {
"sip:127.0.0.1:5060", time.Duration(66)*time.Second, 5077); err != nil {
t.Fatal(err)
}
}
@@ -343,7 +313,7 @@ func TestTutKamCallsAccount1001(t *testing.T) {
if !*testCalls {
return
}
time.Sleep(time.Duration(80) * time.Second) // Allow calls to finish before start querying the results
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", Direction: "*out"}
if err := tutKamCallsRpc.Call("ApierV1.GetAccount", attrs, &reply); err != nil {
@@ -356,17 +326,20 @@ func TestTutKamCallsAccount1001(t *testing.T) {
}
// Make sure account was debited properly
func TestTutKamCallsCdrs(t *testing.T) {
func TestTutKamCalls1001Cdrs(t *testing.T) {
if !*testCalls {
return
}
var reply []*engine.ExternalCdr
req := utils.RpcCdrsFilter{Accounts: []string{"1001"}, RunIds: []string{utils.META_DEFAULT}}
var cgrId string // Share with getCostDetails
var cCost engine.CallCost
req := utils.RpcCdrsFilter{RunIds: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}, DestPrefixes: []string{"1002"}}
if err := tutKamCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
t.Error("Unexpected error: ", err.Error())
} else if len(reply) != 2 {
} else if len(reply) != 1 {
t.Error("Unexpected number of CDRs returned: ", len(reply))
} else {
cgrId = reply[0].CgrId
if reply[0].CdrSource != "KAMAILIO_CGR_CALL_END" {
t.Errorf("Unexpected CdrSource for CDR: %+v", reply[0])
}
@@ -374,11 +347,44 @@ func TestTutKamCallsCdrs(t *testing.T) {
t.Errorf("Unexpected ReqType for CDR: %+v", reply[0])
}
if reply[0].Usage != "67" { // Usage as seconds
t.Errorf("Unexpected Usage for 428CDR: %+v", reply[0])
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
}
if reply[0].Supplier != "suppl2" { // Usage as seconds
t.Errorf("Unexpected Supplier 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"}, DestPrefixes: []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].ReqType != utils.META_PREPAID {
t.Errorf("Unexpected ReqType 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"}, FilterOnRated: true}
if err := tutKamCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
@@ -392,11 +398,17 @@ func TestTutKamCallsCdrs(t *testing.T) {
if reply[0].Subject != "1002" {
t.Errorf("Unexpected Subject for CDR: %+v", reply[0])
}
if reply[0].Supplier != "suppl2" {
t.Errorf("Unexpected Supplier for CDR: %+v", reply[0])
}
}
req = utils.RpcCdrsFilter{Accounts: []string{"1002"}, RunIds: []string{utils.META_DEFAULT}}
}
// Make sure account was debited properly
func TestTutKamCalls1002Cdrs(t *testing.T) {
if !*testCalls {
return
}
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) != 1 {
@@ -414,11 +426,16 @@ func TestTutKamCallsCdrs(t *testing.T) {
if reply[0].Usage != "61" { // Usage as seconds
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
}
if reply[0].Supplier != "suppl1" {
t.Errorf("Unexpected Supplier for CDR: %+v", reply[0])
}
}
req = utils.RpcCdrsFilter{Accounts: []string{"1003"}, RunIds: []string{utils.META_DEFAULT}}
}
// Make sure account was debited properly
func TestTutKamCalls1003Cdrs(t *testing.T) {
if !*testCalls {
return
}
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 {
@@ -433,14 +450,20 @@ func TestTutKamCallsCdrs(t *testing.T) {
if reply[0].Destination != "1001" {
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
}
if reply[0].Usage != "63" { // Usage as seconds
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])
}
if reply[0].Supplier != "suppl1" {
t.Errorf("Unexpected Supplier for CDR: %+v", reply[0])
}
}
req = utils.RpcCdrsFilter{Accounts: []string{"1004"}, RunIds: []string{utils.META_DEFAULT}}
}
// Make sure account was debited properly
func TestTutKamCalls1004Cdrs(t *testing.T) {
if !*testCalls {
return
}
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 {
@@ -455,14 +478,20 @@ func TestTutKamCallsCdrs(t *testing.T) {
if reply[0].Destination != "1001" {
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
}
if reply[0].Usage != "62" { // Usage as seconds
if reply[0].Usage != "62" && reply[0].Usage != "63" { // Usage as seconds
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
}
if reply[0].Supplier != "suppl1" {
t.Errorf("Unexpected Supplier for CDR: %+v", reply[0])
}
}
req = utils.RpcCdrsFilter{Accounts: []string{"1006"}, RunIds: []string{utils.META_DEFAULT}}
}
// Make sure account was debited properly
func TestTutKamCalls1006Cdrs(t *testing.T) {
if !*testCalls {
return
}
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) != 1 {
@@ -477,84 +506,42 @@ func TestTutKamCallsCdrs(t *testing.T) {
if reply[0].Destination != "1002" {
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
}
if reply[0].Usage != "64" { // Usage as seconds
if reply[0].Usage != "64" && reply[0].Usage != "65" { // Usage as seconds
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
}
if reply[0].Supplier != "suppl3" {
t.Errorf("Unexpected Supplier for CDR: %+v", reply[0])
}
}
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].CdrSource != "KAMAILIO_CGR_CALL_END" {
t.Errorf("Unexpected CdrSource for CDR: %+v", reply[0])
}
if reply[0].ReqType != utils.META_PREPAID {
t.Errorf("Unexpected ReqType for CDR: %+v", reply[0])
}
if reply[0].Destination != "1002" {
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
}
if reply[0].Usage != "66" { // Usage as seconds
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
}
if reply[0].Supplier != "suppl3" {
t.Errorf("Unexpected Supplier 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 all stats queues were updated
func TestTutKamCallsCdrStatsAfter(t *testing.T) {
// Make sure account was debited properly
func TestTutKamCalls1007Cdrs(t *testing.T) {
if !*testCalls {
return
}
var statMetrics map[string]float64
eMetrics := map[string]float64{engine.ACC: 0.9015222222, engine.ACD: 65.5555555556, engine.ASR: 100}
if err := tutKamCallsRpc.Call("CDRStatsV1.GetMetrics", v1.AttrGetMetrics{StatsQueueId: utils.META_DEFAULT}, &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: 0.8829, engine.ACD: 64.7142857143, engine.ASR: 100, engine.TCC: 6.1803, engine.TCD: 453}
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.TCC: 6.1803, engine.TCD: 453, engine.ACC: 0.32, engine.ACD: 68.5, engine.ASR: 100}
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: 61, engine.ASR: 100, engine.TCC: 6.1803, engine.TCD: 453, engine.ACC: 1.2334}
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.TCC: 6.1803, engine.TCD: 453, engine.ACC: 1.2334, engine.ACD: -1, engine.ASR: -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.ACC: 1.00404, engine.ACD: 65.2, engine.ASR: 100, engine.TCC: 5.0202, engine.TCD: 326}
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: 67, engine.ASR: 100, engine.TCC: 1.2534, engine.TCD: 134, engine.ACC: 0.6267}
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)
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].CdrSource != "KAMAILIO_CGR_CALL_END" {
t.Errorf("Unexpected CdrSource for CDR: %+v", reply[0])
}
if reply[0].ReqType != utils.META_PREPAID {
t.Errorf("Unexpected ReqType 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])
}
}
}

View File

@@ -23,6 +23,7 @@ import (
"net/rpc/jsonrpc"
"os"
"path"
"reflect"
"strings"
"testing"
"time"
@@ -71,13 +72,13 @@ func TestTutOsipsCallsResetStorDb(t *testing.T) {
}
}
// start Kam server
// start FS server
func TestTutOsipsCallsStartOsips(t *testing.T) {
if !*testCalls {
return
}
engine.KillProcName("opensips", *waitRater)
if err := engine.CallScript(path.Join(*dataDir, "tutorials", "osips_async", "opensips", "etc", "init.d", "opensips"), "start", 100); err != nil {
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)
}
}
@@ -93,12 +94,12 @@ func TestTutOsipsCallsStartEngine(t *testing.T) {
}
}
// Restart Kam so we make sure reconnects are working
func TestTutOsipsCallsRestartKam(t *testing.T) {
// Restart FS so we make sure reconnects are working
func TestTutOsipsCallsRestartOsips(t *testing.T) {
if !*testCalls {
return
}
if err := engine.CallScript(path.Join(*dataDir, "tutorials", "osips_async", "opensips", "etc", "init.d", "opensips"), "restart", 200); err != nil {
if err := engine.CallScript(path.Join(*dataDir, "tutorials", "osips_async", "opensips", "etc", "init.d", "opensips"), "restart", 3000); err != nil {
t.Fatal(err)
}
}
@@ -172,6 +173,51 @@ func TestTutOsipsCallsAccountsBefore(t *testing.T) {
}
}
// Make sure all stats queues are in place
func TestTutOsipsCallsCdrStatsBefore(t *testing.T) {
if !*testCalls {
return
}
//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) {
if !*testCalls {
@@ -179,12 +225,12 @@ func TestTutOsipsCallsStartPjsuaListener(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"}}
&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, *waitRater); err != nil {
t.Fatal(err)
}
@@ -195,18 +241,29 @@ func TestTutOsipsCallsCall1001To1002(t *testing.T) {
if !*testCalls {
return
}
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",
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 !*testCalls {
return
}
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 !*testCalls {
return
}
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, 5072); err != nil {
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)
}
}
@@ -215,8 +272,8 @@ func TestTutOsipsCallsCall1003To1001(t *testing.T) {
if !*testCalls {
return
}
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, 5073); err != nil {
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)
}
}
@@ -225,8 +282,8 @@ func TestTutOsipsCallsCall1004To1001(t *testing.T) {
if !*testCalls {
return
}
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, 5074); err != nil {
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)
}
}
@@ -235,8 +292,8 @@ func TestTutOsipsCallsCall1006To1002(t *testing.T) {
if !*testCalls {
return
}
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, 5075); err != nil {
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)
}
}
@@ -245,8 +302,8 @@ func TestTutOsipsCallsCall1007To1002(t *testing.T) {
if !*testCalls {
return
}
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, 5076); err != nil {
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)
}
}
@@ -269,17 +326,20 @@ func TestTutOsipsCallsAccount1001(t *testing.T) {
}
// Make sure account was debited properly
func TestTutOsipsCallsCdrs(t *testing.T) {
func TestTutOsipsCalls1001Cdrs(t *testing.T) {
if !*testCalls {
return
}
var reply []*engine.ExternalCdr
req := utils.RpcCdrsFilter{Accounts: []string{"1001"}, RunIds: []string{utils.META_DEFAULT}}
var cgrId string // Share with getCostDetails
var cCost engine.CallCost
req := utils.RpcCdrsFilter{RunIds: []string{utils.META_DEFAULT}, Accounts: []string{"1001"}, DestPrefixes: []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].CdrSource != "OSIPS_E_ACC_EVENT" {
t.Errorf("Unexpected CdrSource for CDR: %+v", reply[0])
}
@@ -289,11 +349,47 @@ func TestTutOsipsCallsCdrs(t *testing.T) {
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"}, DestPrefixes: []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].ReqType != utils.META_PREPAID {
t.Errorf("Unexpected ReqType 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"}, FilterOnRated: true}
if err := tutOsipsCallsRpc.Call("ApierV2.GetCdrs", req, &reply); err != nil {
t.Error("Unexpected error: ", err.Error())
} else if len(reply) != 1 {
} else if len(reply) != 2 {
t.Error("Unexpected number of CDRs returned: ", len(reply))
} else {
if reply[0].ReqType != utils.META_RATED {
@@ -303,7 +399,16 @@ func TestTutOsipsCallsCdrs(t *testing.T) {
t.Errorf("Unexpected Subject for CDR: %+v", reply[0])
}
}
req = utils.RpcCdrsFilter{Accounts: []string{"1002"}, RunIds: []string{utils.META_DEFAULT}}
}
// Make sure account was debited properly
func TestTutOsipsCalls1002Cdrs(t *testing.T) {
if !*testCalls {
return
}
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) != 1 {
@@ -322,7 +427,15 @@ func TestTutOsipsCallsCdrs(t *testing.T) {
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
}
}
req = utils.RpcCdrsFilter{Accounts: []string{"1003"}, RunIds: []string{utils.META_DEFAULT}}
}
// Make sure account was debited properly
func TestTutOsipsCalls1003Cdrs(t *testing.T) {
if !*testCalls {
return
}
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 {
@@ -337,11 +450,20 @@ func TestTutOsipsCallsCdrs(t *testing.T) {
if reply[0].Destination != "1001" {
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
}
if reply[0].Usage != "63" { // Usage as seconds
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])
}
}
req = utils.RpcCdrsFilter{Accounts: []string{"1004"}, RunIds: []string{utils.META_DEFAULT}}
}
// Make sure account was debited properly
func TestTutOsipsCalls1004Cdrs(t *testing.T) {
if !*testCalls {
return
}
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 {
@@ -360,7 +482,16 @@ func TestTutOsipsCallsCdrs(t *testing.T) {
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
}
}
req = utils.RpcCdrsFilter{Accounts: []string{"1006"}, RunIds: []string{utils.META_DEFAULT}}
}
// Make sure account was debited properly
func TestTutOsipsCalls1006Cdrs(t *testing.T) {
if !*testCalls {
return
}
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) != 1 {
@@ -375,11 +506,22 @@ func TestTutOsipsCallsCdrs(t *testing.T) {
if reply[0].Destination != "1002" {
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
}
if reply[0].Usage != "64" { // Usage as seconds
if reply[0].Usage != "64" && reply[0].Usage != "65" { // 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])
}
}
req = utils.RpcCdrsFilter{Accounts: []string{"1007"}, RunIds: []string{utils.META_DEFAULT}}
}
// Make sure account was debited properly
func TestTutOsipsCalls1007Cdrs(t *testing.T) {
if !*testCalls {
return
}
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 {
@@ -394,9 +536,12 @@ func TestTutOsipsCallsCdrs(t *testing.T) {
if reply[0].Destination != "1002" {
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
}
if reply[0].Usage != "66" { // Usage as seconds
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])
}
}
}

View File

@@ -386,7 +386,7 @@ func (fsev FSEvent) AsCallDescriptor() (*engine.CallDescriptor, error) {
Account: fsev.GetAccount(utils.META_DEFAULT),
Subject: fsev.GetSubject(utils.META_DEFAULT),
Destination: fsev.GetDestination(utils.META_DEFAULT),
StartTime: utils.FirstNonEmpty(fsev[SETUP_TIME], fsev[ANSWER_TIME]),
SetupTime: utils.FirstNonEmpty(fsev[SETUP_TIME], fsev[ANSWER_TIME]),
Duration: fsev[DURATION],
}
return lcrReq.AsCallDescriptor()

View File

@@ -381,7 +381,7 @@ func (kev KamEvent) AsCallDescriptor() (*engine.CallDescriptor, error) {
Account: kev.GetAccount(utils.META_DEFAULT),
Subject: kev.GetSubject(utils.META_DEFAULT),
Destination: kev.GetDestination(utils.META_DEFAULT),
StartTime: utils.FirstNonEmpty(kev[CGR_SETUPTIME], kev[CGR_ANSWERTIME]),
SetupTime: utils.FirstNonEmpty(kev[CGR_SETUPTIME], kev[CGR_ANSWERTIME]),
Duration: kev[CGR_DURATION],
}
return lcrReq.AsCallDescriptor()

View File

@@ -1078,7 +1078,8 @@ type AttrSetAccount struct {
Direction string
Account string
ActionPlanId string
AllowNegative bool
AllowNegative *bool
Disabled *bool
}
type AttrRemoveAccount struct {