Adding tutorial_osips_calls file, removing obsolete data/tutorials/osips_async, optimizing kam_calls test file

This commit is contained in:
DanB
2015-05-11 08:31:11 +02:00
parent 242b6230f1
commit 2b362b3a4d
8 changed files with 467 additions and 971 deletions

View File

@@ -1,41 +0,0 @@
# Real-time Charging System 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.
[rater]
enabled = true # Enable RaterCDRSExportPath service: <true|false>.
[scheduler]
enabled = true # Starts Scheduler service: <true|false>.
[cdrs]
enabled = true # Start the CDR Server service: <true|false>.
mediator = internal # Address where to reach the Mediator. Empty for disabling mediation. <""|internal>
[mediator]
enabled = true # Starts Mediator service: <true|false>.
[cdrstats]
enabled = true # Starts the cdrstats service: <true|false>
queue_length = 5 # Number of items in the stats buffer
time_window = 5m # Will only keep the CDRs who's call setup time is not older than time.Now()-TimeWindow
[session_manager]
enabled = true # Starts SessionManager service: <true|false>
switch_type = opensips # Defines the type of switch behind: <freeswitch>
cdrs = internal # Address where to reach the CDR server for CDR processing
[opensips]
# listen_udp = 127.0.0.1:2020 # Address where to listen for datagram events coming from OpenSIPS
# mi_addr = 127.0.0.1:8020 # Adress where to reach OpenSIPS mi_datagram module
# reconnects = 3 # Number of attempts on connect failure.
[history_server]
enabled = true # Starts History service: <true|false>.
history_dir = /tmp/cgrates/history # Location on disk where to store history files.
[history_agent]
enabled = true # Starts History as a client: <true|false>.

View File

@@ -1,17 +0,0 @@
# defaults file for CGRateS real-time charging system
# start CGRateS init.d script?
# starts with "true"
ENABLE=true
# Start with specific user/group
#USER=cgrates
#GROUP=cgrates
# what extra options to give cgrates binary?
# See cgr-engine -h for options
ENGINE_OPTS='-config=/usr/share/cgrates/tutorials/osips_event/cgrates/etc/cgrates/cgrates.cfg'
# Don't forget to create an appropriate config file,
# else the CGRateS system will not start.

View File

@@ -1,182 +0,0 @@
#! /bin/sh
### BEGIN INIT INFO
# Provides: cgrates
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: CGRateS real-time charging system
# Description: Control CGRateS - carrier grade real-time charging system
### END INIT INFO
# Author: DanB <danb@cgrates.org>
#
# Do NOT "set -e"
# PATH should only include /usr/* if it runs after the mountnfs.sh script
RUNDIR=/tmp/$NAME/run
PIDFILE=$RUNDIR/cgr-engine.pid
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="CGRateS real-time charging system"
NAME=cgrates
DAEMON=/usr/bin/cgr-engine
USER=cgrates
GROUP=cgrates
TUTFOLDER=/usr/share/cgrates/tutorials/osips_event/cgrates
ENGINE_OPTS=""
PIDFILE=/tmp/cgr-engine_osips_event.pid
SCRIPTNAME=$TUTFOLDER/etc/init.d/$NAME
DEFAULTS=$TUTFOLDER/etc/default/$NAME
ENABLE=false
HISTDIR=/tmp/$NAME/history
CDREDIR=/tmp/$NAME/cdre
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
# Read configuration variable file if it is present
[ -r $DEFAULTS ] && . $DEFAULTS
# Load the VERBOSE setting and other rcS variables
. /lib/init/vars.sh
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions
if [ "$ENABLE" != "true" ]; then
echo "$DESC not yet configured. Edit $DEFAULTS first."
exit 0
fi
# Install the run folder
if [ ! -d $RUNDIR ]; then
mkdir -p $RUNDIR
chown $USER:$GROUP $RUNDIR
fi
# Install the cdre folder
if [ ! -d $CDREDIR ]; then
mkdir -p $CDREDIR
chown $USER:$GROUP $CDREDIR
fi
# Install the history folder
if [ ! -d $HISTDIR ]; then
mkdir -p $HISTDIR
chown $USER:$GROUP $HISTDIR
fi
#
# Function that starts the daemon/service
#
do_start()
{
# Return
# 0 if daemon has been started
# 1 if daemon was already running
# 2 if daemon could not be started
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
|| return 1
start-stop-daemon --start --quiet --pidfile $PIDFILE --make-pidfile --exec $DAEMON --chuid $USER:$GROUP --background -- \
$ENGINE_OPTS \
|| return 2
}
#
# Function that stops the daemon/service
#
do_stop()
{
# Return
# 0 if daemon has been stopped
# 1 if daemon was already stopped
# 2 if daemon could not be stopped
# other if a failure occurred
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE
RETVAL="$?"
[ "$RETVAL" = 2 ] && return 2
# Wait for children to finish too if this is a daemon that forks
# and if the daemon is only ever run from this initscript.
# If the above conditions are not satisfied then add some other code
# that waits for the process to drop all resources that could be
# needed by services started subsequently. A last resort is to
# sleep for some time.
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
[ "$?" = 2 ] && return 2
# Many daemons don't delete their pidfiles when they exit.
rm -f $PIDFILE
return "$RETVAL"
}
#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME
return 0
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
#reload|force-reload)
#
# If do_reload() is not implemented then leave this commented out
# and leave 'force-reload' as an alias for 'restart'.
#
#log_daemon_msg "Reloading $DESC" "$NAME"
#do_reload
#log_end_msg $?
#;;
restart|force-reload)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
exit 3
;;
esac
:

