diff options
| -rw-r--r-- | CMakeLists.txt | 15 | ||||
| -rw-r--r-- | ctest/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | include/fieldstat/fieldstat.h | 3 | ||||
| -rw-r--r-- | src/cube.c | 12 | ||||
| -rw-r--r-- | src/exporter/cjson_exporter.c | 92 | ||||
| -rw-r--r-- | test/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | test/test_empty_tags.cpp | 165 | ||||
| -rw-r--r-- | test/test_special_tags.cpp | 399 |
8 files changed, 464 insertions, 230 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a30f66..45aa8a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,12 +10,12 @@ set(lib_name fieldstat4) project (${lib_name})
-# to fix issue: cannot find pthresh
-# set(CMAKE_THREAD_LIBS_INIT "-lpthread")
-# set(CMAKE_HAVE_THREADS_LIBRARY 1)
-# set(CMAKE_USE_WIN32_THREADS_INIT 0)
-# set(CMAKE_USE_PTHREADS_INIT 1)
-# set(THREADS_PREFER_PTHREAD_FLAG ON)
+find_library(UUID_LIB uuid)
+if(UUID_LIB)
+ message(STATUS "Found UUID library: ${UUID_LIB}")
+else()
+ message(FATAL_ERROR "Could not find the UUID library. Please install libuuid.")
+endif()
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
include(Version)
@@ -127,6 +127,8 @@ add_subdirectory(ctest) # Shared Library Output
add_library(${lib_name}_shared SHARED ${SRC})
+target_link_libraries(${lib_name}_shared ${UUID_LIB})
+
set_target_properties(${lib_name}_shared PROPERTIES LINK_FLAGS
"-Wl,--version-script=${PROJECT_SOURCE_DIR}/src/version.map")
if(DEFINED MESA_SHARED_INSTALL_DIR)
@@ -137,6 +139,7 @@ endif() # static Library Output
add_library(${lib_name}_static STATIC ${SRC})
+target_link_libraries(${lib_name}_static ${UUID_LIB})
set_target_properties(${lib_name}_static PROPERTIES OUTPUT_NAME ${lib_name})
install(TARGETS ${lib_name}_shared LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib COMPONENT LIBRARIES)
diff --git a/ctest/CMakeLists.txt b/ctest/CMakeLists.txt index fd1077d..13bef82 100644 --- a/ctest/CMakeLists.txt +++ b/ctest/CMakeLists.txt @@ -6,7 +6,7 @@ message(STATUS "CMAKE_BINARY_DIR: ${CMAKE_BINARY_DIR}") add_test(NAME COPY_CREATE_DIR COMMAND sh -c "mkdir -p ${CMAKE_BINARY_DIR}/testing/ ") add_test(NAME COPY_GTEST_FS_EASY_BINARY COMMAND sh -c "cp ${CMAKE_BINARY_DIR}/test/test_easy_fs ${CMAKE_BINARY_DIR}/testing/") -add_test(NAME COPY_GTEST_EMPTY_TAGS_BINARY COMMAND sh -c "cp ${CMAKE_BINARY_DIR}/test/test_empty_tags ${CMAKE_BINARY_DIR}/testing/") +add_test(NAME COPY_GTEST_SPECIAL_TAGS_BINARY COMMAND sh -c "cp ${CMAKE_BINARY_DIR}/test/test_special_tags ${CMAKE_BINARY_DIR}/testing/") add_test(NAME COPY_GTEST_JSON_EXPORTER_BINARY COMMAND sh -c "cp ${CMAKE_BINARY_DIR}/test/test_exporter_json ${CMAKE_BINARY_DIR}/testing/") add_test(NAME COPY_GTEST_FUZZ_BINARY COMMAND sh -c "cp ${CMAKE_BINARY_DIR}/test/test_fuzz_test ${CMAKE_BINARY_DIR}/testing/") add_test(NAME COPY_GTEST_MERGE_BINARY COMMAND sh -c "cp ${CMAKE_BINARY_DIR}/test/test_merge ${CMAKE_BINARY_DIR}/testing/") @@ -19,7 +19,7 @@ add_test(NAME CHMOD_UNITTEST COMMAND sh -c "chmod 0755 ${CMAKE_SOURCE_DIR}/test/ set(GTEST_RUN_DIR ${CMAKE_BINARY_DIR}/testing) add_test(NAME GTEST_FS_EASY COMMAND test_easy_fs WORKING_DIRECTORY ${GTEST_RUN_DIR}) -add_test(NAME GTEST_EMPTY_TAGS COMMAND test_empty_tags WORKING_DIRECTORY ${GTEST_RUN_DIR}) +add_test(NAME GTEST_SPECIAL_TAGS COMMAND test_special_tags WORKING_DIRECTORY ${GTEST_RUN_DIR}) add_test(NAME GTEST_JSON_EXPORTER COMMAND test_exporter_json WORKING_DIRECTORY ${GTEST_RUN_DIR}) add_test(NAME GTEST_FUZZ COMMAND test_fuzz_test WORKING_DIRECTORY ${GTEST_RUN_DIR}) add_test(NAME GTEST_MERGE COMMAND test_merge WORKING_DIRECTORY ${GTEST_RUN_DIR}) diff --git a/include/fieldstat/fieldstat.h b/include/fieldstat/fieldstat.h index 8bb5c8f..06fb0c3 100644 --- a/include/fieldstat/fieldstat.h +++ b/include/fieldstat/fieldstat.h @@ -7,6 +7,7 @@ extern "C" #include <stddef.h> #include <stdbool.h> +#include <uuid/uuid.h> #define FS_OK 0 #define FS_ERR_TOO_MANY_CELLS -1 @@ -36,6 +37,7 @@ enum field_type FIELD_VALUE_INTEGER, FIELD_VALUE_DOUBLE, FIELD_VALUE_CSTRING, + FIELD_VALUE_UUID, }; enum sampling_mode { @@ -51,6 +53,7 @@ struct field { long long value_longlong; double value_double; const char *value_str; + uuid_t value_uuid; }; }; @@ -78,6 +78,9 @@ static struct field *field_array_duplicate(const struct field *fields_src, size_ case FIELD_VALUE_DOUBLE: ret[i].value_double = fields_src[i].value_double; break; + case FIELD_VALUE_UUID: + memcpy(ret[i].value_uuid, fields_src[i].value_uuid, sizeof(uuid_t)); + break; default: break; } @@ -142,6 +145,11 @@ void print_field_array(const struct field *fields, size_t n_field) case FIELD_VALUE_CSTRING: printf("%s\n", fields[i].value_str); break; + case FIELD_VALUE_UUID: { + char out[37]; + uuid_unparse(fields[i].value_uuid, out); + printf("%s\n", out); + break;} default: break; } @@ -188,6 +196,10 @@ static void field_array_to_key(const struct field fields[], size_t n_fields, cha val_len = strlen(field->value_str); val_position = (void *)field->value_str; break; + case FIELD_VALUE_UUID: + val_len = sizeof(uuid_t); + val_position = (void *)field->value_uuid; + break; default: assert(0); break; diff --git a/src/exporter/cjson_exporter.c b/src/exporter/cjson_exporter.c index 3c8fdd4..23e890e 100644 --- a/src/exporter/cjson_exporter.c +++ b/src/exporter/cjson_exporter.c @@ -123,6 +123,9 @@ void kv_pair_fill_with_fields(struct export_kv_pair *dest, const struct field *s { dest->key = strdup(src->key); dest->type = src->type; + if (dest->type == FIELD_VALUE_UUID) { + dest->type = FIELD_VALUE_CSTRING; + } switch (src->type) { case FIELD_VALUE_INTEGER: dest->value_longlong = src->value_longlong; @@ -133,6 +136,12 @@ void kv_pair_fill_with_fields(struct export_kv_pair *dest, const struct field *s case FIELD_VALUE_CSTRING: dest->value_str = strdup(src->value_str); break; + case FIELD_VALUE_UUID: { + char uuid_str[37]; + uuid_unparse(src->value_uuid, uuid_str); + dest->value_str = strdup(uuid_str); + break; + } default: assert(0); } @@ -237,6 +246,11 @@ bool field_list_cmp(const struct field_list *a, const struct field_list *b) return false; } break; + case FIELD_VALUE_UUID: + if (uuid_compare(a->field[i].value_uuid, b->field[i].value_uuid) != 0) { + return false; + } + break; default: assert(0); } @@ -264,6 +278,9 @@ struct field_list *field_list_dup(const struct field_list *src) case FIELD_VALUE_CSTRING: dest->field[i].value_str = strdup(src->field[i].value_str); break; + case FIELD_VALUE_UUID: + memcpy(dest->field[i].value_uuid, src->field[i].value_uuid, sizeof(uuid_t)); + break; default: assert(0); } @@ -547,6 +564,7 @@ void kv_pair_write_to_json(const struct export_kv_pair *pairs, struct json_write json_writer_double_field(writer, pairs->key, pairs->value_double); break; case FIELD_VALUE_CSTRING: + case FIELD_VALUE_UUID: json_writer_str_field(writer, pairs->key, pairs->value_str, strlen(pairs->value_str)); break; default: @@ -554,33 +572,30 @@ void kv_pair_write_to_json(const struct export_kv_pair *pairs, struct json_write } } -void field_list_write_to_json(const struct field_list *field_list, struct json_writer *json_obj) +void kv_pair_free_list(struct export_kv_pair *pairs, size_t len) { - struct export_kv_pair pairs = {0}; + for (int i = 0; i < len; i++) { + struct export_kv_pair *pair = &pairs[i]; + if (pair->type == FIELD_VALUE_CSTRING) { + free(pair->value_str); + } + free(pair->key); + } + free(pairs); +} +void field_list_write_to_json(const struct field_list *field_list, struct json_writer *json_obj) +{ + struct export_kv_pair *pairs = malloc(sizeof(struct export_kv_pair) * field_list->n_field); for (int i = 0; i < field_list->n_field; i++) { if (field_list->n_field == 0) { continue; } - memset(&pairs, 0, sizeof(struct export_kv_pair)); - pairs.key = (char *)field_list->field[i].key; - pairs.type = field_list->field[i].type; - switch (pairs.type) - { - case FIELD_VALUE_INTEGER: - pairs.value_longlong = field_list->field[i].value_longlong; - break; - case FIELD_VALUE_DOUBLE: - pairs.value_double = field_list->field[i].value_double; - break; - case FIELD_VALUE_CSTRING: - pairs.value_str = (char *)field_list->field[i].value_str; - break; - default: - break; - } - kv_pair_write_to_json(&pairs, json_obj); + + kv_pair_fill_with_fields(&pairs[i], &field_list->field[i]); + kv_pair_write_to_json(&pairs[i], json_obj); } + kv_pair_free_list(pairs, field_list->n_field); } void cell_iter_read_dimensions(const struct cell_iter *iter, struct export_kv_pair **exported_dimensions, size_t *n_dimension_out) @@ -602,18 +617,6 @@ void cell_iter_read_dimensions(const struct cell_iter *iter, struct export_kv_pa } } -void kv_pair_free_list(struct export_kv_pair *pairs, size_t len) -{ - for (int i = 0; i < len; i++) { - struct export_kv_pair *pair = &pairs[i]; - if (pair->type == FIELD_VALUE_CSTRING) { - free(pair->value_str); - } - free(pair->key); - } - free(pairs); -} - // return 1 if added, 0 if not added int json_obj_add(struct cellwise_rec_for_export *tag_field_pair, const struct cell_iter *iter) { @@ -953,30 +956,9 @@ void fieldstat_json_exporter_set_global_dimension(struct fieldstat_json_exporter free(exporter->global_tag_list->field); free(exporter->global_tag_list); } + struct field_list tmp = {(struct field *)tag_list, n_field}; - exporter->global_tag_list = malloc(sizeof(struct field_list)); - exporter->global_tag_list->n_field = n_field; - exporter->global_tag_list->field = malloc(sizeof(struct field) * n_field); - for (size_t i = 0; i < n_field; i++) { - struct field *field = &exporter->global_tag_list->field[i]; - field->key = strdup(tag_list[i].key); - field->type = tag_list[i].type; - switch (field->type) - { - case FIELD_VALUE_INTEGER: - field->value_longlong = tag_list[i].value_longlong; - break; - case FIELD_VALUE_CSTRING: - field->value_str = strdup(tag_list[i].value_str); - break; - case FIELD_VALUE_DOUBLE: - field->value_double = tag_list[i].value_double; - break; - - default: - break; - } - } + exporter->global_tag_list = field_list_dup(&tmp); } void fieldstat_json_exporter_free(struct fieldstat_json_exporter *exporter) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a6c1403..ac387fc 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -43,12 +43,12 @@ SET(TEST_UTILS_SRC function (add_unit_test file_name)
add_executable(${file_name} ${SRC} ${TEST_UTILS_SRC} ${file_name}.cpp)
- target_link_libraries(${file_name} gtest-static ${ZLIB_LIBRARIES} ${LFLAGS})
+ target_link_libraries(${file_name} gtest-static fieldstat4_shared ${ZLIB_LIBRARIES} ${LFLAGS} )
set_property(TARGET ${file_name} PROPERTY CXX_STANDARD 17)
endfunction()
add_unit_test(test_easy_fs)
-add_unit_test(test_empty_tags)
+add_unit_test(test_special_tags)
add_unit_test(test_exporter_json)
add_unit_test(test_fuzz_test)
add_unit_test(test_merge)
diff --git a/test/test_empty_tags.cpp b/test/test_empty_tags.cpp deleted file mode 100644 index 7de6489..0000000 --- a/test/test_empty_tags.cpp +++ /dev/null @@ -1,165 +0,0 @@ -#include <gtest/gtest.h> - -#include "utils.hpp" -#include "cjson/cJSON.h" - -#include "fieldstat.h" -#include "fieldstat_exporter.h" - -void assert_cell_null(const struct fieldstat *instance, int cube_id, long long expected_count) -{ - struct field_list *tag_list = NULL; - size_t n_cell = 0; - fieldstat_cube_get_cells(instance, cube_id, &tag_list, &n_cell); - EXPECT_EQ(n_cell, 1); - EXPECT_EQ(tag_list[0].n_field, 0); - EXPECT_TRUE(tag_list[0].field == NULL); - long long value; - fieldstat_counter_get(instance, cube_id, &tag_list[0], 0, &value); - EXPECT_EQ(value, expected_count); - fieldstat_field_list_arr_free(tag_list, n_cell); -} - -TEST(test_empty_tag, add_many_times) -{ - struct fieldstat *instance = fieldstat_new(); - int cube_id = fieldstat_cube_create(instance, NULL, 0); - int metric_id = fieldstat_register_counter(instance, cube_id, "metric"); - fieldstat_cube_set_sampling(instance, cube_id, SAMPLING_MODE_COMPREHENSIVE, 1, 0); - - fieldstat_counter_incrby(instance, cube_id, metric_id, NULL, 0, 1); - fieldstat_counter_incrby(instance, cube_id, metric_id, NULL, 0, 1); - - assert_cell_null(instance, cube_id, 2); - - fieldstat_free(instance); -} - -struct fieldstat *test_empty_my_init(enum sampling_mode mode = SAMPLING_MODE_COMPREHENSIVE) -{ - struct fieldstat *instance = fieldstat_new(); - int cube_id = fieldstat_cube_create(instance, NULL, 0); - int metric_id = fieldstat_register_counter(instance, cube_id, "metric"); - fieldstat_cube_set_sampling(instance, cube_id, mode, 1, 0); - - fieldstat_counter_incrby(instance, cube_id, metric_id, NULL, 0, 1); - - return instance; -} - -TEST(test_empty_tag, merge) -{ - struct fieldstat *instance_src = test_empty_my_init(); - struct fieldstat *instance_dst = fieldstat_new(); - - fieldstat_merge(instance_dst, instance_src); - fieldstat_merge(instance_dst, instance_src); - - int *ret_cube_id_arr = NULL; - int n_cube = 0; - fieldstat_get_cubes(instance_dst, &ret_cube_id_arr, &n_cube); - int ret_cell_id = ret_cube_id_arr[0]; - struct field_list *shared_tag = fieldstat_cube_get_dimension(instance_dst, ret_cell_id); - EXPECT_EQ(shared_tag->n_field, 0); - EXPECT_TRUE(shared_tag->field == NULL); - fieldstat_field_list_arr_free(shared_tag, 1); - free(ret_cube_id_arr); - - assert_cell_null(instance_dst, ret_cell_id, 2); - - fieldstat_free(instance_dst); - fieldstat_free(instance_src); -} - -TEST(test_empty_tag, merge_topk) -{ - struct fieldstat *instance_src = test_empty_my_init(SAMPLING_MODE_TOPK); - struct fieldstat *instance_dst = fieldstat_new(); - - fieldstat_merge(instance_dst, instance_src); - fieldstat_merge(instance_dst, instance_src); - - int *ret_cube_id_arr = NULL; - int n_cube = 0; - fieldstat_get_cubes(instance_dst, &ret_cube_id_arr, &n_cube); - int ret_cell_id = ret_cube_id_arr[0]; - struct field_list *shared_tag = fieldstat_cube_get_dimension(instance_dst, ret_cell_id); - EXPECT_EQ(shared_tag->n_field, 0); - EXPECT_TRUE(shared_tag->field == NULL); - fieldstat_field_list_arr_free(shared_tag, 1); - free(ret_cube_id_arr); - - assert_cell_null(instance_dst, ret_cell_id, 2); - - - fieldstat_free(instance_dst); - fieldstat_free(instance_src); -} - -TEST(test_empty_tag, merge_spreadsketch) -{ - struct fieldstat *instance_src = fieldstat_new(); - int cube_id = fieldstat_cube_create(instance_src, NULL, 0); - int metric_id = fieldstat_register_hll(instance_src, cube_id, "metric", 4); - fieldstat_cube_set_sampling(instance_src, cube_id, SAMPLING_MODE_TOP_CARDINALITY, 1, 0); - fieldstat_hll_add(instance_src, cube_id, metric_id, NULL, 0, "1", 1); - struct fieldstat *instance_dst = fieldstat_new(); - - fieldstat_merge(instance_dst, instance_src); - fieldstat_merge(instance_dst, instance_src); - - int *ret_cube_id_arr = NULL; - int n_cube = 0; - fieldstat_get_cubes(instance_dst, &ret_cube_id_arr, &n_cube); - int ret_cell_id = ret_cube_id_arr[0]; - struct field_list *shared_tag = fieldstat_cube_get_dimension(instance_dst, ret_cell_id); - EXPECT_EQ(shared_tag->n_field, 0); - EXPECT_TRUE(shared_tag->field == NULL); - fieldstat_field_list_arr_free(shared_tag, 1); - free(ret_cube_id_arr); - - struct field_list *tag_list = NULL; - size_t n_cell = 0; - fieldstat_cube_get_cells(instance_dst, cube_id, &tag_list, &n_cell); - EXPECT_EQ(n_cell, 1); - EXPECT_EQ(tag_list[0].n_field, 0); - EXPECT_TRUE(tag_list[0].field == NULL); - double value; - fieldstat_hll_get(instance_dst, cube_id, &tag_list[0], 0, &value); - EXPECT_NEAR(value, 1, 0.4); - fieldstat_field_list_arr_free(tag_list, n_cell); - - fieldstat_free(instance_dst); - fieldstat_free(instance_src); -} - -TEST(test_empty_tag, export) -{ - struct fieldstat *instance = test_empty_my_init(); - struct fieldstat_json_exporter *fieldstat_json_exporter = fieldstat_json_exporter_new(); - char *json_string = fieldstat_json_exporter_export(fieldstat_json_exporter, instance, &TEST_TIMEVAL); - // std::cout << "json_string: \n" << json_string << std::endl; - - cJSON *root_arr = cJSON_Parse(json_string); - free(json_string); - fieldstat_json_exporter_free(fieldstat_json_exporter); - fieldstat_free(instance); - - cJSON *root = cJSON_GetArrayItem(root_arr, 0); - // check field - cJSON *field = cJSON_GetObjectItem(root, "tags"); - EXPECT_EQ(cJSON_GetArraySize(field), 0); - - cJSON *metrics = cJSON_GetObjectItem(root, "fields"); - EXPECT_NE(metrics, nullptr); - cJSON *counter = cJSON_GetObjectItem(metrics, "metric"); - EXPECT_EQ(counter->valueint, 1); - - cJSON_Delete(root_arr); -} - -int main(int argc, char **argv) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -}
\ No newline at end of file diff --git a/test/test_special_tags.cpp b/test/test_special_tags.cpp new file mode 100644 index 0000000..fec3924 --- /dev/null +++ b/test/test_special_tags.cpp @@ -0,0 +1,399 @@ +#include <gtest/gtest.h> + +#include "utils.hpp" +#include "cjson/cJSON.h" + +#include "fieldstat.h" +#include "fieldstat_exporter.h" + +void assert_cell_null(const struct fieldstat *instance, int cube_id, long long expected_count) +{ + struct field_list *tag_list = NULL; + size_t n_cell = 0; + fieldstat_cube_get_cells(instance, cube_id, &tag_list, &n_cell); + EXPECT_EQ(n_cell, 1); + EXPECT_EQ(tag_list[0].n_field, 0); + EXPECT_TRUE(tag_list[0].field == NULL); + long long value; + fieldstat_counter_get(instance, cube_id, &tag_list[0], 0, &value); + EXPECT_EQ(value, expected_count); + fieldstat_field_list_arr_free(tag_list, n_cell); +} + +TEST(test_empty_tag, add_many_times) +{ + struct fieldstat *instance = fieldstat_new(); + int cube_id = fieldstat_cube_create(instance, NULL, 0); + int metric_id = fieldstat_register_counter(instance, cube_id, "metric"); + fieldstat_cube_set_sampling(instance, cube_id, SAMPLING_MODE_COMPREHENSIVE, 1, 0); + + fieldstat_counter_incrby(instance, cube_id, metric_id, NULL, 0, 1); + fieldstat_counter_incrby(instance, cube_id, metric_id, NULL, 0, 1); + + assert_cell_null(instance, cube_id, 2); + + fieldstat_free(instance); +} + +struct fieldstat *test_empty_my_init(enum sampling_mode mode = SAMPLING_MODE_COMPREHENSIVE) +{ + struct fieldstat *instance = fieldstat_new(); + int cube_id = fieldstat_cube_create(instance, NULL, 0); + int metric_id = fieldstat_register_counter(instance, cube_id, "metric"); + fieldstat_cube_set_sampling(instance, cube_id, mode, 1, 0); + + fieldstat_counter_incrby(instance, cube_id, metric_id, NULL, 0, 1); + + return instance; +} + +void assert_cell_uuid(const struct fieldstat *instance, int cube_id, long long expected_count) +{ + struct field_list *tag_list = NULL; + size_t n_cell = 0; + fieldstat_cube_get_cells(instance, cube_id, &tag_list, &n_cell); + EXPECT_EQ(n_cell, 1); + EXPECT_EQ(tag_list[0].n_field, 0); + EXPECT_TRUE(tag_list[0].field == NULL); + long long value; + fieldstat_counter_get(instance, cube_id, &tag_list[0], 0, &value); + EXPECT_EQ(value, expected_count); + fieldstat_field_list_arr_free(tag_list, n_cell); +} + +TEST(test_empty_tag, merge) +{ + struct fieldstat *instance_src = test_empty_my_init(); + struct fieldstat *instance_dst = fieldstat_new(); + + fieldstat_merge(instance_dst, instance_src); + fieldstat_merge(instance_dst, instance_src); + + int *ret_cube_id_arr = NULL; + int n_cube = 0; + fieldstat_get_cubes(instance_dst, &ret_cube_id_arr, &n_cube); + int ret_cube_id = ret_cube_id_arr[0]; + struct field_list *shared_tag = fieldstat_cube_get_dimension(instance_dst, ret_cube_id); + EXPECT_EQ(shared_tag->n_field, 0); + EXPECT_TRUE(shared_tag->field == NULL); + fieldstat_field_list_arr_free(shared_tag, 1); + free(ret_cube_id_arr); + + assert_cell_null(instance_dst, ret_cube_id, 2); + + fieldstat_free(instance_dst); + fieldstat_free(instance_src); +} + +TEST(test_empty_tag, merge_topk) +{ + struct fieldstat *instance_src = test_empty_my_init(SAMPLING_MODE_TOPK); + struct fieldstat *instance_dst = fieldstat_new(); + + fieldstat_merge(instance_dst, instance_src); + fieldstat_merge(instance_dst, instance_src); + + int *ret_cube_id_arr = NULL; + int n_cube = 0; + fieldstat_get_cubes(instance_dst, &ret_cube_id_arr, &n_cube); + int ret_cube_id = ret_cube_id_arr[0]; + struct field_list *shared_tag = fieldstat_cube_get_dimension(instance_dst, ret_cube_id); + EXPECT_EQ(shared_tag->n_field, 0); + EXPECT_TRUE(shared_tag->field == NULL); + fieldstat_field_list_arr_free(shared_tag, 1); + free(ret_cube_id_arr); + + assert_cell_null(instance_dst, ret_cube_id, 2); + + + fieldstat_free(instance_dst); + fieldstat_free(instance_src); +} + +TEST(test_empty_tag, merge_spreadsketch) +{ + struct fieldstat *instance_src = fieldstat_new(); + int cube_id = fieldstat_cube_create(instance_src, NULL, 0); + int metric_id = fieldstat_register_hll(instance_src, cube_id, "metric", 4); + fieldstat_cube_set_sampling(instance_src, cube_id, SAMPLING_MODE_TOP_CARDINALITY, 1, 0); + fieldstat_hll_add(instance_src, cube_id, metric_id, NULL, 0, "1", 1); + struct fieldstat *instance_dst = fieldstat_new(); + + fieldstat_merge(instance_dst, instance_src); + fieldstat_merge(instance_dst, instance_src); + + int *ret_cube_id_arr = NULL; + int n_cube = 0; + fieldstat_get_cubes(instance_dst, &ret_cube_id_arr, &n_cube); + int ret_cube_id = ret_cube_id_arr[0]; + struct field_list *shared_tag = fieldstat_cube_get_dimension(instance_dst, ret_cube_id); + EXPECT_EQ(shared_tag->n_field, 0); + EXPECT_TRUE(shared_tag->field == NULL); + fieldstat_field_list_arr_free(shared_tag, 1); + free(ret_cube_id_arr); + + struct field_list *tag_list = NULL; + size_t n_cell = 0; + fieldstat_cube_get_cells(instance_dst, cube_id, &tag_list, &n_cell); + EXPECT_EQ(n_cell, 1); + EXPECT_EQ(tag_list[0].n_field, 0); + EXPECT_TRUE(tag_list[0].field == NULL); + double value; + fieldstat_hll_get(instance_dst, cube_id, &tag_list[0], 0, &value); + EXPECT_NEAR(value, 1, 0.4); + fieldstat_field_list_arr_free(tag_list, n_cell); + + fieldstat_free(instance_dst); + fieldstat_free(instance_src); +} + +TEST(test_empty_tag, export) +{ + struct fieldstat *instance = test_empty_my_init(); + struct fieldstat_json_exporter *fieldstat_json_exporter = fieldstat_json_exporter_new(); + char *json_string = fieldstat_json_exporter_export(fieldstat_json_exporter, instance, &TEST_TIMEVAL); + // std::cout << "json_string: \n" << json_string << std::endl; + + cJSON *root_arr = cJSON_Parse(json_string); + free(json_string); + fieldstat_json_exporter_free(fieldstat_json_exporter); + fieldstat_free(instance); + + cJSON *root = cJSON_GetArrayItem(root_arr, 0); + // check field + cJSON *field = cJSON_GetObjectItem(root, "tags"); + EXPECT_EQ(cJSON_GetArraySize(field), 0); + + cJSON *metrics = cJSON_GetObjectItem(root, "fields"); + EXPECT_NE(metrics, nullptr); + cJSON *counter = cJSON_GetObjectItem(metrics, "metric"); + EXPECT_EQ(counter->valueint, 1); + + cJSON_Delete(root_arr); +} + +/* -------------------------------------------------------------------------- */ +/* UUID */ +/* -------------------------------------------------------------------------- */ +class UuidTagContext { + private: + std::unordered_map<int, struct field *> fields; + + public: + UuidTagContext() { + + } + + ~UuidTagContext() { + for (auto it = fields.begin(); it != fields.end(); it++) { + free((char *)it->second->key); + free(it->second); + } + } + + struct field *get(int index) { + if (fields.find(index) != fields.end()) { + return fields[index]; + } else { + uuid_t uuid; + uuid_generate(uuid); + struct field *field = (struct field *)malloc(sizeof(struct field)); + field->type = FIELD_VALUE_UUID; + memcpy(field->value_uuid, uuid, sizeof(uuid_t)); + field->key = (const char *)malloc(10); + sprintf((char *)field->key, "key_%d", index); + + fields[index] = field; + return field; + } + } + bool check(int index, struct field *field) { + if (fields.find(index) == fields.end()) { + return false; + } + return uuid_compare(fields[index]->value_uuid, field->value_uuid) == 0; + } + bool check(int index, const char *uuid_str) { + if (fields.find(index) == fields.end()) { + return false; + } + + uuid_t uuid; + uuid_parse(uuid_str, uuid); + return uuid_compare(fields[index]->value_uuid, uuid) == 0; + } +}; + +void check_cell_uuid(const struct fieldstat *instance, int cube_id, int index, long long expected_count, UuidTagContext &context) +{ + struct field_list *tag_list = NULL; + size_t n_cell = 0; + fieldstat_cube_get_cells(instance, cube_id, &tag_list, &n_cell); + EXPECT_EQ(n_cell, 1); + EXPECT_EQ(tag_list[0].n_field, 1); + EXPECT_TRUE(context.check(index, &tag_list[0].field[0])); + long long value; + fieldstat_counter_get(instance, cube_id, &tag_list[0], 0, &value); + EXPECT_EQ(value, expected_count); + fieldstat_field_list_arr_free(tag_list, n_cell); +} + +TEST(test_uuid_tag, add_many_times) +{ + UuidTagContext context; + struct fieldstat *instance = fieldstat_new(); + int cube_id = fieldstat_cube_create(instance, context.get(0), 1); + int metric_id = fieldstat_register_counter(instance, cube_id, "metric"); + fieldstat_cube_set_sampling(instance, cube_id, SAMPLING_MODE_COMPREHENSIVE, 1, 0); + + fieldstat_counter_incrby(instance, cube_id, metric_id, context.get(1), 1, 1); + fieldstat_counter_incrby(instance, cube_id, metric_id, context.get(1), 1, 1); + + check_cell_uuid(instance, cube_id, 1, 2, context); + + fieldstat_free(instance); +} + +struct fieldstat *test_uuid_tag_my_init(UuidTagContext &context,enum sampling_mode mode = SAMPLING_MODE_COMPREHENSIVE) +{ + struct fieldstat *instance = fieldstat_new(); + int cube_id = fieldstat_cube_create(instance, context.get(0), 1); + int metric_id = fieldstat_register_counter(instance, cube_id, "metric"); + fieldstat_cube_set_sampling(instance, cube_id, mode, 1, 0); + + fieldstat_counter_incrby(instance, cube_id, metric_id, context.get(1), 1, 1); + + return instance; +} + +TEST(test_uuid_tag, merge) +{ + UuidTagContext context; + struct fieldstat *instance_src = test_uuid_tag_my_init(context); + struct fieldstat *instance_dst = fieldstat_new(); + + fieldstat_merge(instance_dst, instance_src); + fieldstat_merge(instance_dst, instance_src); + + int *ret_cube_id_arr = NULL; + int n_cube = 0; + fieldstat_get_cubes(instance_dst, &ret_cube_id_arr, &n_cube); + int ret_cube_id = ret_cube_id_arr[0]; + struct field_list *shared_tag = fieldstat_cube_get_dimension(instance_dst, ret_cube_id); + EXPECT_TRUE(context.check(0, &shared_tag->field[0])); + fieldstat_field_list_arr_free(shared_tag, 1); + free(ret_cube_id_arr); + + check_cell_uuid(instance_dst, ret_cube_id, 1, 2, context); + + fieldstat_free(instance_dst); + fieldstat_free(instance_src); +} + +TEST(test_uuid_tag, merge_topk) +{ + UuidTagContext context; + struct fieldstat *instance_src = test_uuid_tag_my_init(context, SAMPLING_MODE_TOPK); + struct fieldstat *instance_dst = fieldstat_new(); + + fieldstat_merge(instance_dst, instance_src); + fieldstat_merge(instance_dst, instance_src); + + int *ret_cube_id_arr = NULL; + int n_cube = 0; + fieldstat_get_cubes(instance_dst, &ret_cube_id_arr, &n_cube); + int ret_cell_id = ret_cube_id_arr[0]; + struct field_list *shared_tag = fieldstat_cube_get_dimension(instance_dst, ret_cell_id); + EXPECT_EQ(shared_tag->n_field, 1); + EXPECT_TRUE(context.check(0, &shared_tag->field[0])); + fieldstat_field_list_arr_free(shared_tag, 1); + free(ret_cube_id_arr); + + check_cell_uuid(instance_dst, ret_cell_id, 1, 2, context); + + fieldstat_free(instance_dst); + fieldstat_free(instance_src); +} + +TEST(test_uuid_tag, merge_spreadsketch) +{ + UuidTagContext context; + struct fieldstat *instance_src = fieldstat_new(); + int cube_id = fieldstat_cube_create(instance_src, context.get(0), 1); + int metric_id = fieldstat_register_hll(instance_src, cube_id, "metric", 4); + fieldstat_cube_set_sampling(instance_src, cube_id, SAMPLING_MODE_TOP_CARDINALITY, 1, 0); + fieldstat_hll_add(instance_src, cube_id, metric_id, context.get(1), 1, "1", 1); + struct fieldstat *instance_dst = fieldstat_new(); + + fieldstat_merge(instance_dst, instance_src); + fieldstat_merge(instance_dst, instance_src); + + struct field_list *tag_list = NULL; + size_t n_cell = 0; + fieldstat_cube_get_cells(instance_dst, cube_id, &tag_list, &n_cell); + EXPECT_EQ(n_cell, 1); + EXPECT_EQ(tag_list[0].n_field, 1); + EXPECT_TRUE(context.check(1, &tag_list[0].field[0])); + double value; + fieldstat_hll_get(instance_dst, cube_id, &tag_list[0], 0, &value); + EXPECT_NEAR(value, 1, 0.4); + fieldstat_field_list_arr_free(tag_list, n_cell); + + fieldstat_free(instance_dst); + fieldstat_free(instance_src); +} + +TEST(test_uuid_tag, export) +{ + UuidTagContext context; + struct fieldstat *instance = test_uuid_tag_my_init(context); + struct fieldstat_json_exporter *fieldstat_json_exporter = fieldstat_json_exporter_new(); + fieldstat_json_exporter_set_global_dimension(fieldstat_json_exporter, context.get(2), 1); + + char *json_string = fieldstat_json_exporter_export(fieldstat_json_exporter, instance, &TEST_TIMEVAL); + // std::cout << "json_string: \n" << json_string << std::endl; + + cJSON *root_arr = cJSON_Parse(json_string); + free(json_string); + fieldstat_json_exporter_free(fieldstat_json_exporter); + fieldstat_free(instance); + + cJSON *root = cJSON_GetArrayItem(root_arr, 0); + + // check field(3 tags) + bool ok_index[3] = {false, false, false}; + cJSON *field = cJSON_GetObjectItem(root, "tags"); + EXPECT_EQ(cJSON_GetArraySize(field), 3); + + for (int index_json = 0; index_json < 3; index_json++) { + cJSON *uuid = cJSON_GetArrayItem(field, index_json); + char *uuid_str = cJSON_GetObjectItem(field, uuid->string)->valuestring; + + for (int index = 0; index < 3; index++) { + if (ok_index[index]) { + continue; + } + + if (context.check(index, uuid_str)) { + ok_index[index] = true; + break; + } + } + } + for (int index = 0; index < 3; index++) { + EXPECT_TRUE(ok_index[index]); + } + + cJSON *metrics = cJSON_GetObjectItem(root, "fields"); + EXPECT_NE(metrics, nullptr); + cJSON *counter = cJSON_GetObjectItem(metrics, "metric"); + EXPECT_EQ(counter->valueint, 1); + + cJSON_Delete(root_arr); +} + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}
\ No newline at end of file |
