2024-11-25 19:22:19 +08:00
# include <stdio.h>
# include <sys/time.h>
# include <gtest/gtest.h>
# include <netinet/in.h>
# include "utable/utable.h"
# include "cjson/cJSON.h"
# include "uthash/utarray.h"
# pragma GCC diagnostic ignored "-Wunused-parameter"
# define IPFIX_DEFUALT_VERSION 10
# define GEEDGE_NETWORKS_PEN_NUMBER 54450
# define IPFIX_DEFUALT_PEN_NUMBER GEEDGE_NETWORKS_PEN_NUMBER
# define IPFIX_NONE_PEN_NUMBER -1
# define IPFIX_TEMPLATE_SET_ID 2
# define IPFIX_BUFF_MAX_SIZE 2048
# define IPFIX_ELEMENT_MAX_LEN 32
# ifndef MIN
# define MIN(a, b) (((a) < (b)) ? (a) : (b))
# endif
enum ipfix_type
{
IPFIX_UNSIGNED8 = 0 ,
IPFIX_UNSIGNED16 ,
IPFIX_UNSIGNED32 ,
IPFIX_UNSIGNED64 ,
IPFIX_VARIABLE_STRING ,
IPFIX_UNKNOWN
} ;
struct ipfix_element
{
enum ipfix_type type ;
uint16_t element_id ;
uint16_t value_length ; // if type is variable_string, value_length is 0
int PEN_number ;
char name [ IPFIX_ELEMENT_MAX_LEN ] ;
} ;
struct ipfix_template
{
uint16_t template_id ;
char * name ;
UT_array * elements_array ; // utarray for current template elements
} ;
struct ipfix_worker_context
{
int source_id ;
int sequence ;
size_t template_blob_length ;
char * template_blob ;
} ;
struct ipfix_exporter_schema
{
uint16_t n_worker ;
uint16_t version ;
int domain_id ;
int PEN_number ;
UT_array * templates_array ; // utarray for templates
struct ipfix_worker_context * worker_context_array ; // utarray for worker_context
} ;
struct ipfix_message_head
{
uint16_t version ;
uint16_t length ;
int exporttime ;
int ipfix_message_sequence ;
int domain_id ;
} ;
# define IPFIX_MESSAGE_HEAD_LEN sizeof(struct ipfix_message_head)
# define THREAD_MAX 4
# define TEMPLATE_MAX 13
struct gtest_ipfix_template_info
{
const char * template_name ;
int template_id ;
int n_elements ;
} ;
struct gtest_ipfix_template_info gtest_ipfix_template_info [ TEMPLATE_MAX ] = {
{ " BASE " , 257 , 87 } ,
{ " SSL " , 258 , 98 } ,
{ " HTTP " , 259 , 108 } ,
{ " MAIL " , 260 , 100 } ,
{ " DNS " , 261 , 106 } ,
{ " DTLS " , 262 , 97 } ,
{ " QUIC " , 263 , 90 } ,
{ " FTP " , 264 , 91 } ,
{ " SIP " , 265 , 102 } ,
{ " RTP " , 266 , 91 } ,
{ " SSH " , 267 , 98 } ,
{ " RDP " , 268 , 102 } ,
{ " Stratum " , 269 , 91 } } ;
# define IPFIX_ELEMENT_HEAD_LEN sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t) // element_id + element_length + PEN_number
const char * ipfix_schema_json_path = " ./conf/ipfix_schema.json " ;
int g_domain_id = 1 ;
TEST ( utable_ipfix_exporter_test , ipfix_schema_new_error_path )
{
struct ipfix_exporter_schema * ipfix_schema = utable_ipfix_exporter_schema_new ( ( const char * ) " " , g_domain_id , THREAD_MAX ) ;
ASSERT_TRUE ( ipfix_schema = = NULL ) ;
}
int test_template_blob_len_calculate ( struct ipfix_exporter_schema * ipfix_schema )
{
int template_blob_length = 0 ;
template_blob_length + = IPFIX_MESSAGE_HEAD_LEN ; // message head
template_blob_length + = sizeof ( uint16_t ) + sizeof ( uint16_t ) ; // flow set id + flow set length
for ( unsigned int i = 0 ; i < TEMPLATE_MAX ; i + + )
{
struct ipfix_template * template_item = ( struct ipfix_template * ) utarray_eltptr ( ipfix_schema - > templates_array , i ) ;
template_blob_length + = sizeof ( uint16_t ) + sizeof ( uint16_t ) + utarray_len ( template_item - > elements_array ) * ( IPFIX_ELEMENT_HEAD_LEN ) ; // sizeof(template_id) + sizeof(field_count) + n_elements * sizeof(element_id + element_length + PEN_number)
}
return template_blob_length ;
}
TEST ( utable_ipfix_exporter_test , ipfix_schema_new_check_schema )
{
struct ipfix_exporter_schema * ipfix_schema = utable_ipfix_exporter_schema_new ( ipfix_schema_json_path , g_domain_id , THREAD_MAX ) ;
ASSERT_TRUE ( ipfix_schema ! = NULL ) ;
EXPECT_EQ ( ipfix_schema - > domain_id , 1 ) ;
EXPECT_EQ ( ipfix_schema - > n_worker , THREAD_MAX ) ;
EXPECT_EQ ( utarray_len ( ipfix_schema - > templates_array ) , TEMPLATE_MAX ) ;
EXPECT_EQ ( ipfix_schema - > PEN_number , GEEDGE_NETWORKS_PEN_NUMBER ) ;
EXPECT_EQ ( ipfix_schema - > version , IPFIX_DEFUALT_VERSION ) ;
for ( unsigned int i = 0 ; i < TEMPLATE_MAX ; i + + )
{
struct ipfix_template * template_item = ( struct ipfix_template * ) utarray_eltptr ( ipfix_schema - > templates_array , i ) ;
ASSERT_TRUE ( template_item ! = NULL ) ;
EXPECT_EQ ( template_item - > template_id , gtest_ipfix_template_info [ i ] . template_id ) ;
EXPECT_EQ ( gtest_ipfix_template_info [ i ] . n_elements , utarray_len ( template_item - > elements_array ) ) ;
EXPECT_STREQ ( template_item - > name , gtest_ipfix_template_info [ i ] . template_name ) ;
}
ASSERT_TRUE ( ipfix_schema - > worker_context_array ! = NULL ) ;
for ( int i = 0 ; i < THREAD_MAX ; i + + )
{
EXPECT_EQ ( ipfix_schema - > worker_context_array [ i ] . source_id , ( g_domain_id < < 16 ) + i ) ;
EXPECT_EQ ( ipfix_schema - > worker_context_array [ i ] . sequence , 0 ) ;
ASSERT_TRUE ( ipfix_schema - > worker_context_array [ i ] . template_blob ! = NULL ) ;
EXPECT_EQ ( ipfix_schema - > worker_context_array [ i ] . template_blob_length , test_template_blob_len_calculate ( ipfix_schema ) ) ;
}
utable_ipfix_exporter_schema_free ( ipfix_schema ) ;
}
TEST ( utable_ipfix_exporter_test , ipfix_template_flow_get0_all_elements_check_blob )
{
struct ipfix_exporter_schema * ipfix_schema = utable_ipfix_exporter_schema_new ( ipfix_schema_json_path , g_domain_id , THREAD_MAX ) ;
ASSERT_TRUE ( ipfix_schema ! = NULL ) ;
for ( int i = 0 ; i < THREAD_MAX ; i + + )
{
size_t blob_len = 0 ;
const char * blob = utable_ipfix_template_flow_get0 ( ipfix_schema , i , & blob_len ) ;
ASSERT_TRUE ( blob ! = NULL ) ;
EXPECT_EQ ( blob_len , test_template_blob_len_calculate ( ipfix_schema ) ) ;
// check header
struct ipfix_message_head * header = ( struct ipfix_message_head * ) blob ;
struct ipfix_message_head header_value = { } ;
header_value . version = htons ( header - > version ) ;
header_value . length = htons ( header - > length ) ;
header_value . domain_id = htonl ( header - > domain_id ) ;
header_value . ipfix_message_sequence = htonl ( header - > ipfix_message_sequence ) ;
EXPECT_EQ ( header_value . version , IPFIX_DEFUALT_VERSION ) ;
EXPECT_EQ ( header_value . length , test_template_blob_len_calculate ( ipfix_schema ) ) ;
EXPECT_EQ ( header_value . domain_id , ( g_domain_id < < 16 ) + i ) ;
EXPECT_EQ ( header_value . ipfix_message_sequence , 0 ) ;
size_t offset = 0 ;
offset + = IPFIX_MESSAGE_HEAD_LEN ;
uint16_t flow_set_id = ntohs ( * ( uint16_t * ) ( blob + offset ) ) ;
EXPECT_EQ ( flow_set_id , IPFIX_TEMPLATE_SET_ID ) ; // template set id
offset + = 2 ;
uint16_t flow_set_length = ntohs ( * ( uint16_t * ) ( blob + offset ) ) ;
EXPECT_EQ ( flow_set_length , blob_len - IPFIX_MESSAGE_HEAD_LEN ) ; // template set length
offset + = 2 ;
for ( unsigned int j = 0 ; j < TEMPLATE_MAX ; j + + )
{
uint16_t cur_template_blob_len = sizeof ( uint16_t ) + sizeof ( uint16_t ) + gtest_ipfix_template_info [ j ] . n_elements * IPFIX_ELEMENT_HEAD_LEN ;
ASSERT_LE ( offset + cur_template_blob_len , blob_len ) ;
uint16_t template_id = ntohs ( * ( uint16_t * ) ( blob + offset ) ) ;
EXPECT_EQ ( template_id , gtest_ipfix_template_info [ j ] . template_id ) ; // template id
offset + = 2 ;
uint16_t field_count = ntohs ( * ( uint16_t * ) ( blob + offset ) ) ;
EXPECT_EQ ( field_count , gtest_ipfix_template_info [ j ] . n_elements ) ; // field count
offset + = 2 ;
struct ipfix_template * template_item = ( struct ipfix_template * ) utarray_eltptr ( ipfix_schema - > templates_array , j ) ;
for ( unsigned int p = 0 ; p < ( unsigned int ) gtest_ipfix_template_info [ j ] . n_elements ; p + + )
{
struct ipfix_element * element = ( struct ipfix_element * ) utarray_eltptr ( template_item - > elements_array , p ) ;
uint16_t PEN_number_flag = ntohs ( * ( uint16_t * ) ( blob + offset ) ) & 0x8000 ;
EXPECT_EQ ( PEN_number_flag , 0x8000 ) ; // PEN number flag
uint16_t element_id = ntohs ( * ( uint16_t * ) ( blob + offset ) ) & 0x7fff ;
EXPECT_EQ ( element_id , element - > element_id ) ; // element id
offset + = 2 ;
if ( element - > type = = IPFIX_VARIABLE_STRING )
{
uint16_t element_length = ntohs ( * ( uint16_t * ) ( blob + offset ) ) ;
EXPECT_EQ ( element_length , 65535 ) ; // element length
}
else
{
uint16_t element_length = ntohs ( * ( uint16_t * ) ( blob + offset ) ) ;
EXPECT_EQ ( element_length , element - > value_length ) ; // element length
}
offset + = 2 ;
uint32_t PEN_number = ntohl ( * ( uint32_t * ) ( blob + offset ) ) ;
EXPECT_EQ ( PEN_number , element - > PEN_number ) ; // PEN number
offset + = 4 ;
}
}
}
utable_ipfix_exporter_schema_free ( ipfix_schema ) ;
}
TEST ( utable_ipfix_exporter_test , ipfix_template_flow_get0_all_elements_check_sequence )
{
struct ipfix_exporter_schema * ipfix_schema = utable_ipfix_exporter_schema_new ( ipfix_schema_json_path , g_domain_id , THREAD_MAX ) ;
ASSERT_TRUE ( ipfix_schema ! = NULL ) ;
for ( int i = 0 ; i < THREAD_MAX ; i + + )
{
size_t blob_len = 0 ;
const char * blob = utable_ipfix_template_flow_get0 ( ipfix_schema , i , & blob_len ) ;
ASSERT_TRUE ( blob ! = NULL ) ;
// check header
struct ipfix_message_head * header = ( struct ipfix_message_head * ) blob ;
struct ipfix_message_head header_value = { } ;
header_value . version = htons ( header - > version ) ;
header_value . length = htons ( header - > length ) ;
header_value . domain_id = htonl ( header - > domain_id ) ;
header_value . ipfix_message_sequence = htonl ( header - > ipfix_message_sequence ) ;
EXPECT_EQ ( header_value . version , IPFIX_DEFUALT_VERSION ) ;
EXPECT_EQ ( header_value . length , test_template_blob_len_calculate ( ipfix_schema ) ) ;
EXPECT_EQ ( header_value . domain_id , ( g_domain_id < < 16 ) + i ) ;
EXPECT_EQ ( header_value . ipfix_message_sequence , 0 ) ;
memset ( & header_value , 0 , sizeof ( struct ipfix_message_head ) ) ;
header = NULL ;
blob = NULL ;
// check sequence, utable_ipfix_template_flow_get0 will not increase sequence
blob = utable_ipfix_template_flow_get0 ( ipfix_schema , i , & blob_len ) ;
ASSERT_TRUE ( blob ! = NULL ) ;
// check header
header = ( struct ipfix_message_head * ) blob ;
header_value . ipfix_message_sequence = htonl ( header - > ipfix_message_sequence ) ;
EXPECT_EQ ( header_value . ipfix_message_sequence , 0 ) ;
}
utable_ipfix_exporter_schema_free ( ipfix_schema ) ;
}
TEST ( utable_ipfix_exporter_test , ipfix_template_get_not_found )
{
struct ipfix_exporter_schema * ipfix_schema = utable_ipfix_exporter_schema_new ( ipfix_schema_json_path , g_domain_id , THREAD_MAX ) ;
ASSERT_TRUE ( ipfix_schema ! = NULL ) ;
int template_id = utable_ipfix_template_get ( ipfix_schema , " test " ) ;
EXPECT_EQ ( template_id , - 1 ) ;
utable_ipfix_exporter_schema_free ( ipfix_schema ) ;
}
TEST ( utable_ipfix_exporter_test , ipfix_template_get_check_template_id )
{
struct ipfix_exporter_schema * ipfix_schema = utable_ipfix_exporter_schema_new ( ipfix_schema_json_path , g_domain_id , THREAD_MAX ) ;
ASSERT_TRUE ( ipfix_schema ! = NULL ) ;
int template_id = 0 ;
for ( unsigned int i = 0 ; i < TEMPLATE_MAX ; i + + )
{
template_id = utable_ipfix_template_get ( ipfix_schema , gtest_ipfix_template_info [ i ] . template_name ) ;
EXPECT_EQ ( template_id , i ) ;
struct ipfix_template * template_item = ( struct ipfix_template * ) utarray_eltptr ( ipfix_schema - > templates_array , i ) ;
ASSERT_TRUE ( template_item ! = NULL ) ;
}
utable_ipfix_exporter_schema_free ( ipfix_schema ) ;
}
cJSON * test_ipifx_data_blob_to_cjson ( struct ipfix_template * template_item , char * blob , size_t sz_blob )
{
cJSON * root = cJSON_CreateObject ( ) ;
size_t offset = IPFIX_MESSAGE_HEAD_LEN + sizeof ( uint16_t ) + sizeof ( uint16_t ) ; // skip message head and flow set id and flow set length
size_t n_elements = utarray_len ( template_item - > elements_array ) ;
for ( size_t i = 0 ; i < n_elements ; i + + )
{
struct ipfix_element * p_element = ( struct ipfix_element * ) utarray_eltptr ( template_item - > elements_array , i ) ;
switch ( p_element - > type )
{
case IPFIX_UNSIGNED8 :
{
cJSON_AddNumberToObject ( root , p_element - > name , * ( uint8_t * ) ( blob + offset ) ) ;
offset + = sizeof ( uint8_t ) ;
break ;
}
case IPFIX_UNSIGNED16 :
{
cJSON_AddNumberToObject ( root , p_element - > name , ntohs ( * ( uint16_t * ) ( blob + offset ) ) ) ;
offset + = sizeof ( uint16_t ) ;
break ;
}
case IPFIX_UNSIGNED32 :
{
cJSON_AddNumberToObject ( root , p_element - > name , ntohl ( * ( uint32_t * ) ( blob + offset ) ) ) ;
offset + = sizeof ( uint32_t ) ;
break ;
}
case IPFIX_UNSIGNED64 :
{
cJSON_AddNumberToObject ( root , p_element - > name , be64toh ( * ( uint64_t * ) ( blob + offset ) ) ) ;
offset + = sizeof ( uint64_t ) ;
break ;
}
case IPFIX_VARIABLE_STRING :
{
uint8_t sz_value = * ( uint8_t * ) ( blob + offset ) ;
offset + = sizeof ( uint8_t ) ;
char * string_value = NULL ;
if ( sz_value = = 0 )
{
break ;
}
else if ( sz_value < 255 )
{
string_value = ( char * ) malloc ( sizeof ( char ) * ( sz_value + 1 ) ) ;
memcpy ( string_value , blob + offset , sz_value ) ;
string_value [ sz_value ] = ' \0 ' ;
offset + = sz_value ;
}
else // >= 255
{
uint16_t sz_long_string_value = ntohs ( * ( uint16_t * ) ( blob + offset ) ) ;
offset + = sizeof ( uint16_t ) ;
string_value = ( char * ) malloc ( sizeof ( char ) * ( sz_long_string_value + 1 ) ) ;
memcpy ( string_value , blob + offset , sz_long_string_value ) ;
string_value [ sz_long_string_value ] = ' \0 ' ;
offset + = sz_long_string_value ;
}
cJSON_AddStringToObject ( root , p_element - > name , string_value ) ;
free ( string_value ) ;
break ;
}
default :
break ;
}
}
return root ;
}
// after include before, and the extra part is cJSON_Number, but valueint = 0;
void test_ipfix_compare_cjson ( cJSON * before , cJSON * after )
{
// find before's element in after
cJSON * item = before - > child ;
while ( item ! = NULL )
{
if ( item - > type = = cJSON_Number )
{
cJSON * item_after = cJSON_GetObjectItem ( after , item - > string ) ;
ASSERT_TRUE ( item_after ! = NULL ) ;
EXPECT_EQ ( item - > valueint , item_after - > valueint ) ;
}
if ( item - > type = = cJSON_String )
{
cJSON * item_after = cJSON_GetObjectItem ( after , item - > string ) ;
ASSERT_TRUE ( item_after ! = NULL ) ;
EXPECT_STREQ ( item - > valuestring , item_after - > valuestring ) ;
}
item = item - > next ;
}
// find after's element in before
item = after - > child ;
while ( item ! = NULL )
{
if ( item - > type = = cJSON_Number ) // if after's element is cJSON_Number, before's element may be empty or cJSON_Number
{
cJSON * item_before = cJSON_GetObjectItem ( before , item - > string ) ;
if ( item_before = = NULL ) // if before's element is empty, after's element valueint must be 0
{
EXPECT_EQ ( item - > valueint , 0 ) ;
}
else
{
EXPECT_EQ ( item - > valueint , item_before - > valueint ) ; // if before's element is cJSON_Number, after's element valueint must be equal to before's element valueint
}
}
if ( item - > type = = cJSON_String )
{
cJSON * item_before = cJSON_GetObjectItem ( before , item - > string ) ;
ASSERT_TRUE ( item_before ! = NULL ) ;
EXPECT_STREQ ( item - > valuestring , item_before - > valuestring ) ;
}
item = item - > next ;
}
}
int test_empty_data_blob_len_calculate ( struct ipfix_exporter_schema * ipfix_schema , int template_id )
{
struct ipfix_template * template_item = ( struct ipfix_template * ) utarray_eltptr ( ipfix_schema - > templates_array , ( unsigned int ) template_id ) ;
int data_blob_length = 0 ;
data_blob_length + = IPFIX_MESSAGE_HEAD_LEN ; // message head
data_blob_length + = sizeof ( uint16_t ) + sizeof ( uint16_t ) ; // flow set id + flow set length
for ( unsigned int i = 0 ; i < utarray_len ( template_item - > elements_array ) ; i + + )
{
struct ipfix_element * element = ( struct ipfix_element * ) utarray_eltptr ( template_item - > elements_array , i ) ;
if ( element - > type = = IPFIX_VARIABLE_STRING )
{
data_blob_length + = 1 ;
}
else
{
data_blob_length + = element - > value_length ; // element length
}
}
return data_blob_length ;
}
TEST ( utable_ipfix_exporter_test , ipfix_data_flow_empty_utable_check_blob )
{
struct ipfix_exporter_schema * ipfix_schema = utable_ipfix_exporter_schema_new ( ipfix_schema_json_path , g_domain_id , THREAD_MAX ) ;
ASSERT_TRUE ( ipfix_schema ! = NULL ) ;
for ( unsigned int i = 0 ; i < TEMPLATE_MAX ; i + + )
{
cJSON * before = cJSON_CreateObject ( ) ;
struct utable * table = utable_new ( ) ;
int template_id = utable_ipfix_template_get ( ipfix_schema , gtest_ipfix_template_info [ i ] . template_name ) ;
ASSERT_EQ ( template_id , i ) ;
for ( unsigned int j = 0 ; j < THREAD_MAX ; j + + )
{
size_t blob_len = 0 ;
char * blob = NULL ;
utable_ipfix_data_flow_exporter ( table , ipfix_schema , template_id , j , & blob , & blob_len ) ;
ASSERT_TRUE ( blob ! = NULL ) ;
struct ipfix_message_head * header = ( struct ipfix_message_head * ) blob ;
struct ipfix_message_head header_value = { } ;
header_value . version = htons ( header - > version ) ;
header_value . length = htons ( header - > length ) ;
header_value . domain_id = htonl ( header - > domain_id ) ;
header_value . ipfix_message_sequence = htonl ( header - > ipfix_message_sequence ) ;
ASSERT_EQ ( header_value . version , IPFIX_DEFUALT_VERSION ) ;
ASSERT_EQ ( header_value . length , blob_len ) ;
ASSERT_EQ ( header_value . length , test_empty_data_blob_len_calculate ( ipfix_schema , i ) ) ;
ASSERT_EQ ( header_value . domain_id , ( g_domain_id < < 16 ) + j ) ;
ASSERT_EQ ( header_value . ipfix_message_sequence , i ) ;
cJSON * after = test_ipifx_data_blob_to_cjson ( ( struct ipfix_template * ) utarray_eltptr ( ipfix_schema - > templates_array , i ) , blob , blob_len ) ;
test_ipfix_compare_cjson ( before , after ) ;
cJSON_Delete ( after ) ;
free ( blob ) ;
blob = NULL ;
}
cJSON_Delete ( before ) ;
utable_free ( table ) ;
}
utable_ipfix_exporter_schema_free ( ipfix_schema ) ;
}
TEST ( utable_ipfix_exporter_test , ipfix_data_flow_utable_value_type_integer )
{
struct ipfix_exporter_schema * ipfix_schema = utable_ipfix_exporter_schema_new ( ipfix_schema_json_path , g_domain_id , THREAD_MAX ) ;
ASSERT_TRUE ( ipfix_schema ! = NULL ) ;
cJSON * before = cJSON_CreateObject ( ) ;
struct utable * table = utable_new ( ) ;
utable_add_integer ( table , " session_id " , 123456789 ) ;
cJSON_AddNumberToObject ( before , " session_id " , 123456789 ) ;
unsigned int template_id = utable_ipfix_template_get ( ipfix_schema , " HTTP " ) ;
char * blob = NULL ;
size_t sz_blob = 0 ;
utable_ipfix_data_flow_exporter ( table , ipfix_schema , template_id , 0 , & blob , & sz_blob ) ;
ASSERT_EQ ( sz_blob , test_empty_data_blob_len_calculate ( ipfix_schema , template_id ) ) ; // integer value length has been calculated in test_empty_data_blob_len_calculate
cJSON * after = test_ipifx_data_blob_to_cjson ( ( struct ipfix_template * ) utarray_eltptr ( ipfix_schema - > templates_array , template_id ) , blob , sz_blob ) ;
test_ipfix_compare_cjson ( before , after ) ;
cJSON_Delete ( before ) ;
cJSON_Delete ( after ) ;
utable_free ( table ) ;
free ( blob ) ;
utable_ipfix_exporter_schema_free ( ipfix_schema ) ;
}
TEST ( utable_ipfix_exporter_test , ipfix_data_flow_utable_value_type_cstring )
{
struct ipfix_exporter_schema * ipfix_schema = utable_ipfix_exporter_schema_new ( ipfix_schema_json_path , g_domain_id , THREAD_MAX ) ;
ASSERT_TRUE ( ipfix_schema ! = NULL ) ;
cJSON * before = cJSON_CreateObject ( ) ;
struct utable * table = utable_new ( ) ;
utable_add_integer ( table , " session_id " , 123456789 ) ;
cJSON_AddNumberToObject ( before , " session_id " , 123456789 ) ;
utable_add_cstring ( table , " http_url " , " http://www.baidu.com " , strlen ( " http://www.baidu.com " ) ) ;
cJSON_AddStringToObject ( before , " http_url " , " http://www.baidu.com " ) ;
unsigned int template_id = utable_ipfix_template_get ( ipfix_schema , " HTTP " ) ;
char * blob = NULL ;
size_t sz_blob = 0 ;
utable_ipfix_data_flow_exporter ( table , ipfix_schema , template_id , 0 , & blob , & sz_blob ) ;
ASSERT_EQ ( sz_blob , test_empty_data_blob_len_calculate ( ipfix_schema , template_id ) + strlen ( " http://www.baidu.com " ) ) ; // variable_string length need to be calculated
cJSON * after = test_ipifx_data_blob_to_cjson ( ( struct ipfix_template * ) utarray_eltptr ( ipfix_schema - > templates_array , template_id ) , blob , sz_blob ) ;
test_ipfix_compare_cjson ( before , after ) ;
cJSON_Delete ( before ) ;
cJSON_Delete ( after ) ;
utable_free ( table ) ;
free ( blob ) ;
utable_ipfix_exporter_schema_free ( ipfix_schema ) ;
}
char http_url_test [ ] = " storeapi.app-vtion.com/storeApi/systemApp/checkAppStatus.json?store=com.tcl.appmarket2&mac=3C:59:1E:DC:F8:F4&accessKeyId=1472540256617 " ;
TEST ( utable_ipfix_exporter_test , ipfix_data_flow_variable_string_6000 ) // 6000 bytes > 2 * IPFIX_BUFF_MAX_SIZE, test variable_string length > 255 and realloc
{
struct ipfix_exporter_schema * ipfix_schema = utable_ipfix_exporter_schema_new ( ipfix_schema_json_path , g_domain_id , THREAD_MAX ) ;
ASSERT_TRUE ( ipfix_schema ! = NULL ) ;
char * http_url = NULL ;
struct utable * table = utable_new ( ) ;
cJSON * before = cJSON_CreateObject ( ) ;
utable_add_cstring ( table , " decoded_as " , " HTTP " , strlen ( " HTTP " ) ) ;
cJSON_AddStringToObject ( before , " decoded_as " , " HTTP " ) ;
http_url = ( char * ) malloc ( sizeof ( char ) * 7000 ) ;
int offset = 0 ;
while ( offset < 6000 )
{
memcpy ( http_url + offset , http_url_test , sizeof ( http_url_test ) ) ;
offset + = sizeof ( http_url_test ) ;
}
utable_add_cstring ( table , " http_url " , http_url , offset ) ;
cJSON_AddStringToObject ( before , " http_url " , http_url ) ;
unsigned int template_id = utable_ipfix_template_get ( ipfix_schema , " HTTP " ) ;
char * blob = NULL ;
size_t sz_blob = 0 ;
utable_ipfix_data_flow_exporter ( table , ipfix_schema , template_id , 0 , & blob , & sz_blob ) ;
ASSERT_EQ ( sz_blob , test_empty_data_blob_len_calculate ( ipfix_schema , template_id ) + offset + strlen ( " HTTP " ) + 2 ) ; // variable_string length need to be calculated, if length > 255, length + 2
cJSON * after = test_ipifx_data_blob_to_cjson ( ( struct ipfix_template * ) utarray_eltptr ( ipfix_schema - > templates_array , template_id ) , blob , sz_blob ) ;
test_ipfix_compare_cjson ( before , after ) ;
cJSON_Delete ( before ) ;
cJSON_Delete ( after ) ;
utable_free ( table ) ;
free ( blob ) ;
free ( http_url ) ;
utable_ipfix_exporter_schema_free ( ipfix_schema ) ;
}
TEST ( utable_ipfix_exporter_test , ipfix_data_flow_utable_value_type_integer_array )
{
struct ipfix_exporter_schema * ipfix_schema = utable_ipfix_exporter_schema_new ( ipfix_schema_json_path , g_domain_id , THREAD_MAX ) ;
ASSERT_TRUE ( ipfix_schema ! = NULL ) ;
cJSON * before = cJSON_CreateObject ( ) ;
struct utable * table = utable_new ( ) ;
utable_add_integer ( table , " session_id " , 123456789 ) ;
cJSON_AddNumberToObject ( before , " session_id " , 123456789 ) ;
int64_t monitor_rule_list [ 8 ] = { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 } ;
utable_add_integer_array ( table , " monitor_rule_list " , monitor_rule_list , 8 ) ;
cJSON_AddStringToObject ( before , " monitor_rule_list " , " [1,2,3,4,5,6,7,8] " ) ;
unsigned int template_id = utable_ipfix_template_get ( ipfix_schema , " HTTP " ) ;
char * blob = NULL ;
size_t sz_blob = 0 ;
utable_ipfix_data_flow_exporter ( table , ipfix_schema , template_id , 0 , & blob , & sz_blob ) ;
ASSERT_EQ ( sz_blob , test_empty_data_blob_len_calculate ( ipfix_schema , template_id ) + strlen ( " [1,2,3,4,5,6,7,8] " ) ) ; // variable_string length need to be calculated
cJSON * after = test_ipifx_data_blob_to_cjson ( ( struct ipfix_template * ) utarray_eltptr ( ipfix_schema - > templates_array , template_id ) , blob , sz_blob ) ;
test_ipfix_compare_cjson ( before , after ) ;
cJSON_Delete ( before ) ;
cJSON_Delete ( after ) ;
utable_free ( table ) ;
free ( blob ) ;
utable_ipfix_exporter_schema_free ( ipfix_schema ) ;
}
extern " C " int load_file_to_memory ( const char * file_name , unsigned char * * pp_out , size_t * out_sz ) ;
cJSON * ipfix_init_utable_from_log_json ( struct utable * table , const char * test_json_path , size_t * sz_blob )
{
size_t json_size = 0 ;
unsigned char * json_str = NULL ;
load_file_to_memory ( test_json_path , & json_str , & json_size ) ;
if ( json_str = = NULL | | json_size = = 0 )
{
return NULL ;
}
cJSON * root = NULL ;
root = cJSON_Parse ( ( const char * ) json_str ) ;
cJSON * item = root - > child ;
while ( item ! = NULL )
{
switch ( item - > type )
{
case cJSON_Number :
{
utable_add_integer ( table , item - > string , item - > valueint ) ;
break ;
}
case cJSON_String :
{
int sz_value = strlen ( item - > valuestring ) ;
utable_add_cstring ( table , item - > string , item - > valuestring , sz_value ) ;
if ( sz_value < 255 )
{
* sz_blob + = strlen ( item - > valuestring ) ;
}
else
{
* sz_blob + = ( strlen ( item - > valuestring ) + 2 ) ;
}
break ;
}
case cJSON_Array :
{
cJSON * array_item = cJSON_GetArrayItem ( item , 0 ) ;
size_t array_sz = cJSON_GetArraySize ( item ) ;
if ( array_sz > 0 )
{
if ( array_item - > type = = cJSON_Number )
{
int * array = ( int * ) malloc ( sizeof ( int ) * array_sz ) ;
int64_t * long_array = ( int64_t * ) malloc ( sizeof ( int64_t ) * array_sz ) ;
for ( size_t i = 0 ; i < array_sz ; i + + )
{
array_item = cJSON_GetArrayItem ( item , i ) ;
if ( array_item - > type = = cJSON_Number )
{
array [ i ] = array_item - > valueint ;
long_array [ i ] = array_item - > valueint ;
}
}
utable_add_integer_array ( table , item - > string , long_array , array_sz ) ;
cJSON * json_array = cJSON_CreateIntArray ( ( const int * ) array , array_sz ) ;
cJSON_Delete ( item - > child ) ;
item - > child = NULL ;
2024-11-25 19:23:01 +08:00
item - > type = cJSON_String ;
2024-11-25 19:22:19 +08:00
item - > valuestring = cJSON_PrintUnformatted ( json_array ) ;
cJSON_Delete ( json_array ) ;
free ( array ) ;
free ( long_array ) ;
}
2024-11-25 19:23:01 +08:00
else if ( array_item - > type = = cJSON_String )
2024-11-25 19:22:19 +08:00
{
char * * array = ( char * * ) malloc ( sizeof ( char * ) * array_sz ) ;
size_t * sz_value = ( size_t * ) malloc ( sizeof ( size_t ) * array_sz ) ;
for ( size_t i = 0 ; i < array_sz ; i + + )
{
array_item = cJSON_GetArrayItem ( item , i ) ;
if ( array_item - > type = = cJSON_String )
{
sz_value [ i ] = strlen ( array_item - > valuestring ) ;
array [ i ] = strdup ( array_item - > valuestring ) ;
}
}
utable_add_cstring_array ( table , item - > string , ( const char * * ) array , sz_value , array_sz ) ;
2024-11-25 19:23:01 +08:00
free ( sz_value ) ;
2024-11-25 19:22:19 +08:00
cJSON * json_array = cJSON_CreateStringArray ( ( const char * * ) array , array_sz ) ;
item - > valuestring = cJSON_PrintUnformatted ( json_array ) ;
item - > type = cJSON_String ;
cJSON_Delete ( item - > child ) ;
item - > child = NULL ;
cJSON_Delete ( json_array ) ;
for ( size_t i = 0 ; i < array_sz ; i + + )
{
free ( array [ i ] ) ;
}
free ( array ) ;
}
int sz_value = strlen ( item - > valuestring ) ;
if ( sz_value < 255 )
{
* sz_blob + = sz_value ;
}
else
{
* sz_blob + = ( sz_value + 2 ) ;
}
}
break ;
}
default :
break ;
}
item = item - > next ;
}
free ( json_str ) ;
return root ;
}
const char * ssl_test_json_path = " ./conf/ipfix_ssl_test.json " ;
TEST ( utable_ipfix_exporter_test , ipfix_data_flow_ssl_log_test )
{
struct ipfix_exporter_schema * ipfix_schema = utable_ipfix_exporter_schema_new ( ipfix_schema_json_path , g_domain_id , THREAD_MAX ) ;
ASSERT_TRUE ( ipfix_schema ! = NULL ) ;
struct utable * table = utable_new ( ) ;
unsigned int template_id = utable_ipfix_template_get ( ipfix_schema , " SSL " ) ;
size_t predict_sz_blob = test_empty_data_blob_len_calculate ( ipfix_schema , template_id ) ;
cJSON * before_json_root = ipfix_init_utable_from_log_json ( table , ssl_test_json_path , & predict_sz_blob ) ;
char * blob = NULL ;
size_t sz_blob = 0 ;
utable_ipfix_data_flow_exporter ( table , ipfix_schema , template_id , 0 , & blob , & sz_blob ) ;
ASSERT_EQ ( sz_blob , predict_sz_blob ) ;
cJSON * after_json_root = test_ipifx_data_blob_to_cjson ( ( struct ipfix_template * ) utarray_eltptr ( ipfix_schema - > templates_array , template_id ) , blob , sz_blob ) ;
char * before_json_str = cJSON_Print ( before_json_root ) ;
char * after_json_str = cJSON_Print ( after_json_root ) ;
printf ( " before_json: %s \n " , before_json_str ) ;
printf ( " after_json: %s \n " , after_json_str ) ;
free ( before_json_str ) ;
free ( after_json_str ) ;
test_ipfix_compare_cjson ( before_json_root , after_json_root ) ;
cJSON_Delete ( before_json_root ) ;
cJSON_Delete ( after_json_root ) ;
free ( blob ) ;
utable_free ( table ) ;
utable_ipfix_exporter_schema_free ( ipfix_schema ) ;
}
const char * http_test_json_path = " ./conf/ipfix_http_test.json " ;
TEST ( utable_ipfix_exporter_test , ipfix_data_flow_http_log_test )
{
struct ipfix_exporter_schema * ipfix_schema = utable_ipfix_exporter_schema_new ( ipfix_schema_json_path , g_domain_id , THREAD_MAX ) ;
ASSERT_TRUE ( ipfix_schema ! = NULL ) ;
struct utable * table = utable_new ( ) ;
unsigned int template_id = utable_ipfix_template_get ( ipfix_schema , " HTTP " ) ;
size_t predict_sz_blob = test_empty_data_blob_len_calculate ( ipfix_schema , template_id ) ;
cJSON * before_json_root = ipfix_init_utable_from_log_json ( table , http_test_json_path , & predict_sz_blob ) ;
char * blob = NULL ;
size_t sz_blob = 0 ;
utable_ipfix_data_flow_exporter ( table , ipfix_schema , template_id , 0 , & blob , & sz_blob ) ;
ASSERT_EQ ( sz_blob , predict_sz_blob ) ;
cJSON * after_json_root = test_ipifx_data_blob_to_cjson ( ( struct ipfix_template * ) utarray_eltptr ( ipfix_schema - > templates_array , template_id ) , blob , sz_blob ) ;
test_ipfix_compare_cjson ( before_json_root , after_json_root ) ;
cJSON_Delete ( before_json_root ) ;
cJSON_Delete ( after_json_root ) ;
free ( blob ) ;
utable_free ( table ) ;
utable_ipfix_exporter_schema_free ( ipfix_schema ) ;
}
int main ( int argc , char * argv [ ] )
{
testing : : InitGoogleTest ( & argc , argv ) ;
return RUN_ALL_TESTS ( ) ;
}