✨ feat(integrate utable): deps/utable
This commit is contained in:
31
deps/utable/test/CMakeLists.txt
vendored
Normal file
31
deps/utable/test/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
include_directories(${CMAKE_SOURCE_DIR}/deps)
|
||||
|
||||
add_executable(gtest_utable
|
||||
unit_test_utable.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
gtest_utable
|
||||
utable
|
||||
gtest
|
||||
)
|
||||
|
||||
add_executable(gtest_ipfix_exporter
|
||||
unit_test_ipfix_exporter.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
gtest_ipfix_exporter
|
||||
utable
|
||||
gtest
|
||||
)
|
||||
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/conf DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/)
|
||||
|
||||
include(GoogleTest)
|
||||
gtest_discover_tests(gtest_utable)
|
||||
|
||||
gtest_discover_tests(gtest_ipfix_exporter
|
||||
TEST_LIST gtest_ipfix_exporter_tests
|
||||
)
|
||||
set_tests_properties(${gtest_ipfix_exporter_tests} PROPERTIES WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/)
|
||||
59
deps/utable/test/conf/ipfix_http_test.json
vendored
Normal file
59
deps/utable/test/conf/ipfix_http_test.json
vendored
Normal file
File diff suppressed because one or more lines are too long
1222
deps/utable/test/conf/ipfix_schema.json
vendored
Normal file
1222
deps/utable/test/conf/ipfix_schema.json
vendored
Normal file
File diff suppressed because it is too large
Load Diff
50
deps/utable/test/conf/ipfix_ssl_test.json
vendored
Normal file
50
deps/utable/test/conf/ipfix_ssl_test.json
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"flags_identify_info": [1,2,3],
|
||||
"security_rule_list": ["aaa","bbb", "ccc"],
|
||||
"tcp_rtt_ms": 61,
|
||||
"ssl_ja3s_hash": "cd5a8d2e276eabf0839bf1a25acc479e",
|
||||
"ssl_version": "v3",
|
||||
"ssl_cn": "*.google.com",
|
||||
"ssl_cert_issuer": "CN=GTS CA 1C3;O=Google Trust Services LLC;C=US;;;;",
|
||||
"ssl_cert_subject": "CN=*.google.com;;;;;;",
|
||||
"ssl_san": "*.google.com;*.appengine.google.com;*.bdn.dev;*.cloud.google.com;*.crowdsource.google.com;*.datacompute.google.com;*.google.ca;*.google.cl;*.google.co.in;*.google.co.jp;*.google.co.uk;*.google.com.ar;*.google.com.au;*.google.com.br;*.google.com.co;*.google.com.mx;*.google.com.tr;*.google.com.vn;*.google.de;*.google.es;*.google.fr;*.google.hu;*.google.it;*.google.nl;*.google.pl;*.google.pt;*.googleadapis.com;*.googleapis.cn;*.googlevideo.com;*.gstatic.cn;*.gstatic-cn.com;*.gstaticcnapps.cn;googlecnapps.cn;*.googlecnapps.cn;googleapps-cn.com;*.googleapps-cn.com;gkecnapps.cn;*.gkecnapps.cn;googledownloads.cn;*.googledownloads.cn;recaptcha.net.cn;*.recaptcha.net.cn;widevine.cn;*.widevine.cn;ampproject.org.cn;*.ampproject.org.cn;ampproject.net.cn;*.ampproject.net.cn;google-analytics-cn.com;*.google-analytics-cn.com;googleadservices-cn.com;*.googleadservices-cn.com;googlevads-cn.com;*.googlevads-cn.com;googleapis-cn.com;*.googleapis-cn.com;googleoptimize-cn.com;*.googleoptimize-cn.com;doubleclick-cn.net;*.doubleclick-cn.net;*.fls.doubleclick-cn.net;*.g.doubleclick-cn.net;doubleclick.cn;*.doubleclick.cn;*.fls.doubleclick.cn;*.g.doubleclick.cn;dartsearch-cn.net;*.dartsearch-cn.net;googletraveladservices-cn.com;*.googletraveladservices-cn.com;googletagservices-cn.com;*.googletagservices-cn.com;googletagmanager-cn.com;*.googletagmanager-cn.com;googlesyndication-cn.com;*.googlesyndication-cn.com;*.safeframe.googlesyndication-cn.com;app-measurement-cn.com;*.app-measurement-cn.com;gvt1-cn.com;*.gvt1-cn.com;gvt2-cn.com;*.gvt2-cn.com;2mdn-cn.net;*.2mdn-cn.net;googleflights-cn.net;*.googleflights-cn.net;admob-cn.com;*.admob-cn.com;*.gstatic.com;*.metric.gstatic.com;*.gvt1.com;*.gcpcdn.gvt1.com;*.gvt2.com;*.gcp.gvt2.com;*.url.google.com;*.youtube-nocookie.com;*.ytimg.com;android.com;*.android.com;*.flash.android.com;g.cn;*.g.cn;g.co;*.g.co;goo.gl;www.goo.gl;google-analytics.com;*.google-analytics.com;google.com;googlecommerce.com;*.googlecommerce.com;ggpht.cn",
|
||||
"in_src_mac": "d4:c1:c8:8f:ac:f0",
|
||||
"in_dest_mac": "d4:c1:c8:98:c7:60",
|
||||
"tcp_client_isn": 2664633009,
|
||||
"tcp_server_isn": 2183931785,
|
||||
"address_type": 4,
|
||||
"client_ip": "196.190.248.0",
|
||||
"server_ip": "142.250.185.34",
|
||||
"client_port": 16986,
|
||||
"server_port": 443,
|
||||
"in_link_id": 0,
|
||||
"out_link_id": 0,
|
||||
"start_timestamp_ms": 1702610615910,
|
||||
"end_timestamp_ms": 1702610615996,
|
||||
"duration_ms": 86,
|
||||
"sent_pkts": 0,
|
||||
"sent_bytes": 0,
|
||||
"received_pkts": 10,
|
||||
"received_bytes": 7246,
|
||||
"tcp_c2s_ip_fragments": 0,
|
||||
"tcp_s2c_ip_fragments": 0,
|
||||
"tcp_c2s_rtx_pkts": 0,
|
||||
"tcp_c2s_rtx_bytes": 0,
|
||||
"tcp_s2c_rtx_pkts": 0,
|
||||
"tcp_s2c_rtx_bytes": 0,
|
||||
"tcp_c2s_o3_pkts": 0,
|
||||
"tcp_s2c_o3_pkts": 0,
|
||||
"tcp_c2s_lost_bytes": 0,
|
||||
"tcp_s2c_lost_bytes": 0,
|
||||
"flags": 0,
|
||||
"decoded_as": "SSL",
|
||||
"decoded_path": "ETHERNET.IPv4.UDP.VXLAN.ETHERNET.IPv4.TCP",
|
||||
"t_vsys_id": 1,
|
||||
"vsys_id": 1,
|
||||
"session_id": 11849422307955,
|
||||
"tcp_handshake_latency_ms": 37,
|
||||
"server_os_desc": "Android",
|
||||
"device_tag": "{\"tags\":[{\"tag\":\"device_id\",\"value\":\"device_1\"}]}",
|
||||
"sled_ip": "127.0.0.1",
|
||||
"dup_traffic_flag": 0
|
||||
}
|
||||
802
deps/utable/test/unit_test_ipfix_exporter.cpp
vendored
Normal file
802
deps/utable/test/unit_test_ipfix_exporter.cpp
vendored
Normal file
@@ -0,0 +1,802 @@
|
||||
|
||||
#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->type = cJSON_String;
|
||||
item->child = NULL;
|
||||
item->valuestring = cJSON_PrintUnformatted(json_array);
|
||||
cJSON_Delete(json_array);
|
||||
|
||||
free(array);
|
||||
free(long_array);
|
||||
}
|
||||
if (array_item->type == cJSON_String)
|
||||
{
|
||||
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);
|
||||
|
||||
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();
|
||||
}
|
||||
773
deps/utable/test/unit_test_utable.cpp
vendored
Normal file
773
deps/utable/test/unit_test_utable.cpp
vendored
Normal file
@@ -0,0 +1,773 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "base64/b64.h"
|
||||
#include "utable/utable.h"
|
||||
#include "cjson/cJSON.h"
|
||||
#include "mpack/mpack.h"
|
||||
|
||||
|
||||
|
||||
void test_utable_assert_arr(const struct utable *table, const char *key, int64_t expected_arr[], size_t n_expected_arr)
|
||||
{
|
||||
int64_t *arr = NULL;
|
||||
size_t n_arr = 0;
|
||||
EXPECT_EQ(utable_get_value_type(table, key), utable_value_type_integer_array);
|
||||
utable_get0_integer_value_array(table, key, &arr, &n_arr);
|
||||
EXPECT_EQ(n_arr, n_expected_arr);
|
||||
for (size_t i = 0; i < n_arr; i++) {
|
||||
EXPECT_EQ(expected_arr[i], arr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void test_utable_assert_str(const struct utable *table, const char *key, const char *expected_str)
|
||||
{
|
||||
char *str = NULL;
|
||||
size_t str_len = 0;
|
||||
EXPECT_EQ(utable_get_value_type(table, key), utable_value_type_cstring);
|
||||
utable_get0_cstring_value(table, key, &str, &str_len);
|
||||
EXPECT_EQ(str_len, strlen(expected_str));
|
||||
EXPECT_EQ(strncmp(str, expected_str, str_len), 0);
|
||||
}
|
||||
|
||||
void test_utable_assert_str_array(const struct utable *table, const char *key, const char **expected_str_array, size_t n_expected_str)
|
||||
{
|
||||
char **str_array = NULL;
|
||||
size_t *str_len = NULL;
|
||||
size_t n_str = 0;
|
||||
EXPECT_EQ(utable_get_value_type(table, key), utable_value_type_cstring_array);
|
||||
utable_get0_cstring_value_array(table, key, &str_array, &str_len, &n_str);
|
||||
EXPECT_EQ(n_str, n_expected_str);
|
||||
for (size_t i = 0; i < n_str; i++) {
|
||||
EXPECT_EQ(str_len[i], strlen(expected_str_array[i]));
|
||||
EXPECT_EQ(strncmp(str_array[i], expected_str_array[i], str_len[i]), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void test_utable_assert_blob(const struct utable *table, const char *key, const char *expected_blob, size_t expected_blob_len)
|
||||
{
|
||||
char *blob = NULL;
|
||||
size_t blob_len = 0;
|
||||
EXPECT_EQ(utable_get_value_type(table, key), utable_value_type_blob);
|
||||
utable_get0_blob_value(table, key, &blob, &blob_len);
|
||||
EXPECT_EQ(blob_len, expected_blob_len);
|
||||
EXPECT_EQ(memcmp(blob, expected_blob, blob_len), 0);
|
||||
}
|
||||
|
||||
TEST(utable_test, new_del_when_empty)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
ASSERT_TRUE(table != NULL);
|
||||
utable_free(table);
|
||||
}
|
||||
|
||||
TEST(utable_test, add_1_int_and_query)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
int64_t int_array[] = { 1 };
|
||||
utable_add_integer_array(table, "key", int_array, 1);
|
||||
|
||||
test_utable_assert_arr(table, "key", int_array, 1);
|
||||
|
||||
struct utable_stat A={};
|
||||
struct utable_stat B={};
|
||||
B.n_item=1;
|
||||
B.n_item_size=strlen("key")+sizeof(int64_t);
|
||||
B.n_integer_array=1;
|
||||
B.n_integer_array_size=sizeof(int64_t);
|
||||
utable_stat(table, &A);
|
||||
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
|
||||
|
||||
utable_free(table);
|
||||
}
|
||||
|
||||
TEST(utable_test, add_2_int_and_query)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
int64_t int_array[] = { 1, 2 };
|
||||
utable_add_integer_array(table, "key", int_array, 2);
|
||||
test_utable_assert_arr(table, "key", int_array, 2);
|
||||
|
||||
struct utable_stat A={};
|
||||
struct utable_stat B={};
|
||||
B.n_item=1;
|
||||
B.n_item_size=strlen("key")+sizeof(int64_t)*2;
|
||||
B.n_integer_array=1;
|
||||
B.n_integer_array_size=sizeof(int64_t)*2;
|
||||
utable_stat(table, &A);
|
||||
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
|
||||
|
||||
utable_free(table);
|
||||
}
|
||||
|
||||
TEST(utable_test, add_string_and_query)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
const char *str = "hello world";
|
||||
utable_add_cstring(table, "key", str, strlen(str));
|
||||
test_utable_assert_str(table, "key", str);
|
||||
|
||||
struct utable_stat A={};
|
||||
struct utable_stat B={};
|
||||
B.n_item=1;
|
||||
B.n_item_size=strlen("key")+strlen(str);
|
||||
B.n_cstring=1;
|
||||
B.n_cstring_size=strlen(str);
|
||||
utable_stat(table, &A);
|
||||
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
|
||||
|
||||
utable_free(table);
|
||||
}
|
||||
|
||||
TEST(utable_test, add_string_array_and_query)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
const char *str[] = {"hello world", "foo bar"};
|
||||
size_t n_str=sizeof(str)/sizeof(str[0]);
|
||||
size_t str_sz[] = {strlen(str[0]), strlen(str[1])};
|
||||
utable_add_cstring_array(table, "key", str, str_sz, n_str);
|
||||
test_utable_assert_str_array(table, "key", str, n_str);
|
||||
|
||||
struct utable_stat A={};
|
||||
struct utable_stat B={};
|
||||
B.n_item=1;
|
||||
B.n_item_size=strlen("key")+str_sz[0]+str_sz[1];
|
||||
B.n_cstring_array=1;
|
||||
B.n_cstring_array_size=str_sz[0]+str_sz[1];
|
||||
utable_stat(table, &A);
|
||||
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
|
||||
|
||||
utable_free(table);
|
||||
}
|
||||
|
||||
TEST(utable_test, add_blob_and_query)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
const char *blob = "hello world";
|
||||
size_t blob_len = strlen(blob);
|
||||
utable_add_blob(table, "key", blob, blob_len);
|
||||
test_utable_assert_blob(table, "key", blob, blob_len);
|
||||
|
||||
struct utable_stat A={};
|
||||
struct utable_stat B={};
|
||||
B.n_item=1;
|
||||
B.n_item_size=strlen("key")+blob_len;
|
||||
B.n_blob=1;
|
||||
B.n_blob_size=blob_len;
|
||||
utable_stat(table, &A);
|
||||
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
|
||||
|
||||
utable_free(table);
|
||||
}
|
||||
|
||||
void test_utable_check_if_value_in_json(cJSON *tag_obj, const char *key, const std::string &value)
|
||||
{
|
||||
cJSON *tag_val = cJSON_GetObjectItem(tag_obj, key);
|
||||
EXPECT_NE(tag_val, nullptr);
|
||||
EXPECT_STREQ(tag_val->valuestring, value.c_str());
|
||||
}
|
||||
|
||||
void test_utable_check_if_value_in_json(cJSON *tag_obj, const char *key, const char *value[], size_t n_value)
|
||||
{
|
||||
cJSON *tag_val = cJSON_GetObjectItem(tag_obj, key);
|
||||
EXPECT_NE(tag_val, nullptr);
|
||||
EXPECT_EQ(tag_val->type, cJSON_Array);
|
||||
int arr_size = cJSON_GetArraySize(tag_val);
|
||||
EXPECT_EQ(arr_size, n_value);
|
||||
for (int i = 0; i < arr_size; i++) {
|
||||
cJSON *arr_item = cJSON_GetArrayItem(tag_val, i);
|
||||
EXPECT_STREQ(arr_item->valuestring, value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void test_utable_check_if_value_in_json(cJSON *tag_obj, const char *key, int64_t value[], size_t n_value)
|
||||
{
|
||||
cJSON *tag_val = cJSON_GetObjectItem(tag_obj, key);
|
||||
EXPECT_NE(tag_val, nullptr);
|
||||
EXPECT_EQ(tag_val->type, cJSON_Array);
|
||||
int arr_size = cJSON_GetArraySize(tag_val);
|
||||
EXPECT_EQ(arr_size, n_value);
|
||||
for (int i = 0; i < arr_size; i++) {
|
||||
cJSON *arr_item = cJSON_GetArrayItem(tag_val, i);
|
||||
EXPECT_EQ(arr_item->valueint, value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void test_utable_check_if_value_in_json(cJSON *tag_obj, const char *key, const char *value, size_t blob_len)
|
||||
{
|
||||
cJSON *tag_val = cJSON_GetObjectItem(tag_obj, key);
|
||||
EXPECT_NE(tag_val, nullptr);
|
||||
// the tag_val is encoded in base64
|
||||
size_t dec_size = 0;
|
||||
unsigned char *dec = b64_decode_ex(tag_val->valuestring, strlen(tag_val->valuestring), &dec_size);
|
||||
EXPECT_EQ(dec_size, blob_len);
|
||||
EXPECT_EQ(memcmp(dec, value, blob_len), 0);
|
||||
|
||||
free(dec);
|
||||
}
|
||||
|
||||
TEST(utable_test, export_json)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
int64_t int_array[] = { 1, 2 };
|
||||
const char *str = "hello world";
|
||||
const char *blob = "bin hello world";
|
||||
|
||||
const char *str_array[] = {"hello world", "foo bar"};
|
||||
size_t n_str=sizeof(str_array)/sizeof(str_array[0]);
|
||||
size_t str_sz[] = {strlen(str_array[0]), strlen(str_array[1])};
|
||||
|
||||
utable_add_integer_array(table, "key1", int_array, 2);
|
||||
utable_add_cstring(table, "key2", str, strlen(str));
|
||||
utable_add_blob(table, "key3", blob, strlen(blob));
|
||||
utable_add_cstring_array(table, "key4", str_array, str_sz, n_str);
|
||||
|
||||
char *json = NULL;
|
||||
size_t json_len = 0;
|
||||
EXPECT_EQ(utable_json_export(table, &json, &json_len), 0);
|
||||
EXPECT_NE(nullptr, json);
|
||||
cJSON *root = cJSON_Parse(json);
|
||||
test_utable_check_if_value_in_json(root, "key1", int_array, 2);
|
||||
std::string expected_str(str);
|
||||
test_utable_check_if_value_in_json(root, "key2", expected_str);
|
||||
test_utable_check_if_value_in_json(root, "key3", blob, strlen(blob));
|
||||
|
||||
test_utable_check_if_value_in_json(root, "key4", str_array, n_str);
|
||||
|
||||
struct utable_stat A={};
|
||||
struct utable_stat B={};
|
||||
B.n_item=4;
|
||||
B.n_item_size=strlen("key1")+sizeof(int64_t)*2+strlen("key2")+strlen(str)+strlen("key3")+strlen(blob)+strlen("key4")+str_sz[0]+str_sz[1];
|
||||
B.n_blob=1;
|
||||
B.n_blob_size=strlen(blob);
|
||||
B.n_cstring=1;
|
||||
B.n_cstring_size=strlen(str);
|
||||
B.n_integer_array=1;
|
||||
B.n_integer_array_size=sizeof(int64_t)*2;
|
||||
B.n_integer=0;
|
||||
B.n_integer_size=0;
|
||||
B.n_cstring_array=1;
|
||||
B.n_cstring_array_size=str_sz[0]+str_sz[1];
|
||||
utable_stat(table, &A);
|
||||
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
|
||||
|
||||
utable_free(table);
|
||||
free(json);
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
|
||||
TEST(utable_test, export_invalid_unicode_string_to_json)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
const char *str = "googleads.g.doublec\x86rck.net";
|
||||
utable_add_cstring(table, "key2", str, strlen(str));
|
||||
|
||||
char *json = NULL;
|
||||
size_t json_len = 0;
|
||||
EXPECT_EQ(utable_json_export(table, &json, &json_len), 0);
|
||||
EXPECT_NE(nullptr, json);
|
||||
cJSON *root = cJSON_Parse(json);
|
||||
std::string expected_str(str);
|
||||
test_utable_check_if_value_in_json(root, "key2", expected_str);
|
||||
|
||||
struct utable_stat A={};
|
||||
struct utable_stat B={};
|
||||
B.n_item=1;
|
||||
B.n_item_size=strlen("key2")+strlen(str);
|
||||
B.n_cstring=1;
|
||||
B.n_cstring_size=strlen(str);
|
||||
utable_stat(table, &A);
|
||||
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
|
||||
|
||||
utable_free(table);
|
||||
free(json);
|
||||
cJSON_Delete(root);
|
||||
}
|
||||
|
||||
char *test_get_cstring_from_mpack_node(mpack_node_t node)
|
||||
{
|
||||
size_t len = mpack_node_strlen(node);
|
||||
char *str = (char *)malloc(len + 1);
|
||||
memcpy(str, mpack_node_str(node), len);
|
||||
str[len] = '\0';
|
||||
return str;
|
||||
}
|
||||
|
||||
void test_utable_check_if_value_in_mpack(mpack_node_t item, const char *key, const std::string &value)
|
||||
{
|
||||
mpack_node_t key_node = mpack_node_map_cstr(item, "key");
|
||||
mpack_node_t type_node = mpack_node_map_cstr(item, "type");
|
||||
mpack_node_t value_node = mpack_node_map_cstr(item, "value");
|
||||
|
||||
char *key_tmp = test_get_cstring_from_mpack_node(key_node);
|
||||
char *type_tmp = test_get_cstring_from_mpack_node(type_node);
|
||||
char *value_tmp = test_get_cstring_from_mpack_node(value_node);
|
||||
EXPECT_STREQ(key_tmp, key);
|
||||
EXPECT_STREQ(type_tmp, "c_str");
|
||||
EXPECT_STREQ(value_tmp, value.c_str());
|
||||
|
||||
free(key_tmp);
|
||||
free(type_tmp);
|
||||
free(value_tmp);
|
||||
}
|
||||
|
||||
void test_utable_check_if_value_in_mpack(mpack_node_t item, const char *key, int64_t value[], size_t n_value)
|
||||
{
|
||||
mpack_node_t key_node = mpack_node_map_cstr(item, "key");
|
||||
mpack_node_t type_node = mpack_node_map_cstr(item, "type");
|
||||
mpack_node_t value_node = mpack_node_map_cstr(item, "value");
|
||||
char *key_tmp = test_get_cstring_from_mpack_node(key_node);
|
||||
char *type_tmp = test_get_cstring_from_mpack_node(type_node);
|
||||
|
||||
EXPECT_STREQ(key_tmp, key);
|
||||
EXPECT_STREQ(type_tmp, "i_arr");
|
||||
EXPECT_EQ(mpack_node_array_length(value_node), n_value);
|
||||
for (size_t i = 0; i < n_value; i++) {
|
||||
mpack_node_t tmp_v_node = mpack_node_array_at(value_node, i);
|
||||
EXPECT_EQ(mpack_node_i64(tmp_v_node), value[i]);
|
||||
}
|
||||
free(key_tmp);
|
||||
free(type_tmp);
|
||||
}
|
||||
|
||||
void test_utable_check_if_value_in_mpack(mpack_node_t item, const char *key, const char *value, size_t blob_len)
|
||||
{
|
||||
mpack_node_t key_node = mpack_node_map_cstr(item, "key");
|
||||
mpack_node_t type_node = mpack_node_map_cstr(item, "type");
|
||||
mpack_node_t value_node = mpack_node_map_cstr(item, "value");
|
||||
char *key_tmp = test_get_cstring_from_mpack_node(key_node);
|
||||
char *type_tmp = test_get_cstring_from_mpack_node(type_node);
|
||||
EXPECT_STREQ(key_tmp, key);
|
||||
EXPECT_STREQ(type_tmp, "blob");
|
||||
EXPECT_EQ(mpack_node_bin_size(value_node), blob_len);
|
||||
EXPECT_EQ(memcmp(mpack_node_bin_data(value_node), value, blob_len), 0);
|
||||
|
||||
free(key_tmp);
|
||||
free(type_tmp);
|
||||
}
|
||||
|
||||
TEST(utable_test, DISABLED_export_mpack)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
int64_t int_array[] = { 1, 2 };
|
||||
const char *str = "hello world";
|
||||
const char *blob = "bin hello world";
|
||||
utable_add_integer_array(table, "key1", int_array, 2);
|
||||
utable_add_cstring(table, "key2", str, strlen(str));
|
||||
utable_add_blob(table, "key3", blob, strlen(blob));
|
||||
|
||||
char *mpack = NULL;
|
||||
size_t mpack_len = 0;
|
||||
EXPECT_EQ(utable_msgpack_export(table, &mpack, &mpack_len), 0);
|
||||
|
||||
|
||||
mpack_tree_t tree;
|
||||
mpack_tree_init_data(&tree, mpack, mpack_len);
|
||||
mpack_tree_parse(&tree);
|
||||
mpack_node_t root = mpack_tree_root(&tree);
|
||||
size_t n_item = mpack_node_array_length(root);
|
||||
EXPECT_EQ(n_item, 3);
|
||||
|
||||
test_utable_check_if_value_in_mpack(mpack_node_array_at(root, 0), "key1", int_array, 2);
|
||||
std::string expected_str(str);
|
||||
test_utable_check_if_value_in_mpack(mpack_node_array_at(root, 1), "key2", expected_str);
|
||||
test_utable_check_if_value_in_mpack(mpack_node_array_at(root, 2), "key3", blob, strlen(blob));
|
||||
|
||||
utable_free(table);
|
||||
free(mpack);
|
||||
mpack_tree_destroy(&tree);
|
||||
}
|
||||
|
||||
|
||||
TEST(utable_test, add_blob_then_del)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
const char *blob = "hello world";
|
||||
size_t blob_len = strlen(blob);
|
||||
utable_add_blob(table, "key", blob, blob_len);
|
||||
test_utable_assert_blob(table, "key", blob, blob_len);
|
||||
|
||||
struct utable_stat A={};
|
||||
struct utable_stat B={};
|
||||
B.n_item=1;
|
||||
B.n_item_size=strlen("key")+strlen(blob);
|
||||
B.n_blob=1;
|
||||
B.n_blob_size=strlen(blob);
|
||||
utable_stat(table, &A);
|
||||
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
|
||||
|
||||
char *value;
|
||||
size_t value_len;
|
||||
utable_delete_item(table, "key");
|
||||
EXPECT_EQ(utable_get0_blob_value(table, "key", &value, &value_len), -1);
|
||||
EXPECT_EQ(utable_get0_cstring_value(table, "key", &value, &value_len), -1);
|
||||
int64_t *value_array;
|
||||
size_t n_value;
|
||||
EXPECT_EQ(utable_get0_integer_value_array(table, "key", &value_array, &n_value), -1);
|
||||
EXPECT_EQ(utable_get_value_type(table, "key"), utable_value_type_undefined);
|
||||
|
||||
struct utable_stat C={};
|
||||
utable_stat(table, &A);
|
||||
EXPECT_EQ(memcmp(&A, &C, sizeof(struct utable_stat)), 0);
|
||||
|
||||
utable_free(table);
|
||||
}
|
||||
|
||||
|
||||
TEST(utable_test, add_string_array_then_del)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
const char *str[] = {"hello world", "foo bar"};
|
||||
size_t n_str=sizeof(str)/sizeof(str[0]);
|
||||
size_t str_sz[] = {strlen(str[0]), strlen(str[1])};
|
||||
utable_add_cstring_array(table, "key", str, str_sz, n_str);
|
||||
test_utable_assert_str_array(table, "key", str, n_str);
|
||||
|
||||
struct utable_stat A={};
|
||||
struct utable_stat B={};
|
||||
B.n_item=1;
|
||||
B.n_item_size=strlen("key")+str_sz[0]+str_sz[1];
|
||||
B.n_cstring_array=1;
|
||||
B.n_cstring_array_size=str_sz[0]+str_sz[1];
|
||||
utable_stat(table, &A);
|
||||
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
|
||||
|
||||
char *value;
|
||||
size_t value_len;
|
||||
utable_delete_item(table, "key");
|
||||
EXPECT_EQ(utable_get0_blob_value(table, "key", &value, &value_len), -1);
|
||||
EXPECT_EQ(utable_get0_cstring_value(table, "key", &value, &value_len), -1);
|
||||
int64_t *value_array;
|
||||
size_t n_value;
|
||||
EXPECT_EQ(utable_get0_integer_value_array(table, "key", &value_array, &n_value), -1);
|
||||
|
||||
char **str_array = NULL;
|
||||
size_t *str_len = NULL;
|
||||
n_str = 0;
|
||||
EXPECT_EQ(utable_get0_cstring_value_array(table, "key", &str_array, &str_len, &n_str), -1);
|
||||
|
||||
EXPECT_EQ(utable_get_value_type(table, "key"), utable_value_type_undefined);
|
||||
|
||||
struct utable_stat C={};
|
||||
utable_stat(table, &A);
|
||||
EXPECT_EQ(memcmp(&A, &C, sizeof(struct utable_stat)), 0);
|
||||
|
||||
utable_free(table);
|
||||
}
|
||||
|
||||
TEST(utable_test, query_on_wrong_key)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
|
||||
char *value;
|
||||
size_t value_len;
|
||||
EXPECT_EQ(utable_get0_blob_value(table, "key", &value, &value_len), -1);
|
||||
EXPECT_EQ(utable_get0_cstring_value(table, "key", &value, &value_len), -1);
|
||||
int64_t *value_array;
|
||||
size_t n_value;
|
||||
EXPECT_EQ(utable_get0_integer_value_array(table, "key", &value_array, &n_value), -1);
|
||||
EXPECT_EQ(utable_get_value_type(table, "key"), utable_value_type_undefined);
|
||||
|
||||
utable_free(table);
|
||||
}
|
||||
|
||||
TEST(utable_test, add_on_dup_key)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
int64_t int_array[] = { 1, 2 };
|
||||
const char *str = "hello world";
|
||||
utable_add_integer_array(table, "key", int_array, 2);
|
||||
utable_add_cstring(table, "key", str, strlen(str));
|
||||
|
||||
test_utable_assert_arr(table, "key", int_array, 2);
|
||||
|
||||
struct utable_stat A={};
|
||||
struct utable_stat B={};
|
||||
B.n_item=1;
|
||||
B.n_item_size=strlen("key")+sizeof(int64_t)*2;
|
||||
B.n_integer_array=1;
|
||||
B.n_integer_array_size=sizeof(int64_t)*2;
|
||||
|
||||
utable_stat(table, &A);
|
||||
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
|
||||
|
||||
utable_free(table);
|
||||
}
|
||||
|
||||
TEST(utable_test, iter_and_query)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
|
||||
int64_t int_array[] = { 1, 2 };
|
||||
const char *str = "hello world";
|
||||
utable_add_integer_array(table, "key1", int_array, 2);
|
||||
utable_add_cstring(table, "key2", str, strlen(str));
|
||||
utable_add_integer_array(table, "key3", int_array, 2);
|
||||
|
||||
EXPECT_STREQ(utable_next_key(table), "key1");
|
||||
EXPECT_STREQ(utable_next_key(table), "key2");
|
||||
EXPECT_STREQ(utable_next_key(table), "key3");
|
||||
EXPECT_EQ(utable_next_key(table), nullptr);
|
||||
utable_reset_iter(table);
|
||||
EXPECT_STREQ(utable_next_key(table), "key1");
|
||||
EXPECT_STREQ(utable_next_key(table), "key2");
|
||||
EXPECT_STREQ(utable_next_key(table), "key3");
|
||||
EXPECT_EQ(utable_next_key(table), nullptr);
|
||||
|
||||
struct utable_stat A={};
|
||||
struct utable_stat B={};
|
||||
B.n_item=3;
|
||||
B.n_item_size=strlen("key1")+sizeof(int64_t)*2+strlen("key2")+strlen(str)+strlen("key3")+sizeof(int64_t)*2;
|
||||
B.n_blob=0;
|
||||
B.n_blob_size=0;
|
||||
B.n_cstring=1;
|
||||
B.n_cstring_size=strlen(str);
|
||||
B.n_integer_array=2;
|
||||
B.n_integer_array_size=sizeof(int64_t)*4;
|
||||
B.n_integer=0;
|
||||
B.n_integer_size=0;
|
||||
utable_stat(table, &A);
|
||||
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
|
||||
|
||||
|
||||
utable_free(table);
|
||||
}
|
||||
|
||||
TEST(utable_test, dup_empty)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
|
||||
struct utable *dup_table = utable_duplicate(table);
|
||||
EXPECT_EQ(utable_next_key(dup_table), nullptr);
|
||||
|
||||
utable_free(table);
|
||||
utable_free(dup_table);
|
||||
}
|
||||
|
||||
TEST(utable_test, dup_and_query)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
|
||||
const char *str = "hello world";
|
||||
utable_add_cstring(table, "key1", str, strlen(str));
|
||||
int64_t int_array[] = { 1, 2 };
|
||||
utable_add_integer_array(table, "key2", int_array, 2);
|
||||
const char *blob = "bin hello world";
|
||||
utable_add_blob(table, "key3", blob, strlen(blob));
|
||||
|
||||
struct utable *dup_table = utable_duplicate(table);
|
||||
test_utable_assert_arr(dup_table, "key2", int_array, 2);
|
||||
test_utable_assert_str(dup_table, "key1", str);
|
||||
test_utable_assert_blob(dup_table, "key3", blob, strlen(blob));
|
||||
|
||||
struct utable_stat A={}, B={};
|
||||
utable_stat(table, &A);
|
||||
utable_stat(dup_table, &B);
|
||||
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
|
||||
|
||||
utable_free(table);
|
||||
utable_free(dup_table);
|
||||
}
|
||||
|
||||
TEST(utable_test, replace_8k_cstring)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
|
||||
const char str1[] = "hello world";
|
||||
char str2[8192];
|
||||
memset(str2, 'B', sizeof(str2));
|
||||
str2[8191] = '\0'; // make sure it's null-terminated
|
||||
|
||||
utable_add_cstring(table, "key1", str1, strlen(str1));
|
||||
|
||||
test_utable_assert_str(table, "key1", str1);
|
||||
|
||||
utable_delete_item(table, "key1");
|
||||
utable_add_cstring(table, "key1", str2, strlen(str2));
|
||||
|
||||
test_utable_assert_str(table, "key1", str2);
|
||||
|
||||
struct utable_stat A={};
|
||||
struct utable_stat B={};
|
||||
B.n_item=1;
|
||||
B.n_item_size=strlen("key1")+strlen(str2);
|
||||
B.n_cstring=1;
|
||||
B.n_cstring_size=strlen(str2);
|
||||
utable_stat(table, &A);
|
||||
|
||||
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
|
||||
|
||||
utable_free(table);
|
||||
}
|
||||
|
||||
TEST(utable_test, replace_cstring_many_times)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
|
||||
char str[4000] ;
|
||||
|
||||
memset(str, 'B', sizeof(str));
|
||||
str[3999] = '\0'; // make sure it's null-terminated
|
||||
|
||||
utable_add_cstring(table, "key1", str, strlen(str));
|
||||
|
||||
test_utable_assert_str(table, "key1", str);
|
||||
|
||||
for(int i=0; i<100000; i++)
|
||||
{
|
||||
utable_delete_item(table, "key1");
|
||||
utable_add_cstring(table, "key1", str, strlen(str));
|
||||
}
|
||||
|
||||
test_utable_assert_str(table, "key1", str);
|
||||
|
||||
struct utable_stat A={};
|
||||
struct utable_stat B={};
|
||||
B.n_item=1;
|
||||
B.n_item_size=strlen("key1")+strlen(str);
|
||||
B.n_cstring=1;
|
||||
B.n_cstring_size=strlen(str);
|
||||
utable_stat(table, &A);
|
||||
|
||||
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
|
||||
printf("replace_cstring_many_times done\n");
|
||||
utable_free(table);
|
||||
}
|
||||
|
||||
TEST(utable_test, merge_empty_to_empty)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
struct utable *table2 = utable_new();
|
||||
utable_merge(table, table2);
|
||||
EXPECT_EQ(utable_next_key(table), nullptr);
|
||||
|
||||
struct utable_stat A={}, B={};
|
||||
utable_stat(table, &A);
|
||||
utable_stat(table2, &B);
|
||||
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
|
||||
|
||||
utable_free(table);
|
||||
utable_free(table2);
|
||||
}
|
||||
|
||||
TEST(utable_test, merge_all_new)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
struct utable *table2 = utable_new();
|
||||
|
||||
const char *str = "hello world";
|
||||
utable_add_cstring(table, "key1", str, strlen(str));
|
||||
int64_t int_array[] = { 1, 2 };
|
||||
utable_add_integer_array(table, "key2", int_array, 2);
|
||||
|
||||
const char *blob = "bin hello world";
|
||||
utable_add_blob(table2, "key on tbl2", blob, strlen(blob));
|
||||
|
||||
utable_merge(table2, table);
|
||||
test_utable_assert_arr(table2, "key2", int_array, 2);
|
||||
test_utable_assert_str(table2, "key1", str);
|
||||
test_utable_assert_blob(table2, "key on tbl2", blob, strlen(blob));
|
||||
|
||||
utable_merge(table, table2);
|
||||
struct utable_stat A={}, B={};
|
||||
utable_stat(table, &A);
|
||||
utable_stat(table2, &B);
|
||||
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
|
||||
|
||||
utable_free(table);
|
||||
utable_free(table2);
|
||||
}
|
||||
|
||||
TEST(utable_test, merge_all_skip)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
const char *str = "hello world";
|
||||
utable_add_cstring(table, "key1", str, strlen(str));
|
||||
int64_t int_array[] = { 1, 2 };
|
||||
utable_add_integer_array(table, "key2", int_array, 2);
|
||||
struct utable *table2 = utable_duplicate(table);
|
||||
|
||||
utable_merge(table2, table);
|
||||
|
||||
EXPECT_STREQ(utable_next_key(table2), "key1");
|
||||
EXPECT_STREQ(utable_next_key(table2), "key2");
|
||||
EXPECT_EQ(utable_next_key(table2), nullptr);
|
||||
|
||||
utable_free(table);
|
||||
utable_free(table2);
|
||||
}
|
||||
|
||||
TEST(utable_test, merge_some_skip_some_new)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
struct utable *table2 = utable_new();
|
||||
|
||||
const char *str = "val on tbl1";
|
||||
utable_add_cstring(table, "key_share", str, strlen(str));
|
||||
const char *str2 = "val on tbl2";
|
||||
utable_add_cstring(table2, "key_share", str2, strlen(str2));
|
||||
const char *str3 = "val on tbl1";
|
||||
utable_add_cstring(table, "key1", str3, strlen(str3));
|
||||
|
||||
utable_merge(table2, table);
|
||||
|
||||
test_utable_assert_str(table2, "key_share", str2);
|
||||
test_utable_assert_str(table2, "key1", str3);
|
||||
|
||||
utable_free(table);
|
||||
utable_free(table2);
|
||||
}
|
||||
|
||||
TEST(utable_test, serialize_and_deserialize)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
int64_t int_array[] = { 1, 2 };
|
||||
const char *str = "hello world";
|
||||
const char *blob = "bin hello world";
|
||||
utable_add_integer_array(table, "key1", int_array, 2);
|
||||
utable_add_cstring(table, "key2", str, strlen(str));
|
||||
utable_add_blob(table, "key3", blob, strlen(blob));
|
||||
|
||||
char *blob_out;
|
||||
size_t blob_size;
|
||||
utable_serialize(table, &blob_out, &blob_size);
|
||||
|
||||
struct utable *table2 = utable_deserialize(blob_out, blob_size);
|
||||
test_utable_assert_arr(table2, "key1", int_array, 2);
|
||||
test_utable_assert_str(table2, "key2", str);
|
||||
test_utable_assert_blob(table2, "key3", blob, strlen(blob));
|
||||
|
||||
struct utable_stat A={}, B={};
|
||||
utable_stat(table, &A);
|
||||
utable_stat(table2, &B);
|
||||
EXPECT_EQ(memcmp(&A, &B, sizeof(struct utable_stat)), 0);
|
||||
|
||||
utable_free(table);
|
||||
free(blob_out);
|
||||
utable_free(table2);
|
||||
}
|
||||
|
||||
TEST(utable_test, serialize_empty_and_deserialize)
|
||||
{
|
||||
struct utable *table = utable_new();
|
||||
|
||||
char *blob_out;
|
||||
size_t blob_size;
|
||||
utable_serialize(table, &blob_out, &blob_size);
|
||||
|
||||
struct utable *table2 = utable_deserialize(blob_out, blob_size);
|
||||
|
||||
ASSERT_TRUE(table2 != NULL);
|
||||
ASSERT_EQ(utable_next_key(table2), nullptr);
|
||||
|
||||
utable_free(table);
|
||||
free(blob_out);
|
||||
utable_free(table2);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
Reference in New Issue
Block a user