View File

@@ -1,27 +0,0 @@
#
# OpenSIPS startup options
#
# Set to yes to enable opensips, once configured properly.
RUN_OPENSIPS=yes
# User to run as
USER=opensips
# Group to run as
GROUP=opensips
# Amount of shared memory to allocate for the running OpenSIPS server (in Mb)
S_MEMORY=64
# Amount of pkg memory to allocate for the running OpenSIPS server (in Mb)
P_MEMORY=4
# Enable the server to leave a core file when it crashes.
# Set this to 'yes' to enable OpenSIPS to leave a core file when it crashes
# or 'no' to disable this feature. This option is case sensitive and only
# accepts 'yes' and 'no' and only in lowercase letters.
# On some systems (e.g. Ubuntu 6.10, Debian 4.0) it is necessary to specify
# a directory for the core files to get a dump. Look into the opensips
# init file for an example configuration.
DUMP_CORE=no

View File

@@ -1,192 +0,0 @@
#! /bin/sh
#
### BEGIN INIT INFO
# Provides: opensips
# Required-Start: $syslog $network $local_fs $time
# Required-Stop: $syslog $network $local_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start the OpenSIPS SIP server
# Description: Start the OpenSIPS SIP server
### END INIT INFO
#
# TODO:
# The following fields should be added (and completed):
# Should-Start: postgresql mysql radius
# Should-Stop: postgresql mysql radius
PATH=/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/opensips
NAME=opensips
DESC=opensips
TUTFOLDER=/usr/share/cgrates/tutorials/osips_event/opensips
CFGFILE=$TUTFOLDER/etc/opensips/opensips.cfg
M4CFGFILE=$TUTFOLDER/etc/opensips/opensips.m4
M4ARCHIVEDIR=$TUTFOLDER/etc/opensips/archive
HOMEDIR=/var/run/opensips
PIDFILE=$HOMEDIR/$NAME.pid
DEFAULTS=$TUTFOLDER/etc/default/opensips
RUN_OPENSIPS=no
# Do not start opensips if fork=no is set in the config file
# otherwise the boot process will just stop
check_fork ()
{
if grep -q "^[[:space:]]*fork[[:space:]]*=[[:space:]]*no.*" $CFGFILE; then
echo "Not starting $DESC: fork=no specified in config file; run /etc/init.d/opensips debug instead"
exit 1
fi
}
check_opensips_config ()
{
# Check if opensips configuration is valid before starting the server
set +e
out=$($DAEMON -c 2>&1 > /dev/null)
retcode=$?
set -e
if [ "$retcode" != '0' ]; then
echo "Not starting $DESC: invalid configuration file!"
echo -e "\n$out\n"
exit 1
fi
}
create_radius_seqfile ()
{
# Create a radius sequence file to be used by the radius client if
# radius accounting is enabled. This is needed to avoid any issue
# with the file not being writable if opensips first starts as user
# root because DUMP_CORE is enabled and creates this file as user
# root and then later it switches back to user opensips and cannot
# write to the file. If the file exists before opensips starts, it
# won't change it's ownership and will be writable for both root
# and opensips, no matter what options are chosen at install time
RADIUS_SEQ_FILE=/var/run/opensips/opensips_radius.seq
if [ -d /var/run/opensips ]; then
chown ${USER}:${GROUP} /var/run/opensips
if [ ! -f $RADIUS_SEQ_FILE ]; then
touch $RADIUS_SEQ_FILE
fi
chown ${USER}:${GROUP} $RADIUS_SEQ_FILE
chmod 660 $RADIUS_SEQ_FILE
fi
}
test -f $DAEMON || exit 0
# Load startup options if available
if [ -f $DEFAULTS ]; then
. $DEFAULTS || true
fi
if [ "$RUN_OPENSIPS" != "yes" ]; then
echo "OpenSIPS not yet configured. Edit /etc/default/opensips first."
exit 0
fi
set -e
S_MEMORY=$((`echo $S_MEMORY | sed -e 's/[^0-9]//g'`))
P_MEMORY=$((`echo $P_MEMORY | sed -e 's/[^0-9]//g'`))
[ -z "$USER" ] && USER=opensips
[ -z "$GROUP" ] && GROUP=opensips
[ $S_MEMORY -le 0 ] && S_MEMORY=32
[ $P_MEMORY -le 0 ] && P_MEMORY=32
if test "$DUMP_CORE" = "yes" ; then
# set proper ulimit
ulimit -c unlimited
# directory for the core dump files
# COREDIR=/home/corefiles
# [ -d $COREDIR ] || mkdir $COREDIR
# chmod 777 $COREDIR
# echo "$COREDIR/core.%e.sig%s.%p" > /proc/sys/kernel/core_pattern
fi
OPTIONS="-f $CFGFILE -P $PIDFILE -m $S_MEMORY -M $P_MEMORY -u $USER -g $GROUP"
case "$1" in
start|debug)
check_opensips_config
create_radius_seqfile
if [ "$1" != "debug" ]; then
check_fork
fi
# dirs under /var/run can go away on reboots.
mkdir -p "$HOMEDIR"
chmod 775 "$HOMEDIR"
chown "$USER:$GROUP" "$HOMEDIR" >/dev/null 2>&1 || true
# Generate config from M4
if [ -f $M4CFGFILE ]; then
m4 -Q $M4CFGFILE >$CFGFILE.tmp
if [ $? != 0 ]; then
echo "Cannot process m4 macro"
rm "$CFGFILE.tmp"
exit 1
fi
[ -e $CFGFILE ] || touch $CFGFILE
# compare configs
if [ `md5sum $CFGFILE|awk '{print $1}'` != `md5sum $CFGFILE.tmp|awk '{print $1}'` ]; then
mkdir -p "$M4ARCHIVEDIR"
mv "$CFGFILE" "$M4ARCHIVEDIR/$NAME.cfg-`date +%Y%m%d_%H%M%S`"
fi
mv "$CFGFILE.tmp" "$CFGFILE"
chown $USER:$GROUP $CFGFILE
chmod 640 $CFGFILE
fi
echo -n "Starting $DESC: $NAME"
start-stop-daemon --start --quiet --pidfile $PIDFILE \
--exec $DAEMON -- $OPTIONS || echo -n " already running"
echo "."
;;
stop)
echo -n "Stopping $DESC: $NAME"
start-stop-daemon --oknodo --stop --quiet --pidfile $PIDFILE \
--exec $DAEMON
echo "."
;;
restart|force-reload)
check_opensips_config
create_radius_seqfile
echo -n "Restarting $DESC: $NAME"
start-stop-daemon --oknodo --stop --quiet --pidfile \
$PIDFILE --exec $DAEMON
sleep 1
start-stop-daemon --start --quiet --pidfile \
$PIDFILE --exec $DAEMON -- $OPTIONS
echo "."
;;
status)
echo -n "Status of $DESC: "
if [ ! -r "$PIDFILE" ]; then
echo "$NAME is not running."
exit 3
fi
if read pid < "$PIDFILE" && ps -p "$pid" > /dev/null 2>&1; then
echo "$NAME is running."
exit 0
else
echo "$NAME is not running but $PIDFILE exists."
exit 1
fi
;;
*)
N=/etc/init.d/$NAME
echo "Usage: $N {start|stop|restart|force-reload|debug|status}" >&2
exit 1
;;
esac
exit 0

