diff --git a/data/tutorials/osips_event/cgrates/etc/cgrates/cgrates.cfg b/data/tutorials/osips_event/cgrates/etc/cgrates/cgrates.cfg deleted file mode 100644 index a07150c33..000000000 --- a/data/tutorials/osips_event/cgrates/etc/cgrates/cgrates.cfg +++ /dev/null @@ -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: . - -[scheduler] -enabled = true # Starts Scheduler service: . - -[cdrs] -enabled = true # Start the CDR Server service: . -mediator = internal # Address where to reach the Mediator. Empty for disabling mediation. <""|internal> - -[mediator] -enabled = true # Starts Mediator service: . - -[cdrstats] -enabled = true # Starts the cdrstats service: -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: -switch_type = opensips # Defines the type of switch behind: -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: . -history_dir = /tmp/cgrates/history # Location on disk where to store history files. - -[history_agent] -enabled = true # Starts History as a client: . - diff --git a/data/tutorials/osips_event/cgrates/etc/default/cgrates b/data/tutorials/osips_event/cgrates/etc/default/cgrates deleted file mode 100644 index 789600cdb..000000000 --- a/data/tutorials/osips_event/cgrates/etc/default/cgrates +++ /dev/null @@ -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. - diff --git a/data/tutorials/osips_event/cgrates/etc/init.d/cgrates b/data/tutorials/osips_event/cgrates/etc/init.d/cgrates deleted file mode 100755 index ef33d56b6..000000000 --- a/data/tutorials/osips_event/cgrates/etc/init.d/cgrates +++ /dev/null @@ -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 -# -# 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 - -: diff --git a/data/tutorials/osips_event/opensips/etc/default/opensips b/data/tutorials/osips_event/opensips/etc/default/opensips deleted file mode 100755 index 0671f96a0..000000000 --- a/data/tutorials/osips_event/opensips/etc/default/opensips +++ /dev/null @@ -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 diff --git a/data/tutorials/osips_event/opensips/etc/init.d/opensips b/data/tutorials/osips_event/opensips/etc/init.d/opensips deleted file mode 100755 index c2f22cbed..000000000 --- a/data/tutorials/osips_event/opensips/etc/init.d/opensips +++ /dev/null @@ -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 diff --git a/data/tutorials/osips_event/opensips/etc/opensips/opensips.cfg b/data/tutorials/osips_event/opensips/etc/opensips/opensips.cfg deleted file mode 100644 index d9a888f64..000000000 --- a/data/tutorials/osips_event/opensips/etc/opensips/opensips.cfg +++ /dev/null @@ -1,335 +0,0 @@ -# -# $Id$ -# -# OpenSIPS residential configuration script -# by OpenSIPS Solutions -# -# 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); - - } - -} diff --git a/general_tests/tutorial_kam_calls_test.go b/general_tests/tutorial_kam_calls_test.go index 53002da53..df82f730c 100644 --- a/general_tests/tutorial_kam_calls_test.go +++ b/general_tests/tutorial_kam_calls_test.go @@ -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 diff --git a/general_tests/tutorial_osips_calls_test.go b/general_tests/tutorial_osips_calls_test.go new file mode 100644 index 000000000..9328beeb5 --- /dev/null +++ b/general_tests/tutorial_osips_calls_test.go @@ -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 +*/ + +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) +}