summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorchenzizhan <[email protected]>2024-09-26 14:51:49 +0800
committerchenzizhan <[email protected]>2024-09-26 14:51:49 +0800
commit2d9b9cda59297fa80889c875b909881d25709045 (patch)
tree4a99b82409e6ca0316b98cbf7e089dbf78721e17
parent8a85bbf91bdae7ccab03085e5b8118fd0207e5d6 (diff)
uuid type field(dimension)v4.6.6
-rw-r--r--CMakeLists.txt15
-rw-r--r--ctest/CMakeLists.txt4
-rw-r--r--include/fieldstat/fieldstat.h3
-rw-r--r--src/cube.c12
-rw-r--r--src/exporter/cjson_exporter.c92
-rw-r--r--test/CMakeLists.txt4
-rw-r--r--test/test_empty_tags.cpp165
-rw-r--r--test/test_special_tags.cpp399
8 files changed, 464 insertions, 230 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 80c6cd3..9843401 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)
@@ -126,6 +126,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)
@@ -136,6 +138,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 18532fc..cb0851a 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;
};
};
diff --git a/src/cube.c b/src/cube.c
index 62d9933..1c3e6df 100644
--- a/src/cube.c
+++ b/src/cube.c
@@ -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