| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * License); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License a |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| #include <gtest/gtest.h> |
| #include <unistd.h> |
| #include <utils/db_utils.h> |
| extern "C" { |
| #include "cwrapper/errno_define_c.h" |
| #include "cwrapper/tsfile_cwrapper.h" |
| } |
| |
| #include "common/tablet.h" |
| #include "utils/errno_define.h" |
| namespace CReleaseTest { |
| class CReleaseTest : public testing::Test {}; |
| |
| TEST_F(CReleaseTest, TestCreateFile) { |
| ERRNO error_no = RET_OK; |
| // Create File and Get RET_OK |
| WriteFile file = write_file_new("create_file1.tsfile", &error_no); |
| ASSERT_EQ(RET_OK, error_no); |
| free_write_file(&file); |
| |
| // Already exists |
| file = write_file_new("create_file1.tsfile", &error_no); |
| ASSERT_EQ(RET_ALREADY_EXIST, error_no); |
| ASSERT_EQ(nullptr, file); |
| |
| // Folder |
| file = write_file_new("test/", &error_no); |
| ASSERT_EQ(RET_FILRET_OPEN_ERR, error_no); |
| |
| remove("create_file1.tsfile"); |
| free_write_file(&file); |
| } |
| |
| TEST_F(CReleaseTest, TsFileWriterNew) { |
| ERRNO error_code = RET_OK; |
| |
| TableSchema test_schema; |
| test_schema.table_name = strdup("test_table"); |
| test_schema.column_num = 0; |
| |
| // Invalid schema |
| WriteFile file = write_file_new("test_empty_schema.tsfile", &error_code); |
| ASSERT_EQ(RET_OK, error_code); |
| TsFileWriter writer = tsfile_writer_new(file, &test_schema, &error_code); |
| ASSERT_EQ(RET_INVALID_SCHEMA, error_code); |
| ASSERT_EQ(nullptr, writer); |
| ASSERT_EQ(RET_OK, tsfile_writer_close(writer)); |
| free_write_file(&file); |
| ASSERT_EQ(nullptr, file); |
| remove("test_empty_schema.tsfile"); |
| |
| // Invalid schema with memory threshold |
| file = write_file_new("test_empty_schema_memory_threshold.tsfile", |
| &error_code); |
| ASSERT_EQ(RET_OK, error_code); |
| // Invalid schema |
| writer = tsfile_writer_new_with_memory_threshold(file, &test_schema, 100, |
| &error_code); |
| ASSERT_EQ(RET_INVALID_SCHEMA, error_code); |
| ASSERT_EQ(nullptr, writer); |
| ASSERT_EQ(RET_OK, tsfile_writer_close(writer)); |
| free_write_file(&file); |
| ASSERT_EQ(nullptr, file); |
| remove("test_empty_schema_memory_threshold.tsfile"); |
| |
| // Normal schema |
| file = write_file_new("test_empty_writer.tsfile", &error_code); |
| ASSERT_EQ(RET_OK, error_code); |
| |
| TableSchema table_schema; |
| table_schema.table_name = strdup("test_table"); |
| table_schema.column_num = 2; |
| table_schema.column_schemas = |
| static_cast<ColumnSchema*>(malloc(sizeof(ColumnSchema) * 2)); |
| table_schema.column_schemas[0] = |
| (ColumnSchema){.column_name = strdup("col1"), |
| .data_type = TS_DATATYPE_STRING, |
| .column_category = TAG}; |
| table_schema.column_schemas[1] = |
| (ColumnSchema){.column_name = strdup("col2"), |
| .data_type = TS_DATATYPE_INT32, |
| .column_category = FIELD}; |
| |
| writer = tsfile_writer_new(file, &table_schema, &error_code); |
| ASSERT_EQ(RET_OK, error_code); |
| error_code = tsfile_writer_close(writer); |
| ASSERT_EQ(RET_OK, error_code); |
| free_write_file(&file); |
| remove("test_empty_writer.tsfile"); |
| |
| free_table_schema(table_schema); |
| free_table_schema(test_schema); |
| } |
| |
| TEST_F(CReleaseTest, TsFileWriterWriteDataAbnormalColumn) { |
| remove("TsFileWriterWriteDataAbnormalColumn.tsfile"); |
| ERRNO error_code = RET_OK; |
| WriteFile file = write_file_new( |
| "TsFileWriterWriteDataAbnormalColumn.tsfile", &error_code); |
| |
| TableSchema abnormal_schema; |
| abnormal_schema.table_name = strdup("!@#$%^*()_+-="); |
| abnormal_schema.column_num = 3; |
| abnormal_schema.column_schemas = |
| static_cast<ColumnSchema*>(malloc(sizeof(ColumnSchema) * 4)); |
| abnormal_schema.column_schemas[0] = |
| (ColumnSchema){.column_name = strdup("!@#$%^*()_+-="), |
| .data_type = TS_DATATYPE_STRING, |
| .column_category = TAG}; |
| |
| // TAG's datatype is not correct |
| abnormal_schema.column_schemas[1] = |
| (ColumnSchema){.column_name = strdup("TAG2"), |
| .data_type = TS_DATATYPE_INT32, |
| .column_category = TAG}; |
| |
| // same column name with column[0] |
| abnormal_schema.column_schemas[2] = |
| (ColumnSchema){.column_name = strdup("!@#$%^*()_+-="), |
| .data_type = TS_DATATYPE_DOUBLE, |
| .column_category = FIELD}; |
| |
| // column name conflict |
| TsFileWriter writer = |
| tsfile_writer_new(file, &abnormal_schema, &error_code); |
| ASSERT_EQ(RET_INVALID_SCHEMA, error_code); |
| free(abnormal_schema.column_schemas[2].column_name); |
| |
| abnormal_schema.column_schemas[2] = |
| (ColumnSchema){.column_name = strdup("!@#$%^*()_+-=1"), |
| .data_type = TS_DATATYPE_DOUBLE, |
| .column_category = FIELD}; |
| |
| // datatype conflict |
| writer = tsfile_writer_new(file, &abnormal_schema, &error_code); |
| ASSERT_EQ(RET_INVALID_SCHEMA, error_code); |
| |
| free(abnormal_schema.column_schemas[1].column_name); |
| abnormal_schema.column_schemas[1] = |
| (ColumnSchema){.column_name = strdup("TAG2"), |
| .data_type = TS_DATATYPE_STRING, |
| .column_category = TAG}; |
| |
| writer = tsfile_writer_new(file, &abnormal_schema, &error_code); |
| ASSERT_EQ(RET_OK, error_code); |
| |
| char** column_list = static_cast<char**>(malloc(sizeof(char*) * 3)); |
| column_list[0] = strdup("!@#$%^*()_+-="); |
| column_list[1] = strdup("TAG2"); |
| column_list[2] = strdup("!@#$%^*()_+-=1"); |
| TSDataType* type_list = |
| static_cast<TSDataType*>(malloc(sizeof(TSDataType) * 3)); |
| type_list[0] = TS_DATATYPE_STRING; |
| type_list[1] = TS_DATATYPE_STRING; |
| type_list[2] = TS_DATATYPE_DOUBLE; |
| Tablet tablet = tablet_new(column_list, type_list, 3, 100); |
| for (int i = 0; i < 100; i++) { |
| tablet_add_timestamp(tablet, i, static_cast<int64_t>(i)); |
| tablet_add_value_by_name_string(tablet, i, "!@#$%^*()_+-=", "device1"); |
| tablet_add_value_by_index_string( |
| tablet, i, 1, std::string("sensor" + std::to_string(i)).c_str()); |
| tablet_add_value_by_name_double(tablet, i, "!@#$%^*()_+-=1", i * 100.0); |
| } |
| ASSERT_EQ(RET_OK, tsfile_writer_write(writer, tablet)); |
| ASSERT_EQ(RET_OK, tsfile_writer_close(writer)); |
| free_write_file(&file); |
| |
| TsFileReader reader = tsfile_reader_new( |
| "TsFileWriterWriteDataAbnormalColumn.tsfile", &error_code); |
| ASSERT_EQ(RET_OK, error_code); |
| int i = 0; |
| ResultSet result_set = tsfile_query_table( |
| reader, "!@#$%^*()_+-=", column_list, 3, 0, 100, &error_code); |
| while (tsfile_result_set_next(result_set, &error_code) && |
| error_code == RET_OK) { |
| Timestamp timestamp = |
| tsfile_result_set_get_value_by_name_int64_t(result_set, "time"); |
| ASSERT_EQ(timestamp * 100.0, tsfile_result_set_get_value_by_name_double( |
| result_set, "!@#$%^*()_+-=1")); |
| char* value_str = |
| tsfile_result_set_get_value_by_index_string(result_set, 2); |
| ASSERT_EQ("device1", std::string(value_str)); |
| free(value_str); |
| i++; |
| } |
| ASSERT_EQ(100, i); |
| for (int i = 0; i < 3; i++) { |
| free(column_list[i]); |
| } |
| free(column_list); |
| free(type_list); |
| free_write_file(&file); |
| free_table_schema(abnormal_schema); |
| free_tablet(&tablet); |
| free_tsfile_result_set(&result_set); |
| tsfile_reader_close(reader); |
| remove("TsFileWriterWriteDataAbnormalColumn.tsfile"); |
| } |
| |
| TEST_F(CReleaseTest, TsFileWriterMultiDataType) { |
| ERRNO error_code = RET_OK; |
| remove("TsFileWriterMultiDataType.tsfile"); |
| WriteFile file = |
| write_file_new("TsFileWriterMultiDataType.tsfile", &error_code); |
| ASSERT_EQ(RET_OK, error_code); |
| TableSchema all_type_schema; |
| all_type_schema.table_name = strdup("All_Datatype"); |
| all_type_schema.column_num = 6; |
| all_type_schema.column_schemas = |
| static_cast<ColumnSchema*>(malloc(sizeof(ColumnSchema) * 6)); |
| all_type_schema.column_schemas[0] = |
| (ColumnSchema){.column_name = strdup("TAG"), |
| .data_type = TS_DATATYPE_STRING, |
| .column_category = TAG}; |
| all_type_schema.column_schemas[1] = |
| (ColumnSchema){.column_name = strdup("INT32"), |
| .data_type = TS_DATATYPE_INT32, |
| .column_category = FIELD}; |
| all_type_schema.column_schemas[2] = |
| (ColumnSchema){.column_name = strdup("INT64"), |
| .data_type = TS_DATATYPE_INT64, |
| .column_category = FIELD}; |
| all_type_schema.column_schemas[3] = |
| (ColumnSchema){.column_name = strdup("FLOAT"), |
| .data_type = TS_DATATYPE_FLOAT, |
| .column_category = FIELD}; |
| all_type_schema.column_schemas[4] = |
| (ColumnSchema){.column_name = strdup("DOUBLE"), |
| .data_type = TS_DATATYPE_DOUBLE, |
| .column_category = FIELD}; |
| all_type_schema.column_schemas[5] = |
| (ColumnSchema){.column_name = strdup("BOOLEAN"), |
| .data_type = TS_DATATYPE_BOOLEAN, |
| .column_category = FIELD}; |
| |
| TsFileWriter writer = |
| tsfile_writer_new(file, &all_type_schema, &error_code); |
| ASSERT_EQ(RET_OK, error_code); |
| |
| free_table_schema(all_type_schema); |
| char** column_list = static_cast<char**>(malloc(sizeof(char*) * 6)); |
| column_list[0] = strdup("TAG"); |
| column_list[1] = strdup("INT32"); |
| column_list[2] = strdup("INT64"); |
| column_list[3] = strdup("FLOAT"); |
| column_list[4] = strdup("DOUBLE"); |
| column_list[5] = strdup("BOOLEAN"); |
| TSDataType* type_list = |
| static_cast<TSDataType*>(malloc(sizeof(TSDataType) * 6)); |
| type_list[0] = TS_DATATYPE_STRING; |
| type_list[1] = TS_DATATYPE_INT32; |
| type_list[2] = TS_DATATYPE_INT64; |
| type_list[3] = TS_DATATYPE_FLOAT; |
| type_list[4] = TS_DATATYPE_DOUBLE; |
| type_list[5] = TS_DATATYPE_BOOLEAN; |
| Tablet tablet = tablet_new(column_list, type_list, 6, 1000); |
| for (int i = 0; i < 1000; i++) { |
| // negative timestamp included |
| tablet_add_timestamp(tablet, i, static_cast<int64_t>(i - 10)); |
| tablet_add_value_by_name_string(tablet, i, "TAG", "device1"); |
| tablet_add_value_by_name_int32_t(tablet, i, "INT32", i); |
| tablet_add_value_by_index_int64_t(tablet, i, 2, i * 100); |
| tablet_add_value_by_index_float(tablet, i, 3, i * 100.0); |
| if (i > 900) { |
| continue; |
| } |
| // Null value |
| tablet_add_value_by_index_double(tablet, i, 4, i * 100.0); |
| tablet_add_value_by_index_bool(tablet, i, 5, i % 2 == 0); |
| } |
| ASSERT_EQ(RET_OK, tsfile_writer_write(writer, tablet)); |
| ASSERT_EQ(RET_OK, tsfile_writer_close(writer)); |
| free_write_file(&file); |
| |
| TsFileReader reader = |
| tsfile_reader_new("TsFileWriterMultiDataType.tsfile", &error_code); |
| ASSERT_EQ(RET_OK, error_code); |
| ResultSet result_set = tsfile_query_table( |
| reader, "all_datatype", column_list, 6, 0, 1000, &error_code); |
| int row_num = 0; |
| while (tsfile_result_set_next(result_set, &error_code) && |
| error_code == RET_OK) { |
| Timestamp timestamp = |
| tsfile_result_set_get_value_by_name_int64_t(result_set, "time"); |
| int64_t value = timestamp + 10; |
| char* str_value = |
| tsfile_result_set_get_value_by_name_string(result_set, "TAG"); |
| ASSERT_EQ("device1", std::string(str_value)); |
| free(str_value); |
| ASSERT_EQ(value, tsfile_result_set_get_value_by_name_int32_t(result_set, |
| "int32")); |
| ASSERT_EQ(value * 100, tsfile_result_set_get_value_by_name_int64_t( |
| result_set, "int64")); |
| ASSERT_EQ(value * 100.0, tsfile_result_set_get_value_by_name_float( |
| result_set, "FLOAT")); |
| |
| if (value <= 900) { |
| ASSERT_EQ(value * 100.0, tsfile_result_set_get_value_by_name_double( |
| result_set, "DOUBLE")); |
| ASSERT_EQ(value % 2 == 0, tsfile_result_set_get_value_by_name_bool( |
| result_set, "BOOLEAN")); |
| } else { |
| ASSERT_TRUE( |
| tsfile_result_set_is_null_by_name(result_set, "DOUBLE")); |
| } |
| row_num++; |
| } |
| ASSERT_EQ(990, row_num); |
| free_tsfile_result_set(&result_set); |
| tsfile_reader_close(reader); |
| for (int i = 0; i < 6; i++) { |
| free(column_list[i]); |
| } |
| free_tablet(&tablet); |
| free(column_list); |
| free(type_list); |
| remove("TsFileWriterMultiDataType.tsfile"); |
| } |
| |
| TEST_F(CReleaseTest, TsFileWriterConfTest) { |
| ERRNO err_no = RET_OK; |
| WriteFile file = write_file_new("plain_file.tsfile", &err_no); |
| TableSchema plain_schema; |
| plain_schema.table_name = strdup("plain_table"); |
| plain_schema.column_num = 2; |
| |
| plain_schema.column_schemas = |
| (ColumnSchema*)malloc(sizeof(ColumnSchema) * 2); |
| plain_schema.column_schemas[0].column_name = strdup("id"); |
| plain_schema.column_schemas[0].data_type = TS_DATATYPE_STRING; |
| plain_schema.column_schemas[0].column_category = ColumnCategory::TAG; |
| plain_schema.column_schemas[1].column_name = strdup("value"); |
| plain_schema.column_schemas[1].data_type = TS_DATATYPE_INT64; |
| plain_schema.column_schemas[1].column_category = ColumnCategory::FIELD; |
| |
| set_global_compression(TS_COMPRESSION_UNCOMPRESSED); |
| set_datatype_encoding(TS_DATATYPE_INT64, TS_ENCODING_PLAIN); |
| TsFileWriter writer = tsfile_writer_new(file, &plain_schema, &err_no); |
| free_table_schema(plain_schema); |
| |
| char** column_list = static_cast<char**>(malloc(sizeof(char*) * 2)); |
| column_list[0] = strdup("id"); |
| column_list[1] = strdup("value"); |
| |
| TSDataType* type_list = |
| static_cast<TSDataType*>(malloc(sizeof(TSDataType) * 2)); |
| type_list[0] = TS_DATATYPE_STRING; |
| type_list[1] = TS_DATATYPE_INT64; |
| |
| Tablet tablet = tablet_new(column_list, type_list, 2, 10); |
| for (int i = 0; i < 10; i++) { |
| tablet_add_timestamp(tablet, i, static_cast<int64_t>(i)); |
| tablet_add_value_by_name_string(tablet, i, "id", "device1"); |
| tablet_add_value_by_name_int32_t(tablet, i, "value", i); |
| } |
| |
| ASSERT_EQ(RET_OK, tsfile_writer_write(writer, tablet)); |
| ASSERT_EQ(RET_OK, tsfile_writer_close(writer)); |
| free_write_file(&file); |
| TsFileReader reader = tsfile_reader_new("plain_file.tsfile", &err_no); |
| ASSERT_EQ(RET_OK, err_no); |
| TableSchema schema = tsfile_reader_get_table_schema(reader, "plain_table"); |
| ASSERT_EQ(schema.column_num, 2); |
| uint32_t size = 0; |
| DeviceSchema* device_schema = |
| tsfile_reader_get_all_timeseries_schemas(reader, &size); |
| ASSERT_EQ(1, size); |
| ASSERT_EQ(1, device_schema->timeseries_num); |
| ASSERT_EQ(device_schema->timeseries_schema[0].encoding, TS_ENCODING_PLAIN); |
| ASSERT_EQ(device_schema->timeseries_schema[0].compression, |
| TS_COMPRESSION_UNCOMPRESSED); |
| tsfile_reader_close(reader); |
| free_table_schema(schema); |
| free_device_schema(*device_schema); |
| free(device_schema); |
| free(column_list[0]); |
| free(column_list[1]); |
| free(column_list); |
| free(type_list); |
| free_tablet(&tablet); |
| |
| remove("plain_file.tsfile"); |
| } |
| |
| } // namespace CReleaseTest |