View File

@@ -1,335 +0,0 @@
#
# $Id$
#
# OpenSIPS residential configuration script
# by OpenSIPS Solutions <team@opensips-solutions.com>
#
# This script was generated via "make menuconfig", from
# the "Residential" scenario.
# You can enable / disable more features / functionalities by
# re-generating the scenario with different options.#
#
# Please refer to the Core CookBook at:
# http://www.opensips.org/Resources/DocsCookbooks
# for a explanation of possible statements, functions and parameters.
#
####### Global Parameters #########
debug=3
log_stderror=no
log_facility=LOG_LOCAL0
fork=yes
children=4
auto_aliases=no
disable_tcp=yes
disable_tls=yes
####### Modules Section ########
#set module path
mpath="/usr/lib/opensips/modules"
#### SIGNALING module
loadmodule "signaling.so"
#### StateLess module
loadmodule "sl.so"
#### Transaction Module
loadmodule "tm.so"
modparam("tm", "fr_timer", 5)
modparam("tm", "fr_inv_timer", 30)
modparam("tm", "restart_fr_on_each_reply", 0)
modparam("tm", "onreply_avp_mode", 1)
#### Record Route Module
loadmodule "rr.so"
/* do not append from tag to the RR (no need for this script) */
modparam("rr", "append_fromtag", 0)
#### MAX ForWarD module
loadmodule "maxfwd.so"
#### SIP MSG OPerationS module
loadmodule "sipmsgops.so"
#### FIFO Management Interface
loadmodule "mi_fifo.so"
modparam("mi_fifo", "fifo_name", "/tmp/opensips_fifo")
modparam("mi_fifo", "fifo_mode", 0666)
loadmodule "mi_datagram.so"
modparam("mi_datagram", "socket_name", "udp:127.0.0.1:8020")
#### Eventdatagram module
loadmodule "event_datagram.so"
#### URI module
loadmodule "uri.so"
modparam("uri", "use_uri_table", 0)
#### USeR LOCation module
loadmodule "usrloc.so"
modparam("usrloc", "nat_bflag", "NAT")
modparam("usrloc", "db_mode", 0)
#### REGISTRAR module
loadmodule "registrar.so"
modparam("registrar", "tcp_persistent_flag", "TCP_PERSISTENT")
/* uncomment the next line not to allow more than 10 contacts per AOR */
#modparam("registrar", "max_contacts", 10)
#### DIALOG module
loadmodule "dialog.so"
modparam("dialog", "dlg_match_mode", 1)
modparam("dialog", "default_timeout", 21600) # 6 hours timeout
modparam("dialog", "db_mode", 0)
#### ACCounting module
loadmodule "acc.so"
/* what special events should be accounted ? */
modparam("acc", "early_media", 0)
modparam("acc", "report_cancels", 1)
modparam("acc", "cdr_flag", "CDR")
modparam("acc", "evi_flag", "CDR")
modparam("acc", "evi_missed_flag", "CDR")
modparam("acc", "evi_extra",
"cgr_reqtype=$avp(cgr_reqtype);
cgr_account=$avp(cgr_account);
cgr_subject=$avp(cgr_subject);
cgr_destination=$avp(cgr_destination);
originalUri=$ou")
#### CfgUtils module
loadmodule "cfgutils.so"
#### CacheDB Local
loadmodule "cachedb_local.so"
####### Routing Logic ########
startup_route {
subscribe_event("E_OPENSIPS_START", "udp:127.0.0.1:2020");
raise_event("E_OPENSIPS_START");
}
# main request routing logic
route{
if (!mf_process_maxfwd_header("10")) {
sl_send_reply("483","Too Many Hops");
exit;
}
if (has_totag()) {
# sequential request withing a dialog should
# take the path determined by record-routing
if (loose_route()) {
if (is_method("BYE")) {
#setflag(CDR); # do accounting ...
} else if (is_method("INVITE")) {
# even if in most of the cases is useless, do RR for
# re-INVITEs alos, as some buggy clients do change route set
# during the dialog.
record_route();
}
# route it out to whatever destination was set by loose_route()
# in $du (destination URI).
route(relay);
} else {
if ( is_method("ACK") ) {
if ( t_check_trans() ) {
# non loose-route, but stateful ACK; must be an ACK after
# a 487 or e.g. 404 from upstream server
t_relay();
exit;
} else {
# ACK without matching transaction ->
# ignore and discard
exit;
}
}
sl_send_reply("404","Not here");
}
exit;
}
# CANCEL processing
if (is_method("CANCEL"))
{
if (t_check_trans())
t_relay();
exit;
}
t_check_trans();
if ( !(is_method("REGISTER") ) ) {
if (from_uri==myself)
{
} else {
# if caller is not local, then called number must be local
if (!uri==myself) {
send_reply("403","Rely forbidden");
exit;
}
}
}
# preloaded route checking
if (loose_route()) {
xlog("L_ERR",
"Attempt to route with preloaded Route's [$fu/$tu/$ru/$ci]");
if (!is_method("ACK"))
sl_send_reply("403","Preload Route denied");
exit;
}
# record routing
if (!is_method("REGISTER|MESSAGE"))
record_route();
# account only INVITEs
if (is_method("INVITE")) {
# create dialog with timeout
if ( !create_dialog("B") ) {
send_reply("500","Internal Server Error");
exit;
}
setflag(CDR);
route(CGR_HANDLER);
}
if (!uri==myself) {
append_hf("P-hint: outbound\r\n");
route(relay);
}
# requests for my domain
if (is_method("PUBLISH|SUBSCRIBE"))
{
sl_send_reply("503", "Service Unavailable");
exit;
}
if (is_method("REGISTER"))
{
if ( 0 ) setflag(TCP_PERSISTENT);
if (!save("location"))
sl_reply_error();
exit;
}
if ($rU==NULL) {
# request with no Username in RURI
sl_send_reply("484","Address Incomplete");
exit;
}
# do lookup with method filtering
if (!lookup("location","m")) {
t_newtran();
t_reply("404", "Not Found");
exit;
}
route(relay);
}
route[relay] {
if (!t_relay()) {
send_reply("500","Internal Error");
};
exit;
}
route[CGR_HANDLER] {
# These variables should be populated by script admin on need
$avp(cgr_reqtype)="*rated";
$avp(cgr_account)=$fU;
$avp(cgr_subject)=$fU;
$avp(cgr_destination)=$rU;
switch ($avp(cgr_account)) {
case "1002":
$avp(cgr_reqtype)="*postpaid";
break;
case "1003":
$avp(cgr_reqtype)="*pseudoprepaid";
break;
}
# End of variables population
if $avp(cgr_reqtype)=="*pseudoprepaid" || $avp(cgr_reqtype)=="*prepaid" { #Make sure we got enough balance for the call
$avp(auth_keys) = "cgr_reqtype";
$avp(auth_vals) = $avp(cgr_reqtype);
$avp(auth_keys) = "callid";
$avp(auth_vals) = $ci;
$avp(auth_keys) = "from_tag";
$avp(auth_vals) = $ft;
$avp(auth_keys) = "cgr_account";
$avp(auth_vals) = $avp(cgr_account);
$avp(auth_keys) = "cgr_subject";
$avp(auth_vals) = $avp(cgr_subject);
$avp(auth_keys) = "cgr_destination";
$avp(auth_vals) = $avp(cgr_destination);
$avp(auth_keys) = "created";
$avp(auth_vals) = $Ts;
raise_event("E_CGR_AUTHORIZE", $avp(auth_keys), $avp(auth_vals));
$var(accid) = $ci+";"+$ft+";";
$var(rply_cgr_notify) = $var(accid)+"/"+"cgr_notify"; #Key in localcache for cgr_notify
$var(rply_cgr_maxdur) = $var(accid)+"/"+"cgr_maxdur"; #Key in localcache for cgr_maxdur
$var(ms) = 0;
while($var(ms) < 2000) { # Check for values set every 10 ms for maximum 2 seconds
if cache_fetch("local", "$var(rply_cgr_notify)", $avp(cgr_notify) ) $var(ms) = 2000; # Break out
$var(ms) = $var(ms) + 10;
usleep("10");
}
if $avp(cgr_notify) == NULL { # Cannot check it in switch
sl_send_reply("503","Prepaid controller error on notify");
exit;
}
switch ($avp(cgr_notify)) {
case "SERVER_ERROR":
sl_send_reply("503","Prepaid controller error");
exit;
case "INSUFFICIENT_FUNDS":
sl_send_reply("403", "Payment required");
exit;
}
if !cache_fetch("local", "$var(rply_cgr_maxdur)", $avp(cgr_maxdur) ) {
sl_send_reply("503","Prepaid controller error on maxdur");
exit;
}
$DLG_timeout=$avp(cgr_maxdur);
}
}

View File

@@ -23,7 +23,6 @@ import (
"net/rpc/jsonrpc"
"os"
"path"
"reflect"
"strings"
"testing"
"time"
@@ -131,66 +130,6 @@ func TestTutKamCallsLoadTariffPlanFromFolder(t *testing.T) {
time.Sleep(time.Duration(*waitRater) * time.Millisecond) // Give time for scheduler to execute topups
}
// Check loaded stats
func TestTutKamCallsCacheStats(t *testing.T) {
if !*testCalls {
return
}
var rcvStats *utils.CacheStats
expectedStats := &utils.CacheStats{Destinations: 4, RatingPlans: 3, RatingProfiles: 8, Actions: 6, SharedGroups: 1, RatingAliases: 1, AccountAliases: 1, DerivedChargers: 1}
var args utils.AttrCacheStats
if err := tutKamCallsRpc.Call("ApierV1.GetCacheStats", args, &rcvStats); err != nil {
t.Error("Got error on ApierV1.GetCacheStats: ", err.Error())
} else if !reflect.DeepEqual(expectedStats, rcvStats) {
t.Errorf("Calling ApierV1.GetCacheStats expected: %v, received: %v", expectedStats, rcvStats)
}
}
// Check items age
func TestTutKamCallsGetCachedItemAge(t *testing.T) {
if !*testCalls {
return
}
var rcvAge *utils.CachedItemAge
if err := tutKamCallsRpc.Call("ApierV1.GetCachedItemAge", "1002", &rcvAge); err != nil {
t.Error("Got error on ApierV1.GetCachedItemAge: ", err.Error())
} else if rcvAge.Destination > time.Duration(2)*time.Second {
t.Errorf("Cache too old: %d", rcvAge)
}
if err := tutKamCallsRpc.Call("ApierV1.GetCachedItemAge", "RP_RETAIL1", &rcvAge); err != nil {
t.Error("Got error on ApierV1.GetCachedItemAge: ", err.Error())
} else if rcvAge.RatingPlan > time.Duration(2)*time.Second {
t.Errorf("Cache too old: %d", rcvAge)
}
if err := tutKamCallsRpc.Call("ApierV1.GetCachedItemAge", "*out:cgrates.org:call:*any", &rcvAge); err != nil {
t.Error("Got error on ApierV1.GetCachedItemAge: ", err.Error())
} else if rcvAge.RatingProfile > time.Duration(2)*time.Second {
t.Errorf("Cache too old: %d", rcvAge)
}
if err := tutKamCallsRpc.Call("ApierV1.GetCachedItemAge", "LOG_WARNING", &rcvAge); err != nil {
t.Error("Got error on ApierV1.GetCachedItemAge: ", err.Error())
} else if rcvAge.Action > time.Duration(2)*time.Second {
t.Errorf("Cache too old: %d", rcvAge)
}
if err := tutKamCallsRpc.Call("ApierV1.GetCachedItemAge", "SHARED_A", &rcvAge); err != nil {
t.Error("Got error on ApierV1.GetCachedItemAge: ", err.Error())
} else if rcvAge.SharedGroup > time.Duration(2)*time.Second {
t.Errorf("Cache too old: %d", rcvAge)
}
/*
if err := tutKamCallsRpc.Call("ApierV1.GetCachedItemAge", "1006", &rcvAge); err != nil {
t.Error("Got error on ApierV1.GetCachedItemAge: ", err.Error())
} else if rcvAge.RatingAlias > time.Duration(2)*time.Second {
t.Errorf("Cache too old: %d", rcvAge)
}
if err := tutKamCallsRpc.Call("ApierV1.GetCachedItemAge", "1006", &rcvAge); err != nil {
t.Error("Got error on ApierV1.GetCachedItemAge: ", err.Error())
} else if rcvAge.RatingAlias > time.Duration(2)*time.Second || rcvAge.AccountAlias > time.Duration(2)*time.Second {
t.Errorf("Cache too old: %d", rcvAge)
}
*/
}
// Make sure account was debited properly
func TestTutKamCallsAccountsBefore(t *testing.T) {
if !*testCalls {
@@ -233,122 +172,6 @@ func TestTutKamCallsAccountsBefore(t *testing.T) {
}
}
// Check call costs
func TestTutKamCallsGetCosts(t *testing.T) {
if !*testCalls {
return
}
tStart, _ := utils.ParseDate("2014-08-04T13:00:00Z")
tEnd, _ := utils.ParseDate("2014-08-04T13:00:20Z")
cd := engine.CallDescriptor{
Direction: "*out",
Category: "call",
Tenant: "cgrates.org",
Subject: "1001",
Account: "1001",
Destination: "1002",
DurationIndex: 0,
TimeStart: tStart,
TimeEnd: tEnd,
}
var cc engine.CallCost
if err := tutKamCallsRpc.Call("Responder.GetCost", cd, &cc); err != nil {
t.Error("Got error on Responder.GetCost: ", err.Error())
} else if cc.Cost != 0.6 {
t.Errorf("Calling Responder.GetCost got callcost: %v", cc.Cost)
}
tStart, _ = utils.ParseDate("2014-08-04T13:00:00Z")
tEnd, _ = utils.ParseDate("2014-08-04T13:01:25Z")
cd = engine.CallDescriptor{
Direction: "*out",
Category: "call",
Tenant: "cgrates.org",
Subject: "1001",
Account: "1001",
Destination: "1002",
DurationIndex: 0,
TimeStart: tStart,
TimeEnd: tEnd,
}
if err := tutKamCallsRpc.Call("Responder.GetCost", cd, &cc); err != nil {
t.Error("Got error on Responder.GetCost: ", err.Error())
} else if cc.Cost != 0.6417 {
t.Errorf("Calling Responder.GetCost got callcost: %v", cc.Cost)
}
tStart, _ = utils.ParseDate("2014-08-04T13:00:00Z")
tEnd, _ = utils.ParseDate("2014-08-04T13:00:20Z")
cd = engine.CallDescriptor{
Direction: "*out",
Category: "call",
Tenant: "cgrates.org",
Subject: "1001",
Account: "1001",
Destination: "1003",
DurationIndex: 0,
TimeStart: tStart,
TimeEnd: tEnd,
}
if err := tutKamCallsRpc.Call("Responder.GetCost", cd, &cc); err != nil {
t.Error("Got error on Responder.GetCost: ", err.Error())
} else if cc.Cost != 1 {
t.Errorf("Calling Responder.GetCost got callcost: %v", cc.Cost)
}
tStart, _ = utils.ParseDate("2014-08-04T13:00:00Z")
tEnd, _ = utils.ParseDate("2014-08-04T13:01:25Z")
cd = engine.CallDescriptor{
Direction: "*out",
Category: "call",
Tenant: "cgrates.org",
Subject: "1001",
Account: "1001",
Destination: "1003",
DurationIndex: 0,
TimeStart: tStart,
TimeEnd: tEnd,
}
if err := tutKamCallsRpc.Call("Responder.GetCost", cd, &cc); err != nil {
t.Error("Got error on Responder.GetCost: ", err.Error())
} else if cc.Cost != 1.3 {
t.Errorf("Calling Responder.GetCost got callcost: %v", cc.Cost)
}
tStart, _ = utils.ParseDate("2014-08-04T13:00:00Z")
tEnd, _ = utils.ParseDate("2014-08-04T13:00:20Z")
cd = engine.CallDescriptor{
Direction: "*out",
Category: "call",
Tenant: "cgrates.org",
Subject: "1001",
Account: "1001",
Destination: "1004",
DurationIndex: 0,
TimeStart: tStart,
TimeEnd: tEnd,
}
if err := tutKamCallsRpc.Call("Responder.GetCost", cd, &cc); err != nil {
t.Error("Got error on Responder.GetCost: ", err.Error())
} else if cc.Cost != 1 {
t.Errorf("Calling Responder.GetCost got callcost: %v", cc.Cost)
}
tStart, _ = utils.ParseDate("2014-08-04T13:00:00Z")
tEnd, _ = utils.ParseDate("2014-08-04T13:01:25Z")
cd = engine.CallDescriptor{
Direction: "*out",
Category: "call",
Tenant: "cgrates.org",
Subject: "1001",
Account: "1001",
Destination: "1004",
DurationIndex: 0,
TimeStart: tStart,
TimeEnd: tEnd,
}
if err := tutKamCallsRpc.Call("Responder.GetCost", cd, &cc); err != nil {
t.Error("Got error on Responder.GetCost: ", err.Error())
} else if cc.Cost != 1.3 {
t.Errorf("Calling Responder.GetCost got callcost: %v", cc.Cost)
}
}
func TestTutKamCallsCdrStats(t *testing.T) {
if !*testCalls {
return

View File

@@ -0,0 +1,467 @@
/*
Real-time Charging System for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
This program is free software: you can Storagetribute 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 WITH*out 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"
"strings"
"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) {
if !*testCalls {
return
}
// Init config first
var err error
tutOsipsCallsCfg, err = config.NewCGRConfigFromFolder(path.Join(*dataDir, "tutorials", "kamevapi", "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 !*testCalls {
return
}
if err := engine.InitDataDb(tutOsipsCallsCfg); err != nil {
t.Fatal(err)
}
}
// Wipe out the cdr database
func TestTutOsipsCallsResetStorDb(t *testing.T) {
if !*testCalls {
return
}
if err := engine.InitStorDb(tutOsipsCallsCfg); err != nil {
t.Fatal(err)
}
}
// start Kam 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 {
t.Fatal(err)
}
}
// Start CGR Engine
func TestTutOsipsCallsStartEngine(t *testing.T) {
if !*testCalls {
return
}
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 Kam so we make sure reconnects are working
func TestTutOsipsCallsRestartKam(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 {
t.Fatal(err)
}
}
// Connect rpc client to rater
func TestTutOsipsCallsRpcConn(t *testing.T) {
if !*testCalls {
return
}
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) {
if !*testCalls {
return
}
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) {
if !*testCalls {
return
}
var reply *engine.Account
attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001", Direction: "*out"}
if err := tutOsipsCallsRpc.Call("ApierV1.GetAccount", attrs, &reply); err != nil {
t.Error("Got error on ApierV1.GetAccount: ", err.Error())
} else if reply.BalanceMap[utils.MONETARY+attrs.Direction].GetTotalValue() != 10.0 { // Make sure we debitted
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY+attrs.Direction].GetTotalValue())
}
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1002", Direction: "*out"}
if err := tutOsipsCallsRpc.Call("ApierV1.GetAccount", attrs, &reply); err != nil {
t.Error("Got error on ApierV1.GetAccount: ", err.Error())
} else if reply.BalanceMap[utils.MONETARY+attrs.Direction].GetTotalValue() != 10.0 { // Make sure we debitted
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY+attrs.Direction].GetTotalValue())
}
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1003", Direction: "*out"}
if err := tutOsipsCallsRpc.Call("ApierV1.GetAccount", attrs, &reply); err != nil {
t.Error("Got error on ApierV1.GetAccount: ", err.Error())
} else if reply.BalanceMap[utils.MONETARY+attrs.Direction].GetTotalValue() != 10.0 { // Make sure we debitted
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY+attrs.Direction].GetTotalValue())
}
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1004", Direction: "*out"}
if err := tutOsipsCallsRpc.Call("ApierV1.GetAccount", attrs, &reply); err != nil {
t.Error("Got error on ApierV1.GetAccount: ", err.Error())
} else if reply.BalanceMap[utils.MONETARY+attrs.Direction].GetTotalValue() != 10.0 { // Make sure we debitted
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY+attrs.Direction].GetTotalValue())
}
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1007", Direction: "*out"}
if err := tutOsipsCallsRpc.Call("ApierV1.GetAccount", attrs, &reply); err != nil {
t.Error("Got error on ApierV1.GetAccount: ", err.Error())
} else if reply.BalanceMap[utils.MONETARY+attrs.Direction].GetTotalValue() != 0.0 { // Make sure we debitted
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY+attrs.Direction].GetTotalValue())
}
attrs = &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1005", Direction: "*out"}
if err := tutOsipsCallsRpc.Call("ApierV1.GetAccount", attrs, &reply); err == nil || !strings.HasSuffix(err.Error(), "does not exist") {
t.Error("Got error on ApierV1.GetAccount: %v", err)
}
}
func TestTutOsipsCallsCdrStats(t *testing.T) {
if !*testCalls {
return
}
var queueIds []string
eQueueIds := []string{"*default", "CDRST1", "CDRST_1001", "CDRST_1002", "CDRST_1003", "STATS_SUPPL1", "STATS_SUPPL2"}
if err := tutOsipsCallsRpc.Call("CDRStatsV1.GetQueueIds", "", &queueIds); err != nil {
t.Error("Calling CDRStatsV1.GetQueueIds, got error: ", err.Error())
} else if len(eQueueIds) != len(queueIds) {
t.Errorf("Expecting: %v, received: %v", eQueueIds, queueIds)
}
}
// Start Pjsua as listener and register it to receive calls
func TestTutOsipsCallsStartPjsuaListener(t *testing.T) {
if !*testCalls {
return
}
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 tutOsipsCallsPjSuaListener, err = engine.StartPjsuaListener(acnts, *waitRater); err != nil {
t.Fatal(err)
}
}
// Call from 1001 (prepaid) to 1002
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",
"sip:127.0.0.1:5060", time.Duration(67)*time.Second, 5071); 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 {
t.Fatal(err)
}
}
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 {
t.Fatal(err)
}
}
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 {
t.Fatal(err)
}
}
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 {
t.Fatal(err)
}
}
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 {
t.Fatal(err)
}
}
// Make sure account was debited properly
func TestTutOsipsCallsAccount1001(t *testing.T) {
if !*testCalls {
return
}
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 := tutOsipsCallsRpc.Call("ApierV1.GetAccount", attrs, &reply); err != nil {
t.Error("Got error on ApierV1.GetAccount: ", err.Error())
} else if reply.BalanceMap[utils.MONETARY+attrs.Direction].GetTotalValue() == 10.0 { // Make sure we debitted
t.Errorf("Calling ApierV1.GetBalance received: %f", reply.BalanceMap[utils.MONETARY+attrs.Direction].GetTotalValue())
} else if reply.Disabled == true {
t.Error("Account disabled")
}
}
// Make sure account was debited properly
func TestTutOsipsCallsCdrs(t *testing.T) {
if !*testCalls {
return
}
var reply []*engine.ExternalCdr
req := utils.RpcCdrsFilter{Accounts: []string{"1001"}, 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].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].Usage != "67" { // Usage as seconds
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
}
}
req = utils.RpcCdrsFilter{Accounts: []string{"1001"}, RunIds: []string{"derived_run1"}, FilterOnDerived: true}
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].ReqType != utils.META_RATED {
t.Errorf("Unexpected ReqType for CDR: %+v", reply[0])
}
if reply[0].Subject != "1002" {
t.Errorf("Unexpected Subject for CDR: %+v", reply[0])
}
}
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 {
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_POSTPAID {
t.Errorf("Unexpected ReqType 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])
}
}
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].CdrSource != "KAMAILIO_CGR_CALL_END" {
t.Errorf("Unexpected CdrSource for CDR: %+v", reply[0])
}
if reply[0].ReqType != utils.META_PSEUDOPREPAID {
t.Errorf("Unexpected ReqType for CDR: %+v", reply[0])
}
if reply[0].Destination != "1001" {
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
}
if reply[0].Usage != "63" { // Usage as seconds
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
}
}
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].CdrSource != "KAMAILIO_CGR_CALL_END" {
t.Errorf("Unexpected CdrSource for CDR: %+v", reply[0])
}
if reply[0].ReqType != utils.META_RATED {
t.Errorf("Unexpected ReqType for CDR: %+v", reply[0])
}
if reply[0].Destination != "1001" {
t.Errorf("Unexpected Destination for CDR: %+v", reply[0])
}
if reply[0].Usage != "62" { // Usage as seconds
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
}
}
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 {
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 != "64" { // Usage as seconds
t.Errorf("Unexpected Usage for CDR: %+v", reply[0])
}
}
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].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])
}
}
}
// Make sure account was debited properly
func TestTutOsipsCallsAccountFraud1001(t *testing.T) {
if !*testCalls {
return
}
var reply string
attrAddBlnc := &v1.AttrAddBalance{Tenant: "cgrates.org", Account: "1001", BalanceType: "*monetary", Direction: "*out", 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) {
if !*testCalls {
return
}
var reply *engine.Account
attrs := &utils.AttrGetAccount{Tenant: "cgrates.org", Account: "1001", Direction: "*out"}
if err := tutOsipsCallsRpc.Call("ApierV1.GetAccount", attrs, &reply); err != nil {
t.Error("Got error on ApierV1.GetAccount: ", err.Error())
} else if reply.Disabled == false {
t.Error("Account should be disabled per fraud detection rules.")
}
}
func TestTutOsipsCallsStopPjsuaListener(t *testing.T) {
if !*testCalls {
return
}
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 !*testCalls {
return
}
if err := engine.KillEngine(100); err != nil {
t.Error(err)
}
}
func TestTutOsipsCallsStopOpensips(t *testing.T) {
if !*testCalls {
return
}
engine.KillProcName("opensips", 100)
}