2018-09-27 13:29:07 -04:00
/*
* FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
* Copyright ( C ) 2005 - 2018 , Anthony Minessale II < anthm @ freeswitch . org >
*
* Version : MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 ( the " License " ) ; you may not use this file except in compliance with
* the License . You may obtain a copy of the License at
* http : //www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an " AS IS " basis ,
* WITHOUT WARRANTY OF ANY KIND , either express or implied . See the License
* for the specific language governing rights and limitations under the
* License .
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II < anthm @ freeswitch . org >
* Portions created by the Initial Developer are Copyright ( C )
* the Initial Developer . All Rights Reserved .
*
* Contributor ( s ) :
*
* Chris Rienzo < chris @ signalwire . com >
* Seven Du < seven @ signalwire . com >
*
* switch_test . h - - FreeSWITCH test macros
*/
# ifndef SWITCH_FST_H
# define SWITCH_FST_H
# include <switch.h>
# include <test/switch_fct.h>
2018-10-10 18:40:54 +00:00
/**
* Get environment variable and save to var
*/
static char * fst_getenv_default ( const char * env , char * default_value , switch_bool_t required )
{
char * val = getenv ( env ) ;
if ( ! val ) {
if ( required ) {
fprintf ( stderr , " Failed to start test: environment variable \" %s \" is not set! \n " , env ) ;
exit ( 1 ) ;
}
return default_value ;
}
return val ;
}
2018-09-27 13:29:07 -04:00
/**
* Get environment variable and save to var
*/
# define fst_getenv(env, default_value) \
2018-10-10 18:40:54 +00:00
char * env = fst_getenv_default ( # env , ( char * ) default_value , SWITCH_FALSE ) ;
2018-09-27 13:29:07 -04:00
/**
* Get mandatory environment variable and save to var . Exit with error if missing .
*/
# define fst_getenv_required(env) \
2018-10-10 18:40:54 +00:00
char * env = fst_getenv_default ( # env , NULL , SWITCH_TRUE ) ;
2018-09-27 13:29:07 -04:00
/**
* initialize FS core from optional configuration dir
*/
2019-03-22 16:59:26 +00:00
static switch_status_t fst_init_core_and_modload ( const char * confdir , const char * basedir , int minimal )
2018-09-27 13:29:07 -04:00
{
2019-04-21 12:11:08 -04:00
switch_status_t status ;
2018-09-27 13:29:07 -04:00
const char * err ;
2018-10-04 20:02:08 +00:00
// Let FreeSWITCH core pick these
//SWITCH_GLOBAL_dirs.base_dir = strdup("/usr/local/freeswitch");
//SWITCH_GLOBAL_dirs.mod_dir = strdup("/usr/local/freeswitch/mod");
//SWITCH_GLOBAL_dirs.lib_dir = strdup("/usr/local/freeswitch/lib");
//SWITCH_GLOBAL_dirs.temp_dir = strdup("/tmp");
if ( zstr ( basedir ) ) {
basedir = " . " ;
}
// Allow test to define the runtime dir
2018-09-27 13:29:07 -04:00
if ( ! zstr ( confdir ) ) {
2018-10-15 17:22:05 +03:00
# ifdef SWITCH_TEST_BASE_DIR_FOR_CONF
SWITCH_GLOBAL_dirs . conf_dir = switch_mprintf ( " %s%s%s " , SWITCH_TEST_BASE_DIR_FOR_CONF , SWITCH_PATH_SEPARATOR , confdir ) ;
# else
if ( confdir [ 0 ] ! = ' / ' ) {
SWITCH_GLOBAL_dirs . conf_dir = switch_mprintf ( " .%s%s " , SWITCH_PATH_SEPARATOR , confdir ) ;
} else {
SWITCH_GLOBAL_dirs . conf_dir = strdup ( confdir ) ;
}
# endif
2018-10-04 20:02:08 +00:00
} else {
SWITCH_GLOBAL_dirs . conf_dir = switch_mprintf ( " %s%sconf " , basedir , SWITCH_PATH_SEPARATOR ) ;
2018-09-27 13:29:07 -04:00
}
2018-10-04 20:02:08 +00:00
SWITCH_GLOBAL_dirs . log_dir = switch_mprintf ( " %s%s " , basedir , SWITCH_PATH_SEPARATOR ) ;
SWITCH_GLOBAL_dirs . run_dir = switch_mprintf ( " %s%s " , basedir , SWITCH_PATH_SEPARATOR ) ;
SWITCH_GLOBAL_dirs . recordings_dir = switch_mprintf ( " %s%s " , basedir , SWITCH_PATH_SEPARATOR ) ;
SWITCH_GLOBAL_dirs . sounds_dir = switch_mprintf ( " %s%s " , basedir , SWITCH_PATH_SEPARATOR ) ;
SWITCH_GLOBAL_dirs . cache_dir = switch_mprintf ( " %s%s " , basedir , SWITCH_PATH_SEPARATOR ) ;
SWITCH_GLOBAL_dirs . db_dir = switch_mprintf ( " %s%s " , basedir , SWITCH_PATH_SEPARATOR ) ;
SWITCH_GLOBAL_dirs . script_dir = switch_mprintf ( " %s%s " , basedir , SWITCH_PATH_SEPARATOR ) ;
SWITCH_GLOBAL_dirs . htdocs_dir = switch_mprintf ( " %s%s " , basedir , SWITCH_PATH_SEPARATOR ) ;
SWITCH_GLOBAL_dirs . grammar_dir = switch_mprintf ( " %s%s " , basedir , SWITCH_PATH_SEPARATOR ) ;
SWITCH_GLOBAL_dirs . fonts_dir = switch_mprintf ( " %s%s " , basedir , SWITCH_PATH_SEPARATOR ) ;
SWITCH_GLOBAL_dirs . images_dir = switch_mprintf ( " %s%s " , basedir , SWITCH_PATH_SEPARATOR ) ;
SWITCH_GLOBAL_dirs . storage_dir = switch_mprintf ( " %s%s " , basedir , SWITCH_PATH_SEPARATOR ) ;
SWITCH_GLOBAL_dirs . data_dir = switch_mprintf ( " %s%s " , basedir , SWITCH_PATH_SEPARATOR ) ;
SWITCH_GLOBAL_dirs . localstate_dir = switch_mprintf ( " %s%s " , basedir , SWITCH_PATH_SEPARATOR ) ;
2018-10-15 18:47:31 +03:00
switch_core_set_globals ( ) ;
2018-10-13 00:33:08 +00:00
if ( ! minimal ) {
2019-11-26 22:54:17 +04:00
status = switch_core_init_and_modload ( SCF_USE_SQL , SWITCH_TRUE , & err ) ;
2018-10-13 00:33:08 +00:00
switch_sleep ( 1 * 1000000 ) ;
switch_core_set_variable ( " sound_prefix " , " . " SWITCH_PATH_SEPARATOR ) ;
2019-04-21 12:11:08 -04:00
if ( status ! = SWITCH_STATUS_SUCCESS & & err ) {
fprintf ( stderr , " %s " , err ) ;
}
2019-03-22 16:59:26 +00:00
return status ;
2018-10-13 00:33:08 +00:00
}
2019-04-21 12:11:08 -04:00
status = switch_core_init ( SCF_MINIMAL , SWITCH_TRUE , & err ) ;
if ( status ! = SWITCH_STATUS_SUCCESS & & err ) {
fprintf ( stderr , " %s " , err ) ;
}
return status ;
2018-09-27 13:29:07 -04:00
}
/**
* Park FreeSWITCH session . This is handy when wanting to use switch_core_session_execute_async ( ) on the test session .
* @ param session to park
*/
2018-10-10 18:40:54 +00:00
# define fst_session_park(session) \
switch_ivr_park_session ( session ) ; \
2018-09-27 13:29:07 -04:00
switch_channel_wait_for_state ( switch_core_session_get_channel ( session ) , NULL , CS_PARK ) ;
/**
* check for test requirement - execute teardown on failure
*/
# define fst_requires fct_req
/**
* check for required module - execute teardown on failure
*/
# define fst_requires_module(modname) fct_req(switch_loadable_module_exists(modname) == SWITCH_STATUS_SUCCESS)
/**
* test boolean expression - continue test execution on failure
*/
# define fst_check fct_chk
/**
* test integers for equality - continue test execution on failure
*/
# define fst_check_int_equals fct_chk_eq_int
/**
2019-04-12 20:41:21 -04:00
* test string for equality - continue test execution on failure
2018-09-27 13:29:07 -04:00
*/
# define fst_check_string_equals fct_chk_eq_str
/**
2019-04-12 20:41:21 -04:00
* test string for inequality - continue test execution on failure
2018-09-27 13:29:07 -04:00
*/
# define fst_check_string_not_equals fct_chk_neq_str
2019-04-12 20:41:21 -04:00
/**
* Test string for matching prefix
*/
# define fst_check_string_starts_with fct_chk_startswith_str
/**
* Test string for matching suffix
*/
# define fst_check_string_ends_with fct_chk_endswith_str
/**
* Test string for substring
*/
# define fst_check_string_has fct_chk_incl_str
/**
* Test string for exclusion of substring
*/
# define fst_check_string_does_not_have fct_chk_excl_str
2018-10-09 20:24:55 +00:00
/**
* Mark reference for time measure
*/
# define fst_time_mark() \
fst_time_start = switch_time_now ( ) ;
2018-10-13 00:33:08 +00:00
/**
* Check a test / w error message
*/
# define fst_xcheck(expr, error_msg) \
2019-08-02 15:44:26 +00:00
fct_xchk ( expr , " %s " , error_msg ) ;
2018-10-13 00:33:08 +00:00
/**
* Fail a test
*/
# define fst_fail(error_msg) \
2019-08-02 15:44:26 +00:00
fct_xchk ( 0 , " %s " , error_msg ) ;
2018-10-13 00:33:08 +00:00
2018-10-09 20:24:55 +00:00
/**
* Check duration relative to test start , last marked time , or last check .
*/
# define fst_check_duration(duration_ms, precision_ms) \
{ \
int actual_duration_ms = ( int ) ( ( switch_time_now ( ) - fst_time_start ) / 1000 ) ; \
fct_xchk ( \
abs ( ( actual_duration_ms - duration_ms ) ) < = precision_ms , \
" fst_check_duration: %d != %d +/- %d " , \
( actual_duration_ms ) , \
( duration_ms ) , \
( precision_ms ) \
) ; \
}
/**
* Check if integer is in range
*/
# define fst_check_int_range(actual, expected, precision) \
fct_xchk ( \
2018-10-12 22:00:31 +00:00
abs ( ( actual - expected ) ) < = precision , \
2018-10-09 20:24:55 +00:00
" fst_check_int_range: %d != %d +/- %d " , \
( actual ) , \
( expected ) , \
( precision ) \
) ;
/**
* Check if double - precision number is in range
*/
# define fst_check_double_range(actual, expected, precision) \
fct_xchk ( \
2018-10-12 22:00:31 +00:00
fabs ( ( actual - expected ) ) < = precision , \
2018-10-09 20:24:55 +00:00
" fst_check_double_range: %f != %f +/- %f " , \
( actual ) , \
( expected ) , \
( precision ) \
) ;
2018-09-27 13:29:07 -04:00
2018-10-12 22:00:31 +00:00
/**
* Run test without loading FS core
*/
# define FST_BEGIN() \
FCT_BGN ( ) \
{ \
int fst_core = 0 ; \
switch_time_t fst_time_start = 0 ; \
switch_timer_t fst_timer = { 0 } ; \
switch_memory_pool_t * fst_pool = NULL ; \
2019-04-27 03:34:23 +00:00
int fst_timer_started = 0 ; \
2018-10-12 22:00:31 +00:00
fst_getenv_default ( " FST_SUPPRESS_UNUSED_STATIC_WARNING " , NULL , SWITCH_FALSE ) ; \
if ( fst_core ) { \
2018-10-13 00:33:08 +00:00
fst_init_core_and_modload ( NULL , NULL , 0 ) ; /* shuts up compiler */ \
2018-10-12 22:00:31 +00:00
} \
{ \
# define FST_END() \
} \
if ( fst_time_start ) { \
/* shut up compiler */ \
fst_time_start = 0 ; \
} \
} \
FCT_END ( )
2018-09-27 13:29:07 -04:00
/**
* Define the beginning of a freeswitch core test driver . Only one per test application allowed .
* @ param confdir directory containing freeswitch . xml configuration
*/
# define FST_CORE_BEGIN(confdir) \
FCT_BGN ( ) \
{ \
2019-03-22 16:59:26 +00:00
int fst_core = 0 ; \
2018-10-10 18:40:54 +00:00
switch_time_t fst_time_start = 0 ; \
2018-09-27 13:29:07 -04:00
switch_timer_t fst_timer = { 0 } ; \
switch_memory_pool_t * fst_pool = NULL ; \
2019-04-27 03:34:23 +00:00
int fst_timer_started = 0 ; \
2018-10-10 18:40:54 +00:00
fst_getenv_default ( " FST_SUPPRESS_UNUSED_STATIC_WARNING " , NULL , SWITCH_FALSE ) ; \
2019-04-21 16:43:26 +00:00
if ( fst_init_core_and_modload ( confdir , confdir , 0 ) = = SWITCH_STATUS_SUCCESS ) { \
2019-03-22 16:59:26 +00:00
fst_core = 2 ; \
} else { \
fprintf ( stderr , " Failed to load FS core \n " ) ; \
exit ( 1 ) ; \
} \
2018-10-12 22:00:31 +00:00
{
2018-09-27 13:29:07 -04:00
2018-10-13 00:33:08 +00:00
2018-09-27 13:29:07 -04:00
/**
* Define the end of a freeswitch core test driver .
*/
# define FST_CORE_END() \
2019-04-25 16:47:18 -04:00
switch_core_destroy ( ) ; \
2018-10-10 18:40:54 +00:00
} \
2018-10-12 22:00:31 +00:00
if ( fst_time_start ) { \
/* shut up compiler */ \
fst_time_start = 0 ; \
} \
2018-09-27 13:29:07 -04:00
} \
FCT_END ( )
2018-10-13 00:33:08 +00:00
/**
* Minimal FS core load
*/
2019-11-22 01:14:12 +04:00
# define FST_MINCORE_BEGIN(confdir) \
2018-10-13 00:33:08 +00:00
FCT_BGN ( ) \
{ \
2019-03-22 16:59:26 +00:00
int fst_core = 0 ; \
2018-10-13 00:33:08 +00:00
switch_time_t fst_time_start = 0 ; \
switch_timer_t fst_timer = { 0 } ; \
switch_memory_pool_t * fst_pool = NULL ; \
2019-04-27 03:34:23 +00:00
int fst_timer_started = 0 ; \
2018-10-13 00:33:08 +00:00
fst_getenv_default ( " FST_SUPPRESS_UNUSED_STATIC_WARNING " , NULL , SWITCH_FALSE ) ; \
2019-11-22 01:14:12 +04:00
if ( fst_init_core_and_modload ( confdir , NULL , 1 ) = = SWITCH_STATUS_SUCCESS ) { /* minimal load */ \
2019-03-22 16:59:26 +00:00
fst_core = 1 ; \
} else { \
fprintf ( stderr , " Failed to load FS core \n " ) ; \
exit ( 1 ) ; \
} \
2018-10-13 00:33:08 +00:00
{
# define FST_MINCORE_END FST_CORE_END
2018-09-27 13:29:07 -04:00
/**
* Define the beginning of a FreeSWITCH module test suite . Loads the module for test .
* @ param modname name of module to load .
* @ param suite the name of this test suite
*/
2018-10-15 18:47:31 +03:00
# ifdef WIN32
# define FST_MODULE_BEGIN(modname,suite) \
{ \
const char * fst_test_module = # modname ; \
if ( fst_core & & ! zstr ( fst_test_module ) ) { \
const char * err ; \
2018-10-29 14:03:40 +00:00
switch_loadable_module_load_module ( ( char * ) " ./mod " , ( char * ) fst_test_module , SWITCH_TRUE , & err ) ; \
2018-10-15 18:47:31 +03:00
} \
FCT_FIXTURE_SUITE_BGN ( suite ) ;
# else
2018-09-27 13:29:07 -04:00
# define FST_MODULE_BEGIN(modname,suite) \
2018-10-09 21:35:28 +00:00
{ \
const char * fst_test_module = # modname ; \
2018-10-13 00:33:08 +00:00
if ( fst_core & & ! zstr ( fst_test_module ) ) { \
2018-10-09 21:35:28 +00:00
const char * err ; \
2018-10-29 14:03:40 +00:00
switch_loadable_module_load_module ( ( char * ) " ../.libs " , ( char * ) fst_test_module , SWITCH_TRUE , & err ) ; \
2018-10-09 21:35:28 +00:00
} \
FCT_FIXTURE_SUITE_BGN ( suite ) ;
2018-10-15 18:47:31 +03:00
# endif
2018-09-27 13:29:07 -04:00
/**
* Define the end of a FreeSWITCH module test suite .
*/
2018-10-15 18:47:31 +03:00
# ifdef WIN32
# define FST_MODULE_END() \
FCT_FIXTURE_SUITE_END ( ) ; \
if ( ! zstr ( fst_test_module ) & & switch_loadable_module_exists ( fst_test_module ) = = SWITCH_STATUS_SUCCESS ) { \
const char * err ; \
switch_loadable_module_unload_module ( ( char * ) " ./mod " , ( char * ) fst_test_module , SWITCH_FALSE , & err ) ; \
} \
}
# else
2018-10-09 21:35:28 +00:00
# define FST_MODULE_END() \
FCT_FIXTURE_SUITE_END ( ) ; \
if ( ! zstr ( fst_test_module ) & & switch_loadable_module_exists ( fst_test_module ) = = SWITCH_STATUS_SUCCESS ) { \
const char * err ; \
switch_loadable_module_unload_module ( ( char * ) " ../.libs " , ( char * ) fst_test_module , SWITCH_FALSE , & err ) ; \
} \
}
2018-10-15 18:47:31 +03:00
# endif
2018-09-27 13:29:07 -04:00
/**
* Define the beginning of a test suite not associated with a module .
* @ param suite the name of this test suite
*/
2018-10-01 11:06:34 +08:00
# define FST_SUITE_BEGIN(suite) \
2018-09-27 13:29:07 -04:00
const char * fst_test_module = NULL ; \
FCT_FIXTURE_SUITE_BGN ( suite )
/**
* Define the end of a test suite .
*/
# define FST_SUITE_END FCT_FIXTURE_SUITE_END
/**
* Define the test suite setup . This is run before each test or session test .
*/
2019-04-27 03:34:23 +00:00
# define FST_SETUP_BEGIN() \
FCT_SETUP_BGN ( ) \
if ( fst_core ) { \
switch_core_new_memory_pool ( & fst_pool ) ; \
if ( fst_core > 1 ) { \
fst_timer_started = ( switch_core_timer_init ( & fst_timer , " soft " , 20 , 160 , fst_pool ) = = SWITCH_STATUS_SUCCESS ) ; \
} \
}
2018-09-27 13:29:07 -04:00
/**
* Define the end of test suite setup .
*/
# define FST_SETUP_END FCT_SETUP_END
/**
* Define the test suite teardown . This is run after each test or session test .
*/
# define FST_TEARDOWN_BEGIN() \
FCT_TEARDOWN_BGN ( ) \
2018-10-12 22:00:31 +00:00
if ( fst_core ) { \
2019-04-27 03:34:23 +00:00
if ( fst_pool ) switch_core_destroy_memory_pool ( & fst_pool ) ; \
2018-10-13 00:33:08 +00:00
if ( fst_core > 1 ) { \
2019-04-27 03:34:23 +00:00
if ( fst_timer_started ) switch_core_timer_destroy ( & fst_timer ) ; \
2018-10-13 00:33:08 +00:00
} \
2018-10-12 22:00:31 +00:00
}
2018-09-27 13:29:07 -04:00
/**
* Define the test suite teardown end .
*/
# define FST_TEARDOWN_END FCT_TEARDOWN_END
/**
* Define a test in a test suite .
* Defined vars :
* switch_memory_pool_t * fst_pool ; A memory pool that is torn down on test completion
* switch_core_timer_t * fst_timer ; A 8 kHz , 20 ms soft timer ( 160 samples per frame )
* @ param name the name of this test
*/
# define FST_TEST_BEGIN(name) \
FCT_TEST_BGN ( name ) \
2019-04-26 21:26:37 -04:00
if ( fst_core ) { \
fst_requires ( fst_pool ! = NULL ) ; \
if ( fst_core > 1 ) { \
2019-04-27 03:34:23 +00:00
fst_requires ( fst_timer_started ) ; \
2019-04-26 21:26:37 -04:00
} \
fst_time_mark ( ) ; \
} \
2018-09-27 13:29:07 -04:00
if ( fst_test_module ) { \
fst_requires_module ( fst_test_module ) ; \
}
# define FST_TEST_END FCT_TEST_END
/**
* Define a session test in a test suite . This can be used to test IVR functions .
*
* Records session audio to / tmp / name . wav where name is the name of the test .
*
* Required modules :
* mod_loopback - for null endpoint
* mod_sndfile - for wav file support
*
* Defined vars :
* switch_memory_pool_t * fst_pool ; A memory pool that is torn down on test completion
* switch_core_timer_t * fst_timer ; A 8 kHz , 20 ms soft timer ( 160 samples per frame )
* switch_core_session_t * fst_session ; The outbound null session . L16 , 1 channel , 8 kHz .
* switch_core_session_t * fst_session_pool ; The outbound null session ' s pool .
* switch_channel_t * fst_channel ; The outbound null session ' s channel .
*
* @ param name the name of this test
2018-12-14 10:52:00 +08:00
* @ param rate the rate of the channel
2018-09-27 13:29:07 -04:00
*/
2018-12-14 10:52:00 +08:00
# define FST_SESSION_BEGIN_RATE(name, rate) \
2018-09-27 13:29:07 -04:00
FCT_TEST_BGN ( name ) \
2019-04-26 21:26:37 -04:00
{ \
if ( fst_core ) { \
fst_requires ( fst_pool ! = NULL ) ; \
if ( fst_core > 1 ) { \
2019-04-27 03:34:23 +00:00
fst_requires ( fst_timer_started ) ; \
2019-04-26 21:26:37 -04:00
} \
fst_time_mark ( ) ; \
} \
} \
2018-09-27 13:29:07 -04:00
{ \
switch_core_session_t * fst_session = NULL ; \
switch_event_t * fst_originate_vars = NULL ; \
switch_call_cause_t fst_cause = SWITCH_CAUSE_NORMAL_CLEARING ; \
2018-10-12 22:00:31 +00:00
fst_requires ( fst_core ) ; \
2018-09-27 13:29:07 -04:00
if ( fst_test_module ) { \
fst_requires_module ( fst_test_module ) ; \
} \
fst_requires_module ( " mod_loopback " ) ; \
fst_requires_module ( " mod_sndfile " ) ; \
fst_requires ( switch_core_running ( ) ) ; \
fst_requires ( switch_event_create_plain ( & fst_originate_vars , SWITCH_EVENT_CHANNEL_DATA ) = = SWITCH_STATUS_SUCCESS ) ; \
switch_event_add_header_string ( fst_originate_vars , SWITCH_STACK_BOTTOM , " origination_caller_id_number " , " +15551112222 " ) ; \
2018-12-14 10:52:00 +08:00
switch_event_add_header ( fst_originate_vars , SWITCH_STACK_BOTTOM , " rate " , " %d " , rate ) ; \
2018-09-27 13:29:07 -04:00
if ( switch_ivr_originate ( NULL , & fst_session , & fst_cause , " null/+15553334444 " , 2 , NULL , NULL , NULL , NULL , fst_originate_vars , SOF_NONE , NULL , NULL ) = = SWITCH_STATUS_SUCCESS & & fst_session ) { \
switch_memory_pool_t * fst_session_pool = switch_core_session_get_pool ( fst_session ) ; \
switch_channel_t * fst_channel = switch_core_session_get_channel ( fst_session ) ; \
switch_channel_set_state ( fst_channel , CS_SOFT_EXECUTE ) ; \
switch_channel_wait_for_state ( fst_channel , NULL , CS_SOFT_EXECUTE ) ; \
switch_channel_set_variable ( fst_channel , " send_silence_when_idle " , " -1 " ) ; \
switch_channel_set_variable ( fst_channel , " RECORD_STEREO " , " true " ) ; \
switch_ivr_record_session ( fst_session , ( char * ) " /tmp/ " # name " .wav " , 0 , NULL ) ; \
for ( ; ; ) {
2018-12-14 10:52:00 +08:00
/**
* Define a session test in a test suite . This can be used to test IVR functions .
* See FST_SESSION_BEGIN_RATE
*/
# define FST_SESSION_BEGIN(name) FST_SESSION_BEGIN_RATE(name, 8000)
2018-09-27 13:29:07 -04:00
/* BODY OF TEST CASE HERE */
/**
* Define the end of a session test in a test suite .
* Hangs up session under test .
*/
# define FST_SESSION_END() \
break ; \
} \
if ( switch_channel_ready ( fst_channel ) ) { \
switch_channel_hangup ( fst_channel , SWITCH_CAUSE_NORMAL_CLEARING ) ; \
} \
if ( fst_originate_vars ) { \
switch_event_destroy ( & fst_originate_vars ) ; \
} \
2018-10-10 18:40:54 +00:00
if ( fst_session_pool ) { \
fst_session_pool = NULL ; \
} \
2018-09-27 13:29:07 -04:00
switch_core_session_rwunlock ( fst_session ) ; \
switch_sleep ( 1000000 ) ; \
} \
} \
FCT_TEST_END ( )
/* CORE ASR TEST MACROS */
/**
* Open core ASR for a recognizer module . Opens for L16 , 1 channel , 8 KHz .
*
* Test Requires :
* switch_core_asr_open ( ) = = SWITCH_STATUS_SUCCESS
*
* Defined vars :
* switch_asr_handle_t ah ; Core ASR handle
* switch_asr_flag_t flags ; Core ASR flags used to open recognizer .
* char * fst_asr_result ; Result of last recognition . Allocated from test memory pool .
*
* @ param recognizer name of recognizer to open ( like gcloud_dialogflow )
*
*/
# define fst_test_core_asr_open(recognizer) \
{ \
char * fst_asr_result = NULL ; \
switch_asr_handle_t ah = { 0 } ; \
switch_asr_flag_t flags = SWITCH_ASR_FLAG_NONE ; \
2018-10-13 00:33:08 +00:00
fst_requires ( fst_core > 1 ) ; \
2018-09-27 13:29:07 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " Open recognizer: %s \n " , recognizer ) ; \
/* open ASR interface and feed recorded audio into it and collect result */ \
fst_requires ( switch_core_asr_open ( & ah , recognizer , " L16 " , 8000 , " " , & flags , fst_pool ) = = SWITCH_STATUS_SUCCESS ) ; \
/**
* Execute test on opened recognizer . Reads audio from input file and passes it to the recognizer .
*
* Test Requires :
* switch_core_asr_load_grammar ( grammar ) = = SWITCH_STATUS_SUCCESS
* switch_core_file_open ( input_filename ) = = SWITCH_STATUS_SUCCESS
* switch_core_file_close ( ) = = SWITCH_STATUS_SUCCESS
*
* Test Checks :
* Got result from recognizer .
*
* Test Output :
* fst_asr_result has the xmlstr from switch_core_file_get_results ( )
*
* @ param grammar recognizer grammar
* @ param input_filename name of file containing audio to send to recognizer .
*/
# define fst_test_core_asr(grammar, input_filename) \
{ \
/* feed file into ASR */ \
switch_status_t result ; \
switch_file_handle_t file_handle = { 0 } ; \
2018-10-10 18:40:54 +00:00
uint8_t * buf ; \
size_t len = 160 ; \
int got_result = 0 ; \
fst_asr_result = NULL ; \
2018-09-27 13:29:07 -04:00
file_handle . channels = 1 ; \
file_handle . native_rate = 8000 ; \
2018-10-13 00:33:08 +00:00
fst_requires ( fst_core > 1 ) ; \
2018-10-10 18:40:54 +00:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " Test recognizer: input = %s \n " , input_filename ) ; \
fst_requires ( switch_core_asr_load_grammar ( & ah , grammar , " " ) = = SWITCH_STATUS_SUCCESS ) ; \
2018-09-27 13:29:07 -04:00
fst_requires ( switch_core_file_open ( & file_handle , input_filename , file_handle . channels , 8000 , SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT , NULL ) = = SWITCH_STATUS_SUCCESS ) ; \
2018-10-10 18:40:54 +00:00
buf = ( uint8_t * ) switch_core_alloc ( fst_pool , sizeof ( uint8_t ) * 160 * sizeof ( uint16_t ) * file_handle . channels ) ; \
2018-09-27 13:29:07 -04:00
switch_core_timer_sync ( & fst_timer ) ; \
while ( ( result = switch_core_file_read ( & file_handle , buf , & len ) ) = = SWITCH_STATUS_SUCCESS ) { \
fst_requires ( switch_core_asr_feed ( & ah , buf , len * sizeof ( int16_t ) , & flags ) = = SWITCH_STATUS_SUCCESS ) ; \
switch_core_timer_next ( & fst_timer ) ; \
if ( switch_core_asr_check_results ( & ah , & flags ) = = SWITCH_STATUS_SUCCESS ) { \
2018-10-10 18:40:54 +00:00
char * xmlstr = NULL ; \
switch_event_t * headers = NULL ; \
2018-09-27 13:29:07 -04:00
flags = SWITCH_ASR_FLAG_NONE ; \
/* switch_ivr_detect_speech.. checks one in media bug then again in speech_thread */ \
fst_requires ( switch_core_asr_check_results ( & ah , & flags ) = = SWITCH_STATUS_SUCCESS ) ; \
result = switch_core_asr_get_results ( & ah , & xmlstr , & flags ) ; \
if ( result = = SWITCH_STATUS_SUCCESS ) { \
got_result + + ; \
switch_core_asr_get_result_headers ( & ah , & headers , & flags ) ; \
if ( headers ) { \
switch_event_destroy ( & headers ) ; \
} \
fst_check ( xmlstr ! = NULL ) ; \
if ( xmlstr ! = NULL ) { \
fst_asr_result = switch_core_strdup ( fst_pool , xmlstr ) ; \
} \
switch_safe_free ( xmlstr ) ; \
break ; \
} \
} \
len = 160 ; \
} \
fst_check ( got_result = = 1 ) ; \
fst_requires ( switch_core_file_close ( & file_handle ) = = SWITCH_STATUS_SUCCESS ) ; \
}
/**
* Pause an open recognizer .
*
* Test Requires :
* switch_core_asr_pause ( & ah ) = = SWITCH_STATUS_SUCCESS
*/
# define fst_test_core_asr_pause() \
2018-10-13 00:33:08 +00:00
fst_requires ( fst_core > 1 ) ; \
2018-09-27 13:29:07 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " Pause recognizer \n " ) ; \
flags = SWITCH_ASR_FLAG_NONE ; \
fst_requires ( switch_core_asr_pause ( & ah ) = = SWITCH_STATUS_SUCCESS ) ;
/**
* Resumes an open recognizer
*
* Test Requires :
* switch_core_asr_resume ( & ah ) = = SWITCH_STATUS_SUCCESS
*/
# define fst_test_core_asr_resume() \
2018-10-13 00:33:08 +00:00
fst_requires ( fst_core > 1 ) ; \
2018-09-27 13:29:07 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " Resume recognizer \n " ) ; \
flags = SWITCH_ASR_FLAG_NONE ; \
fst_requires ( switch_core_asr_resume ( & ah ) = = SWITCH_STATUS_SUCCESS ) ;
/**
* Close an open recognizer
*
* Test Requires :
* switch_core_asr_close ( & ah , flags ) = = SWITCH_STATUS_SUCCESS
*/
# define fst_test_core_asr_close() \
2018-10-13 00:33:08 +00:00
fst_requires ( fst_core > 1 ) ; \
2018-09-27 13:29:07 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " Close recognizer \n " ) ; \
flags = SWITCH_ASR_FLAG_NONE ; \
fst_requires ( switch_core_asr_close ( & ah , & flags ) = = SWITCH_STATUS_SUCCESS ) ; \
}
/* PLAY AND DETECT SPEECH TEST MACROS - requires FST_SESSION */
/**
* Define beginning of play_and_detect_speech recognizer test
*
* Defined vars :
* const char * fst_asr_result ; Result of last recognition . Allocated from test memory pool .
*/
# define fst_play_and_detect_speech_test_begin() \
{ \
2018-10-12 22:00:31 +00:00
const char * fst_asr_result = NULL ; \
2018-10-13 00:33:08 +00:00
fst_requires ( fst_core > 1 ) ;
2018-09-27 13:29:07 -04:00
/**
* Use play_and_detect_speech APP to test recognizer
*
* Test Requires :
* switch_ivr_displace_session ( input_filename ) = = SWITCH_STATUS_SUCCESS
* switch_core_session_execute_application ( play_and_detect_speech ) = = SWITCH_STATUS_SUCCESS
2018-10-05 18:43:46 +00:00
* mod_dptools is loaded
2018-09-27 13:29:07 -04:00
*
* Test Checks :
* fst_asr_result ! = NULL after recognition completes
*
* Test Output :
* fst_asr_result has the result from detect_speech_result channel variable .
*
* @ param recognizer name of recognizer
* @ param grammar recognizer grammar
* @ param prompt_filename name of prompt to play
* @ param input_filename name of file containing input audio for the recognizer
*/
2018-10-05 18:43:46 +00:00
# define fst_play_and_detect_speech_app_test(recognizer, grammar, prompt_filename, input_filename) \
2018-09-27 13:29:07 -04:00
{ \
char * args = NULL ; \
2018-10-13 00:33:08 +00:00
fst_requires ( fst_core > 1 ) ; \
2018-10-05 18:43:46 +00:00
fst_requires_module ( " mod_dptools " ) ; \
2018-09-27 13:29:07 -04:00
switch_channel_set_variable ( fst_channel , " detect_speech_result " , " " ) ; \
2018-10-10 18:40:54 +00:00
fst_requires ( switch_ivr_displace_session ( fst_session , input_filename , 0 , " mr " ) = = SWITCH_STATUS_SUCCESS ) ; \
2018-09-27 13:29:07 -04:00
args = switch_core_session_sprintf ( fst_session , " %s detect:%s %s " , prompt_filename , recognizer , grammar ) ; \
fst_requires ( switch_core_session_execute_application ( fst_session , " play_and_detect_speech " , args ) = = SWITCH_STATUS_SUCCESS ) ; \
fst_asr_result = switch_channel_get_variable ( fst_channel , " detect_speech_result " ) ; \
fst_check ( fst_asr_result ! = NULL ) ; \
}
2018-10-05 18:43:46 +00:00
/**
* Use play_and_detect_speech core function to test recognizer
*
* Test Requires :
* switch_ivr_displace_session ( input_filename ) = = SWITCH_STATUS_SUCCESS
*
* Test Checks :
* fst_asr_result ! = NULL after recognition completes
*
* Test Output :
* fst_asr_result has the result from detect_speech_result channel variable .
*
* @ param recognizer name of recognizer
* @ param grammar recognizer grammar
* @ param prompt_filename name of prompt to play
* @ param input_filename name of file containing input audio for the recognizer
* @ param input_args input callback args
*/
# define fst_play_and_detect_speech_test(recognizer, grammar, prompt_filename, input_filename, input_args) \
{ \
char * args = NULL ; \
fst_asr_result = NULL ; \
2018-10-13 00:33:08 +00:00
fst_requires ( fst_core > 1 ) ; \
2018-10-10 18:40:54 +00:00
fst_requires ( switch_ivr_displace_session ( fst_session , input_filename , 0 , " mr " ) = = SWITCH_STATUS_SUCCESS ) ; \
2018-10-05 18:43:46 +00:00
switch_status_t status = switch_ivr_play_and_detect_speech ( fst_session , prompt_filename , recognizer , grammar , ( char * * ) & fst_asr_result , 0 , input_args ) ; \
fst_check ( fst_asr_result ! = NULL ) ; \
}
2018-09-27 13:29:07 -04:00
/**
* Define end of play_and_detect_speech recognizer test
*/
# define fst_play_and_detect_speech_test_end() \
}
2018-10-27 14:19:33 +00:00
/**
* Compare extension dialplan apps and args with expected apps and args
* @ param expected NULL terminated string array of app arg and names .
* const char * expected [ ] = { " playback " , " https://example.com/foo.wav " , " park " , " " , NULL } ;
* @ param extension the switch_caller_extension_t to check
*/
# define fst_check_extension_apps(expected, extension) \
{ \
fst_xcheck ( extension ! = NULL , " Missing extension \n " ) ; \
if ( extension ) { \
int i ; \
switch_caller_application_t * cur_app = extension - > applications ; \
for ( i = 0 ; ; i + = 2 , cur_app = cur_app - > next ) { \
int cur_app_num = i / 2 + 1 ; \
if ( ! expected [ i ] ) { \
if ( cur_app ! = NULL ) { \
fst_fail ( switch_core_sprintf ( fst_pool , " Unexpected application #%d \" %s \" \n " , cur_app_num , cur_app - > application_name ) ) ; \
} \
break ; \
} \
fst_xcheck ( cur_app ! = NULL , switch_core_sprintf ( fst_pool , " Extension application #%d \" %s \" is missing " , cur_app_num , expected [ i ] ) ) ; \
if ( ! cur_app ) { \
break ; \
} \
fst_xcheck ( cur_app - > application_name & & ! strcmp ( expected [ i ] , cur_app - > application_name ) , switch_core_sprintf ( fst_pool , " Expected application #%d name is \" %s \" , but is \" %s \" \n " , cur_app_num , expected [ i ] , cur_app - > application_name ) ) ; \
fst_xcheck ( cur_app - > application_data & & ! strcmp ( expected [ i + 1 ] , cur_app - > application_data ) , switch_core_sprintf ( fst_pool , " Expected application #%d %s data is \" %s \" , but is \" %s \" \n " , cur_app_num , expected [ i ] , expected [ i + 1 ] , cur_app - > application_data ) ) ; \
} \
} \
}
2018-10-05 18:43:46 +00:00
/**
* Inject DTMF into the session to be detected .
*
* Test Requires :
* switch_api_execute ( sched_api ) = = SWITCH_STATUS_SUCCESS
* mod_commands is loaded
*
* @ param when string describing when to send dtmf
* @ param digits to send
*/
# define fst_sched_recv_dtmf(when, digits) \
{ \
switch_stream_handle_t stream = { 0 } ; \
SWITCH_STANDARD_STREAM ( stream ) ; \
2018-10-13 00:33:08 +00:00
fst_requires ( fst_core > 1 ) ; \
2018-10-05 18:43:46 +00:00
fst_requires_module ( " mod_commands " ) ; \
switch_status_t api_result = switch_api_execute ( " sched_api " , switch_core_session_sprintf ( fst_session , " %s none uuid_recv_dtmf %s %s " , when , switch_core_session_get_uuid ( fst_session ) , digits ) , NULL , & stream ) ; \
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( fst_session ) , SWITCH_LOG_INFO , " Injecting DTMF %s at %s \n " , digits , when ) ; \
fst_requires ( api_result = = SWITCH_STATUS_SUCCESS ) ; \
switch_safe_free ( stream . data ) ; \
}
2018-10-06 03:26:04 +00:00
# define fst_xml_start() \
switch_stream_handle_t fst_xml_stream = { 0 } ; \
SWITCH_STANDARD_STREAM ( fst_xml_stream ) ;
int fst_tag_children = 0 ;
int fst_tag_body = 0 ;
# define fst_xml_open_tag(tag_name) \
fst_xml_stream . write_function ( & fst_xml_stream , " <%s " , # tag_name ) ; \
fst_tag_children + + ;
# define fst_xml_attr(attr) \
if ( ! zstr ( attr ) ) fst_xml_stream . write_function ( & fst_xml_stream , " %s= \" %s \" " , # attr , attr ) ;
# define fst_xml_close_tag(tag_name) \
- - fst_tag_children ; \
if ( fst_tag_children > 0 | | fst_tag_body ) { \
fst_xml_stream . write_function ( & fst_xml_stream , " </%s> " , # tag_name ) ; \
} else { \
fst_xml_stream . write_function ( & fst_xml_stream , " /> " ) ; \
} \
fst_tag_body = 0 ;
# define fst_xml_body(body) \
if ( fst_tag_body ) { \
2018-10-17 23:26:04 +08:00
fst_xml_stream . write_function ( & fst_xml_stream , " %s " , body ) ; \
2018-10-06 03:26:04 +00:00
} else { \
fst_tag_body = 1 ; \
fst_xml_stream . write_function ( & fst_xml_stream , " >%s " , body ) ; \
}
# define fst_xml_end() \
switch_xml_parse_str_dynamic ( ( char * ) fst_xml_stream . data , SWITCH_FALSE ) ;
2018-09-27 13:29:07 -04:00
/**
* Parse JSON file and save to varname
*
* Test Requires :
* JSON file can be opened and parsed
*
* Test Output :
* varname points at cJSON object
*
* @ param varname name of var to store the resulting cJSON object
* @ param file name of file to parse
*/
# define fst_parse_json_file(varname, file) \
cJSON * varname = NULL ; \
{ \
char * buf ; \
struct stat s ; \
int size ; \
int fd = open ( file , O_RDONLY ) ; \
fst_requires ( fd > = 0 ) ; \
fstat ( fd , & s ) ; \
buf = malloc ( s . st_size + 1 ) ; \
fst_requires ( buf ) ; \
size = read ( fd , buf , s . st_size ) ; \
fst_requires ( size = = s . st_size ) ; \
close ( fd ) ; \
varname = cJSON_Parse ( buf ) ; \
free ( buf ) ; \
fst_requires ( varname ) ; \
}
# endif