diff --git a/dbms/CMakeLists.txt b/dbms/CMakeLists.txt index d8abac2fac7..6fe83e0ce8b 100644 --- a/dbms/CMakeLists.txt +++ b/dbms/CMakeLists.txt @@ -266,7 +266,8 @@ if (ENABLE_TESTS) # attach all dbms gtest sources grep_gtest_sources(${ClickHouse_SOURCE_DIR}/dbms dbms_gtest_sources) - add_executable(unit_tests_dbms ${dbms_gtest_sources}) - target_link_libraries(unit_tests_dbms gtest_main dbms) - add_check(unit_tests_dbms) + add_executable(gtests_dbms EXCLUDE_FROM_ALL ${dbms_gtest_sources}) + target_link_libraries(gtests_dbms gtest_main dbms clickhouse_functions) + target_compile_options(gtests_dbms PRIVATE -Wno-unknown-pragmas) + add_check(gtests_dbms) endif () diff --git a/dbms/src/Analyzers/CMakeLists.txt b/dbms/src/Analyzers/CMakeLists.txt index 36cab0b3590..b2aec21574d 100644 --- a/dbms/src/Analyzers/CMakeLists.txt +++ b/dbms/src/Analyzers/CMakeLists.txt @@ -1,3 +1,3 @@ if(ENABLE_TESTS) - add_subdirectory(tests) + add_subdirectory(tests EXCLUDE_FROM_ALL) endif() diff --git a/dbms/src/Common/CMakeLists.txt b/dbms/src/Common/CMakeLists.txt index 61d9b9771a4..8af30705b15 100644 --- a/dbms/src/Common/CMakeLists.txt +++ b/dbms/src/Common/CMakeLists.txt @@ -4,5 +4,5 @@ add_subdirectory(StringUtils) #add_subdirectory(ConfigProcessor) if (ENABLE_TESTS) - add_subdirectory (tests) + add_subdirectory (tests EXCLUDE_FROM_ALL) endif () diff --git a/dbms/src/Common/ZooKeeper/CMakeLists.txt b/dbms/src/Common/ZooKeeper/CMakeLists.txt index 197b53da00d..493dae7a3dc 100644 --- a/dbms/src/Common/ZooKeeper/CMakeLists.txt +++ b/dbms/src/Common/ZooKeeper/CMakeLists.txt @@ -7,5 +7,5 @@ add_library(clickhouse_common_zookeeper ${SPLIT_SHARED} ${clickhouse_common_zook target_link_libraries (clickhouse_common_zookeeper clickhouse_common_io) if (ENABLE_TESTS) - add_subdirectory (tests) + add_subdirectory (tests EXCLUDE_FROM_ALL) endif () diff --git a/dbms/src/Common/ZooKeeper/tests/gtest_zkutil_test_multi_exception.cpp b/dbms/src/Common/ZooKeeper/tests/gtest_zkutil_test_multi_exception.cpp index 915b31d420b..0947e60cf8a 100644 --- a/dbms/src/Common/ZooKeeper/tests/gtest_zkutil_test_multi_exception.cpp +++ b/dbms/src/Common/ZooKeeper/tests/gtest_zkutil_test_multi_exception.cpp @@ -15,7 +15,9 @@ using namespace DB; -TEST(zkutil, zookeeper_connected) +/// Disable zookeeper tests since tiflash don't use zookeeper + +TEST(zkutil, DISABLED_zookeeper_connected) { auto zookeeper = std::make_unique("localhost:2181"); try @@ -29,7 +31,7 @@ TEST(zkutil, zookeeper_connected) } } -TEST(zkutil, multi_nice_exception_msg) +TEST(zkutil, DISABLED_multi_nice_exception_msg) { auto zookeeper = std::make_unique("localhost:2181"); @@ -67,7 +69,7 @@ TEST(zkutil, multi_nice_exception_msg) } -TEST(zkutil, multi_async) +TEST(zkutil, DISABLED_multi_async) { auto zookeeper = std::make_unique("localhost:2181"); zkutil::Requests ops; @@ -129,7 +131,7 @@ TEST(zkutil, multi_async) } } -TEST(zkutil, watch_get_children_with_chroot) +TEST(zkutil, DISABLED_watch_get_children_with_chroot) { try { @@ -160,7 +162,7 @@ TEST(zkutil, watch_get_children_with_chroot) } } -TEST(zkutil, multi_create_sequential) +TEST(zkutil, DISABLED_multi_create_sequential) { try { diff --git a/dbms/src/Core/CMakeLists.txt b/dbms/src/Core/CMakeLists.txt index 65172356645..433b18404b7 100644 --- a/dbms/src/Core/CMakeLists.txt +++ b/dbms/src/Core/CMakeLists.txt @@ -1,3 +1,3 @@ if (ENABLE_TESTS) - add_subdirectory (tests) + add_subdirectory (tests EXCLUDE_FROM_ALL) endif () diff --git a/dbms/src/DataStreams/CMakeLists.txt b/dbms/src/DataStreams/CMakeLists.txt index 65172356645..433b18404b7 100644 --- a/dbms/src/DataStreams/CMakeLists.txt +++ b/dbms/src/DataStreams/CMakeLists.txt @@ -1,3 +1,3 @@ if (ENABLE_TESTS) - add_subdirectory (tests) + add_subdirectory (tests EXCLUDE_FROM_ALL) endif () diff --git a/dbms/src/DataStreams/tests/CMakeLists.txt b/dbms/src/DataStreams/tests/CMakeLists.txt index 8c3acb1332e..00f21f56dc4 100644 --- a/dbms/src/DataStreams/tests/CMakeLists.txt +++ b/dbms/src/DataStreams/tests/CMakeLists.txt @@ -3,28 +3,28 @@ include_directories (${CMAKE_CURRENT_BINARY_DIR}) set(SRCS ) add_executable (tab_separated_streams tab_separated_streams.cpp ${SRCS}) -target_link_libraries (tab_separated_streams dbms) +target_link_libraries (tab_separated_streams dbms clickhouse_functions) add_executable (block_row_transforms block_row_transforms.cpp ${SRCS}) -target_link_libraries (block_row_transforms dbms) +target_link_libraries (block_row_transforms dbms clickhouse_functions) add_executable (expression_stream expression_stream.cpp ${SRCS}) -target_link_libraries (expression_stream dbms clickhouse_storages_system) +target_link_libraries (expression_stream dbms clickhouse_storages_system clickhouse_functions) add_executable (native_streams native_streams.cpp ${SRCS}) -target_link_libraries (native_streams dbms) +target_link_libraries (native_streams dbms clickhouse_functions) add_executable (filter_stream filter_stream.cpp ${SRCS}) -target_link_libraries (filter_stream dbms clickhouse_storages_system) +target_link_libraries (filter_stream dbms clickhouse_storages_system clickhouse_functions) add_executable (filter_stream_hitlog filter_stream_hitlog.cpp ${SRCS}) -target_link_libraries (filter_stream_hitlog dbms) +target_link_libraries (filter_stream_hitlog dbms clickhouse_functions) add_executable (sorting_stream sorting_stream.cpp ${SRCS}) -target_link_libraries (sorting_stream dbms) +target_link_libraries (sorting_stream dbms clickhouse_functions) add_executable (union_stream2 union_stream2.cpp ${SRCS}) -target_link_libraries (union_stream2 dbms) +target_link_libraries (union_stream2 dbms clickhouse_functions) add_executable (collapsing_sorted_stream collapsing_sorted_stream.cpp ${SRCS}) -target_link_libraries (collapsing_sorted_stream dbms) +target_link_libraries (collapsing_sorted_stream dbms clickhouse_functions) diff --git a/dbms/src/DataTypes/CMakeLists.txt b/dbms/src/DataTypes/CMakeLists.txt index 65172356645..433b18404b7 100644 --- a/dbms/src/DataTypes/CMakeLists.txt +++ b/dbms/src/DataTypes/CMakeLists.txt @@ -1,3 +1,3 @@ if (ENABLE_TESTS) - add_subdirectory (tests) + add_subdirectory (tests EXCLUDE_FROM_ALL) endif () diff --git a/dbms/src/Debug/DBGInvoker.cpp b/dbms/src/Debug/DBGInvoker.cpp index acd6b61ba21..512f1468c0d 100644 --- a/dbms/src/Debug/DBGInvoker.cpp +++ b/dbms/src/Debug/DBGInvoker.cpp @@ -34,9 +34,11 @@ DBGInvoker::DBGInvoker() regFunc("sleep", dbgFuncSleep); regFunc("mock_tidb_table", MockTiDBTable::dbgFuncMockTiDBTable); + regFunc("mock_tidb_db", MockTiDBTable::dbgFuncMockTiDBDB); regFunc("mock_tidb_partition", MockTiDBTable::dbgFuncMockTiDBPartition); regFunc("rename_table_for_partition", MockTiDBTable::dbgFuncRenameTableForPartition); regFunc("drop_tidb_table", MockTiDBTable::dbgFuncDropTiDBTable); + regFunc("drop_tidb_db", MockTiDBTable::dbgFuncDropTiDBDB); regFunc("add_column_to_tidb_table", MockTiDBTable::dbgFuncAddColumnToTiDBTable); regFunc("drop_column_from_tidb_table", MockTiDBTable::dbgFuncDropColumnFromTiDBTable); regFunc("modify_column_in_tidb_table", MockTiDBTable::dbgFuncModifyColumnInTiDBTable); @@ -63,6 +65,7 @@ DBGInvoker::DBGInvoker() regFunc("enable_schema_sync_service", dbgFuncEnableSchemaSyncService); regFunc("refresh_schemas", dbgFuncRefreshSchemas); + regFunc("reset_schemas", dbgFuncResetSchemas); } void replaceSubstr(std::string & str, const std::string & target, const std::string & replacement) diff --git a/dbms/src/Debug/MockTiDB.cpp b/dbms/src/Debug/MockTiDB.cpp index 9957e8831ad..70c25cec551 100644 --- a/dbms/src/Debug/MockTiDB.cpp +++ b/dbms/src/Debug/MockTiDB.cpp @@ -26,7 +26,25 @@ Table::Table(const String & database_name_, const String & table_name_, TableInf : table_info(std::move(table_info_)), database_name(database_name_), table_name(table_name_) {} -void MockTiDB::dropTable(const String & database_name, const String & table_name) +MockTiDB::MockTiDB() { databases["default"] = 0; } + +void MockTiDB::dropDB(const String & database_name) +{ + version++; + + SchemaDiff diff; + diff.type = SchemaActionDropSchema; + if (databases.find(database_name) == databases.end()) + diff.schema_id = -1; + else + diff.schema_id = databases[database_name]; + diff.version = version; + version_diff[version] = diff; + + databases.erase(database_name); +} + +void MockTiDB::dropTable(const String & database_name, const String & table_name, bool is_drop_db) { std::lock_guard lock(tables_mutex); @@ -47,14 +65,17 @@ void MockTiDB::dropTable(const String & database_name, const String & table_name tables_by_name.erase(it_by_name); - version++; - - SchemaDiff diff; - diff.type = SchemaActionDropTable; - diff.schema_id = table->table_info.db_id; - diff.table_id = table->id(); - diff.version = version; - version_diff[version] = diff; + if (!is_drop_db) + { + version++; + + SchemaDiff diff; + diff.type = SchemaActionDropTable; + diff.schema_id = table->table_info.db_id; + diff.table_id = table->id(); + diff.version = version; + version_diff[version] = diff; + } } ColumnInfo getColumnInfoFromColumn(const NameAndTypePair & column, ColumnID id) @@ -112,6 +133,26 @@ ColumnInfo getColumnInfoFromColumn(const NameAndTypePair & column, ColumnID id) return column_info; } +DatabaseID MockTiDB::newDataBase(const String & database_name) +{ + DatabaseID schema_id = 0; + + if (databases.find(database_name) == databases.end()) + { + schema_id = databases.size() + 1; + databases.emplace(database_name, schema_id); + } + + version++; + SchemaDiff diff; + diff.type = SchemaActionCreateSchema; + diff.schema_id = schema_id; + diff.version = version; + version_diff[version] = diff; + + return schema_id; +} + TableID MockTiDB::newTable(const String & database_name, const String & table_name, const ColumnsDescription & columns, Timestamp tso) { std::lock_guard lock(tables_mutex); @@ -124,9 +165,9 @@ TableID MockTiDB::newTable(const String & database_name, const String & table_na TableInfo table_info; - if (databases.find(database_name) != databases.end()) + if (databases.find(database_name) == databases.end()) { - databases.emplace(database_name, databases.size()); + throw Exception("MockTiDB not found db: " + database_name, ErrorCodes::LOGICAL_ERROR); } table_info.db_id = databases[database_name]; table_info.db_name = database_name; diff --git a/dbms/src/Debug/MockTiDB.h b/dbms/src/Debug/MockTiDB.h index 7465b132874..de2eb517111 100644 --- a/dbms/src/Debug/MockTiDB.h +++ b/dbms/src/Debug/MockTiDB.h @@ -23,6 +23,7 @@ class MockTiDB : public ext::singleton friend class ext::singleton; public: + MockTiDB(); class Table { friend class MockTiDB; @@ -65,9 +66,13 @@ class MockTiDB : public ext::singleton public: TableID newTable(const String & database_name, const String & table_name, const ColumnsDescription & columns, Timestamp tso); + DatabaseID newDataBase(const String & database_name); + TableID newPartition(const String & database_name, const String & table_name, const String & partition_name, Timestamp tso); - void dropTable(const String & database_name, const String & table_name); + void dropTable(const String & database_name, const String & table_name, bool is_drop_db); + + void dropDB(const String & database_name); void addColumnToTable(const String & database_name, const String & table_name, const NameAndTypePair & column); diff --git a/dbms/src/Debug/dbgFuncMockTiDBTable.cpp b/dbms/src/Debug/dbgFuncMockTiDBTable.cpp index 02237d35c56..e787a8f6cab 100644 --- a/dbms/src/Debug/dbgFuncMockTiDBTable.cpp +++ b/dbms/src/Debug/dbgFuncMockTiDBTable.cpp @@ -49,6 +49,20 @@ void MockTiDBTable::dbgFuncMockTiDBTable(Context & context, const ASTs & args, D output(ss.str()); } +void MockTiDBTable::dbgFuncMockTiDBDB(Context &, const ASTs & args, DBGInvoker::Printer output) +{ + if (args.size() != 1) + throw Exception("Args not matched, should be: database-name", ErrorCodes::BAD_ARGUMENTS); + + const String & database_name = typeid_cast(*args[0]).name; + + DatabaseID db_id = MockTiDB::instance().newDataBase(database_name); + + std::stringstream ss; + ss << "mock db #" << db_id; + output(ss.str()); +} + void MockTiDBTable::dbgFuncMockTiDBPartition(Context & context, const ASTs & args, DBGInvoker::Printer output) { if (args.size() != 3) @@ -96,6 +110,26 @@ void MockTiDBTable::dbgFuncRenameTableForPartition(Context & context, const ASTs output(ss.str()); } +void MockTiDBTable::dbgFuncDropTiDBDB(Context & context, const ASTs & args, DBGInvoker::Printer output) +{ + if (args.size() != 1 && args.size() != 2) + throw Exception("Args not matched, should be: database-name [, drop-regions]", ErrorCodes::BAD_ARGUMENTS); + + const String & database_name = typeid_cast(*args[0]).name; + bool drop_regions = true; + if (args.size() == 3) + drop_regions = typeid_cast(*args[1]).name == "true"; + + std::vector table_names; + MockTiDB::instance().traverseTables([&](MockTiDB::TablePtr table) { + if (table->table_info.db_name == database_name) + table_names.push_back(table->table_info.name); + }); + for (auto table_name : table_names) + dbgFuncDropTiDBTableImpl(context, database_name, table_name, drop_regions, true, output); + MockTiDB::instance().dropDB(database_name); +} + void MockTiDBTable::dbgFuncDropTiDBTable(Context & context, const ASTs & args, DBGInvoker::Printer output) { if (args.size() != 2 && args.size() != 3) @@ -106,7 +140,12 @@ void MockTiDBTable::dbgFuncDropTiDBTable(Context & context, const ASTs & args, D bool drop_regions = true; if (args.size() == 3) drop_regions = typeid_cast(*args[1]).name == "true"; + dbgFuncDropTiDBTableImpl(context, database_name, table_name, drop_regions, false, output); +} +void MockTiDBTable::dbgFuncDropTiDBTableImpl( + Context & context, String database_name, String table_name, bool drop_regions, bool is_drop_db, DBGInvoker::Printer output) +{ MockTiDB::TablePtr table = nullptr; TableID table_id = InvalidTableID; try @@ -144,7 +183,7 @@ void MockTiDBTable::dbgFuncDropTiDBTable(Context & context, const ASTs & args, D region_table.mockDropRegionsInTable(table_id); } - MockTiDB::instance().dropTable(database_name, table_name); + MockTiDB::instance().dropTable(database_name, table_name, is_drop_db); std::stringstream ss; ss << "dropped table #" << table_id; diff --git a/dbms/src/Debug/dbgFuncMockTiDBTable.h b/dbms/src/Debug/dbgFuncMockTiDBTable.h index 92b29a7589a..98582d2f5cf 100644 --- a/dbms/src/Debug/dbgFuncMockTiDBTable.h +++ b/dbms/src/Debug/dbgFuncMockTiDBTable.h @@ -17,6 +17,11 @@ struct MockTiDBTable // ./storages-client.sh "DBGInvoke mock_tidb_table(database_name, table_name, 'col1 type1, col2 type2, ...')" static void dbgFuncMockTiDBTable(Context & context, const ASTs & args, DBGInvoker::Printer output); + // Inject mocked TiDB table. + // Usage: + // ./storages-client.sh "DBGInvoke mock_tidb_db(database_name) + static void dbgFuncMockTiDBDB(Context & context, const ASTs & args, DBGInvoker::Printer output); + // Inject a partition into mocked TiDB table. // Usage: // ./storages-client.sh "DBGInvoke mock_tidb_partition(database_name, table_name, partition_name)" @@ -34,6 +39,11 @@ struct MockTiDBTable // ./storages-client.sh "DBGInvoke drop_tidb_table(database_name, table_name)" static void dbgFuncDropTiDBTable(Context & context, const ASTs & args, DBGInvoker::Printer output); + // Drop a mocked TiDB table. + // Usage: + // ./storages-client.sh "DBGInvoke drop_tidb_db(database_name)" + static void dbgFuncDropTiDBDB(Context & context, const ASTs & args, DBGInvoker::Printer output); + // Add a column to a mocked TiDB table. // Usage: // ./storages-client.sh "DBGInvoke add_column_to_tidb_table(database_name, table_name, 'col type')" @@ -58,6 +68,15 @@ struct MockTiDBTable // Usage: // ./storages-client.sh "DBGInvoke truncate_tidb_table(database_name, table_name)" static void dbgFuncTruncateTiDBTable(Context & context, const ASTs & args, DBGInvoker::Printer output); + + // Reset Schema Syncer. + // Usage: + // ./storages-client.sh "DBGInvoke reset_syncer()" + static void dbgFuncResetSyncer(Context & context, const ASTs & args, DBGInvoker::Printer output); + +private: + static void dbgFuncDropTiDBTableImpl( + Context & context, String database_name, String table_name, bool drop_regions, bool is_drop_db, DBGInvoker::Printer output); }; } // namespace DB diff --git a/dbms/src/Debug/dbgFuncSchema.cpp b/dbms/src/Debug/dbgFuncSchema.cpp index 9d03b7debee..039cd556ce2 100644 --- a/dbms/src/Debug/dbgFuncSchema.cpp +++ b/dbms/src/Debug/dbgFuncSchema.cpp @@ -49,4 +49,15 @@ void dbgFuncRefreshSchemas(Context & context, const ASTs &, DBGInvoker::Printer output(ss.str()); } +void dbgFuncResetSchemas(Context & context, const ASTs &, DBGInvoker::Printer output) +{ + TMTContext & tmt = context.getTMTContext(); + auto schema_syncer = tmt.getSchemaSyncer(); + schema_syncer->reset(); + + std::stringstream ss; + ss << "reset schemas"; + output(ss.str()); +} + } // namespace DB diff --git a/dbms/src/Debug/dbgFuncSchema.h b/dbms/src/Debug/dbgFuncSchema.h index 76b6ccd0152..3844cc0dd68 100644 --- a/dbms/src/Debug/dbgFuncSchema.h +++ b/dbms/src/Debug/dbgFuncSchema.h @@ -18,4 +18,10 @@ void dbgFuncEnableSchemaSyncService(Context & context, const ASTs & args, DBGInv // ./storage-client.sh "DBGInvoke refresh_schemas()" void dbgFuncRefreshSchemas(Context & context, const ASTs & args, DBGInvoker::Printer output); +// Reset schemas. +// Usage: +// ./storages-client.sh "DBGInvoke reset_schemas()" +void dbgFuncResetSchemas(Context & context, const ASTs & args, DBGInvoker::Printer output); + + } // namespace DB diff --git a/dbms/src/Functions/CMakeLists.txt b/dbms/src/Functions/CMakeLists.txt index cbc5288eac5..a827ad64130 100644 --- a/dbms/src/Functions/CMakeLists.txt +++ b/dbms/src/Functions/CMakeLists.txt @@ -100,5 +100,5 @@ if (USE_VECTORCLASS) endif () if (ENABLE_TESTS) - add_subdirectory (tests) + add_subdirectory (tests EXCLUDE_FROM_ALL) endif () diff --git a/dbms/src/Functions/tests/CMakeLists.txt b/dbms/src/Functions/tests/CMakeLists.txt index b8ee368bf43..e9c98d2e1f7 100644 --- a/dbms/src/Functions/tests/CMakeLists.txt +++ b/dbms/src/Functions/tests/CMakeLists.txt @@ -7,4 +7,4 @@ add_executable (strings_trim strings_trim.cpp) target_link_libraries (strings_trim dbms gtest_main clickhouse_functions) add_executable (strings_pad strings_pad.cpp) -target_link_libraries (strings_pad dbms gtest_main clickhouse_functions) \ No newline at end of file +target_link_libraries (strings_pad dbms gtest_main clickhouse_functions) diff --git a/dbms/src/IO/CMakeLists.txt b/dbms/src/IO/CMakeLists.txt index 65172356645..433b18404b7 100644 --- a/dbms/src/IO/CMakeLists.txt +++ b/dbms/src/IO/CMakeLists.txt @@ -1,3 +1,3 @@ if (ENABLE_TESTS) - add_subdirectory (tests) + add_subdirectory (tests EXCLUDE_FROM_ALL) endif () diff --git a/dbms/src/Interpreters/CMakeLists.txt b/dbms/src/Interpreters/CMakeLists.txt index 4df38a7f25b..ce411588515 100644 --- a/dbms/src/Interpreters/CMakeLists.txt +++ b/dbms/src/Interpreters/CMakeLists.txt @@ -46,5 +46,5 @@ set (CONFIG_COMPILE ${ClickHouse_BINARY_DIR}/dbms/src/Interpreters/config_compil configure_file (${ClickHouse_SOURCE_DIR}/dbms/src/Interpreters/config_compile.h.in ${CONFIG_COMPILE}) if (ENABLE_TESTS) - add_subdirectory (tests) + add_subdirectory (tests EXCLUDE_FROM_ALL) endif () diff --git a/dbms/src/Parsers/CMakeLists.txt b/dbms/src/Parsers/CMakeLists.txt index 491560b1856..1bfef8d629c 100644 --- a/dbms/src/Parsers/CMakeLists.txt +++ b/dbms/src/Parsers/CMakeLists.txt @@ -5,5 +5,5 @@ target_link_libraries (clickhouse_parsers clickhouse_common_io) target_include_directories (clickhouse_parsers PUBLIC ${DBMS_INCLUDE_DIR}) if (ENABLE_TESTS) - add_subdirectory (tests) + add_subdirectory (tests EXCLUDE_FROM_ALL) endif () diff --git a/dbms/src/Server/Server.cpp b/dbms/src/Server/Server.cpp index db74b6cfa8f..7e74e484ce9 100644 --- a/dbms/src/Server/Server.cpp +++ b/dbms/src/Server/Server.cpp @@ -379,8 +379,9 @@ int Server::main(const std::vector & /*args*/) String ignore_dbs = config().getString("raft.ignore_databases"); Poco::StringTokenizer string_tokens(ignore_dbs, ","); std::stringstream ss; - for (const auto & string_token : string_tokens) + for (auto string_token : string_tokens) { + string_token = Poco::trimInPlace(string_token); ignore_databases.emplace(string_token); ss << string_token << std::endl; } diff --git a/dbms/src/Storages/CMakeLists.txt b/dbms/src/Storages/CMakeLists.txt index 75aaf50d5a2..33353edcc10 100644 --- a/dbms/src/Storages/CMakeLists.txt +++ b/dbms/src/Storages/CMakeLists.txt @@ -1,7 +1,7 @@ add_subdirectory (System) if (ENABLE_TESTS) - add_subdirectory (tests) - add_subdirectory (Transaction/tests) - add_subdirectory (Page/tests) + add_subdirectory (tests EXCLUDE_FROM_ALL) + add_subdirectory (Transaction/tests EXCLUDE_FROM_ALL) + add_subdirectory (Page/tests EXCLUDE_FROM_ALL) endif () diff --git a/dbms/src/Storages/Page/tests/CMakeLists.txt b/dbms/src/Storages/Page/tests/CMakeLists.txt index 33d9262f22a..c31f170193c 100644 --- a/dbms/src/Storages/Page/tests/CMakeLists.txt +++ b/dbms/src/Storages/Page/tests/CMakeLists.txt @@ -1,15 +1,29 @@ +add_headers_and_sources(page_storage ../) +add_library(page_storage + ${page_storage_headers} ${page_storage_sources}) +target_link_libraries(page_storage clickhouse_common_io) -add_executable(page_test_page_storage gtest_page_storage.cpp) -target_link_libraries(page_test_page_storage gtest_main dbms) +# glob all unit tests of dm into gtests_page_storage +macro(grep_gtest_sources BASE_DIR DST_VAR) + # Cold match files that are not in tests/ directories + file(GLOB_RECURSE "${DST_VAR}" RELATIVE "${BASE_DIR}" "gtest*.cpp") +endmacro() -add_executable(page_test_page_file gtest_page_file.cpp) -target_link_libraries(page_test_page_file gtest_main dbms) +# attach all dm gtest sources +grep_gtest_sources(${ClickHouse_SOURCE_DIR}/dbms/src/Storages/Page/tests ps_gtest_sources) +add_executable(gtests_page_storage ${ps_gtest_sources}) +target_link_libraries(gtests_page_storage gtest_main page_storage) +target_compile_options(gtests_page_storage PRIVATE -Wno-unknown-pragmas) +add_check(gtests_page_storage) + +# non googletest add_executable(page_stress_page_storage stress_page_stroage.cpp) -target_link_libraries(page_stress_page_storage dbms) +target_link_libraries(page_stress_page_storage page_storage) +target_compile_options(page_stress_page_storage PRIVATE -Wno-format) # turn off printf format check add_executable(page_utils_get_valid_pages utils_get_valid_pages.cpp) -target_link_libraries(page_utils_get_valid_pages dbms) +target_link_libraries(page_utils_get_valid_pages page_storage) target_compile_options(page_utils_get_valid_pages PRIVATE -Wno-format) add_executable(test_page_storage_write_disk_full test_page_storage_write_disk_full.cpp) diff --git a/dbms/src/Storages/Transaction/SchemaBuilder.cpp b/dbms/src/Storages/Transaction/SchemaBuilder.cpp index dd7896095c8..0da1d2e6f8f 100644 --- a/dbms/src/Storages/Transaction/SchemaBuilder.cpp +++ b/dbms/src/Storages/Transaction/SchemaBuilder.cpp @@ -182,6 +182,12 @@ void SchemaBuilder::applyDiff(const SchemaDiff & diff) if (di == nullptr) throw Exception("miss database: " + std::to_string(diff.schema_id)); + if (isIgnoreDB(di->name)) + { + LOG_INFO(log, "ignore schema changes for db: " + di->name); + return; + } + Int64 oldTableID = 0, newTableID = 0; switch (diff.type) @@ -310,7 +316,7 @@ template bool SchemaBuilder::applyCreateSchema(DatabaseID schema_id) { auto db = getter.getDatabase(schema_id); - if (db->name == "") + if (db == nullptr || db->name == "") { return false; } @@ -321,6 +327,12 @@ bool SchemaBuilder::applyCreateSchema(DatabaseID schema_id) template void SchemaBuilder::applyCreateSchemaImpl(TiDB::DBInfoPtr db_info) { + if (isIgnoreDB(db_info->name)) + { + LOG_INFO(log, "ignore schema changes for db: " + db_info->name); + return; + } + ASTCreateQuery * create_query = new ASTCreateQuery(); create_query->database = db_info->name; create_query->if_not_exists = true; @@ -336,13 +348,20 @@ void SchemaBuilder::applyCreateSchemaImpl(TiDB::DBInfoPtr db_info) template void SchemaBuilder::applyDropSchema(DatabaseID schema_id) { - auto database_name = databases[schema_id]; - if (unlikely(database_name == "")) + auto it = databases.find(schema_id); + if (unlikely(it == databases.end())) { LOG_INFO( log, "Syncer wants to drop database: " + std::to_string(schema_id) + " . But database is not found, may has been dropped."); return; } + applyDropSchemaImpl(it->second); + databases.erase(schema_id); +} + +template +void SchemaBuilder::applyDropSchemaImpl(const String & database_name) +{ LOG_INFO(log, "Try to drop database: " + database_name); auto drop_query = std::make_shared(); drop_query->database = database_name; @@ -351,8 +370,6 @@ void SchemaBuilder::applyDropSchema(DatabaseID schema_id) // It will drop all tables in this database. InterpreterDropQuery drop_interpreter(ast_drop_query, context); drop_interpreter.execute(); - - databases.erase(schema_id); } String createTableStmt(const DBInfo & db_info, const TableInfo & table_info) @@ -498,13 +515,18 @@ void SchemaBuilder::applyDropTable(TiDB::DBInfoPtr dbInfo, Int64 table_i // Drop Invalid Tables in Every DB template -void SchemaBuilder::dropInvalidTables(std::vector> table_dbs) +void SchemaBuilder::dropInvalidTablesAndDBs( + const std::vector> & table_dbs, const std::set & db_names) { std::set table_ids; + std::vector> tables_to_drop; + std::set dbs_to_drop; for (auto table_db : table_dbs) + { table_ids.insert(table_db.first->id); + } auto & tmt_context = context.getTMTContext(); auto storage_map = tmt_context.getStorages().getAllStorage(); @@ -515,9 +537,33 @@ void SchemaBuilder::dropInvalidTables(std::vectorgetDatabaseName(); - applyDropTableImpl(db_name, storage->getTableName()); - LOG_DEBUG(log, "Table " + db_name + "." + storage->getTableName() + " is dropped during schema all schemas"); + if (isIgnoreDB(db_name)) + { + continue; + } + tables_to_drop.push_back(std::make_pair(db_name, storage->getTableName())); + } + } + for (auto table : tables_to_drop) + { + applyDropTableImpl(table.first, table.second); + LOG_DEBUG(log, "Table " + table.first + "." + table.second + " is dropped during sync all schemas"); + } + const auto & dbs = context.getDatabases(); + for (auto it = dbs.begin(); it != dbs.end(); it++) + { + String db_name = it->first; + if (isIgnoreDB(db_name)) + { + continue; } + if (db_names.count(db_name) == 0) + dbs_to_drop.insert(db_name); + } + for (auto db : dbs_to_drop) + { + applyDropSchemaImpl(db); + LOG_DEBUG(log, "DB " + db + " is dropped during sync all schemas"); } } @@ -627,32 +673,29 @@ void SchemaBuilder::syncAllSchema() std::vector all_schema = getter.listDBs(); - for (auto db_info : all_schema) + for (auto it = all_schema.begin(); it != all_schema.end();) { - LOG_DEBUG(log, "Load schema : " + db_info->name); - } - - std::set db_ids; - for (auto db : all_schema) - { - db_ids.insert(db->id); + if (isIgnoreDB((*it)->name)) + { + LOG_INFO(log, "ignore schema changes for db: " + (*it)->name); + it = all_schema.erase(it); + } + else + { + it++; + } } - // Drop invalid databases; - for (auto it = databases.begin(); it != databases.end(); it++) + for (auto db_info : all_schema) { - if (db_ids.count(it->first) == 0) - { - applyDropSchema(it->first); - } + LOG_DEBUG(log, "Load schema : " + db_info->name); } // Collect All Table Info and Create DBs. std::vector> all_tables; for (auto db : all_schema) { - auto database_name = databases[db->id]; - if (database_name == "") + if (databases.find(db->id) == databases.end()) { applyCreateSchemaImpl(db); } @@ -663,13 +706,25 @@ void SchemaBuilder::syncAllSchema() } } - dropInvalidTables(all_tables); + std::set db_names; + for (auto db : all_schema) + { + db_names.insert(db->name); + } + + dropInvalidTablesAndDBs(all_tables, db_names); alterAndRenameTables(all_tables); createTables(all_tables); } -template class SchemaBuilder; -template class SchemaBuilder; +template +bool SchemaBuilder::isIgnoreDB(const String & name) +{ + return context.getTMTContext().getIgnoreDatabases().count(name) > 0; +} + +template struct SchemaBuilder; +template struct SchemaBuilder; // end namespace } // namespace DB diff --git a/dbms/src/Storages/Transaction/SchemaBuilder.h b/dbms/src/Storages/Transaction/SchemaBuilder.h index 81341e534e6..f6e47c920bf 100644 --- a/dbms/src/Storages/Transaction/SchemaBuilder.h +++ b/dbms/src/Storages/Transaction/SchemaBuilder.h @@ -6,7 +6,7 @@ namespace DB { -template +template struct SchemaBuilder { @@ -26,13 +26,15 @@ struct SchemaBuilder void applyDiff(const SchemaDiff & diff); - void applyDropSchema(DatabaseID schema_id); - void syncAllSchema(); void applyRenameTableImpl(const String & old_db, const String & new_db, const String & old_table, const String & new_table); private: + void applyDropSchema(DatabaseID schema_id); + + void applyDropSchemaImpl(const String & db_name); + bool applyCreateSchema(DatabaseID schema_id); void applyCreateSchemaImpl(TiDB::DBInfoPtr db_info); @@ -62,7 +64,9 @@ struct SchemaBuilder void alterAndRenameTables(std::vector> table_dbs); - void dropInvalidTables(std::vector> table_dbs); + void dropInvalidTablesAndDBs(const std::vector> & table_dbs, const std::set &); + + bool isIgnoreDB(const String & name); }; } // namespace DB diff --git a/dbms/src/Storages/Transaction/SchemaSyncer.h b/dbms/src/Storages/Transaction/SchemaSyncer.h index 461c5813853..629b0ed07f8 100644 --- a/dbms/src/Storages/Transaction/SchemaSyncer.h +++ b/dbms/src/Storages/Transaction/SchemaSyncer.h @@ -20,6 +20,8 @@ class SchemaSyncer * @param context */ virtual bool syncSchemas(Context & context) = 0; + + virtual void reset() = 0; }; using SchemaSyncerPtr = std::shared_ptr; diff --git a/dbms/src/Storages/Transaction/TMTContext.cpp b/dbms/src/Storages/Transaction/TMTContext.cpp index 025cff75769..b65db7d9183 100644 --- a/dbms/src/Storages/Transaction/TMTContext.cpp +++ b/dbms/src/Storages/Transaction/TMTContext.cpp @@ -79,4 +79,6 @@ pingcap::kv::RegionCachePtr TMTContext::getRegionCache() const { return region_c pingcap::kv::RpcClientPtr TMTContext::getRpcClient() { return rpc_client; } +const std::unordered_set & TMTContext::getIgnoreDatabases() const { return ignore_databases; } + } // namespace DB diff --git a/dbms/src/Storages/Transaction/TMTContext.h b/dbms/src/Storages/Transaction/TMTContext.h index 8595085d30c..91d9b35b28d 100644 --- a/dbms/src/Storages/Transaction/TMTContext.h +++ b/dbms/src/Storages/Transaction/TMTContext.h @@ -54,6 +54,8 @@ class TMTContext : private boost::noncopyable void restore(); + const std::unordered_set & getIgnoreDatabases() const; + private: KVStorePtr kvstore; TMTStorages storages; diff --git a/dbms/src/Storages/Transaction/TiDBSchemaSyncer.h b/dbms/src/Storages/Transaction/TiDBSchemaSyncer.h index 15782353079..10945898f5c 100644 --- a/dbms/src/Storages/Transaction/TiDBSchemaSyncer.h +++ b/dbms/src/Storages/Transaction/TiDBSchemaSyncer.h @@ -46,6 +46,15 @@ struct TiDBSchemaSyncer : public SchemaSyncer } } + // just for test + void reset() override + { + std::lock_guard lock(schema_mutex); + + databases.clear(); + cur_version = 0; + } + bool syncSchemas(Context & context) override { std::lock_guard lock(schema_mutex); diff --git a/docker/builder/build.sh b/docker/builder/build.sh index 8db723b63ba..85ab30e9786 100755 --- a/docker/builder/build.sh +++ b/docker/builder/build.sh @@ -4,10 +4,14 @@ SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )" SRCPATH=${1:-$(cd $SCRIPTPATH/../..; pwd -P)} NPROC=${NPROC:-$(nproc || grep -c ^processor /proc/cpuinfo)} -ENABLE_TEST=${ENABLE_TEST:-0} -ENABLE_EMBEDDED_COMPILER=${DENABLE_EMBEDDED_COMPILER:-1} +ENABLE_TEST=${ENABLE_TEST:-1} +ENABLE_EMBEDDED_COMPILER=${ENABLE_EMBEDDED_COMPILER:-1} CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE:-Debug} +if [[ "${CMAKE_BUILD_TYPE}" != "Debug" ]]; then + ENABLE_TEST=0 +fi + set -xe if [ -d "$SRCPATH/contrib/kvproto" ]; then @@ -19,9 +23,11 @@ fi build_dir="$SRCPATH/build_docker" mkdir -p $build_dir && cd $build_dir -cmake "$SRCPATH" -DENABLE_EMBEDDED_COMPILER=$ENABLE_EMBEDDED_COMPILER -DENABLE_TESTS=$ENABLE_TEST -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE +cmake "$SRCPATH" \ + -DENABLE_EMBEDDED_COMPILER=$ENABLE_EMBEDDED_COMPILER \ + -DENABLE_TESTS=$ENABLE_TEST \ + -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE make -j $NPROC -#ctest -V -j $(nproc || grep -c ^processor /proc/cpuinfo) install_dir="$SRCPATH/docker/builder/tics" if [ -d "$install_dir" ]; then rm -rf "$install_dir"/*; else mkdir -p "$install_dir"; fi @@ -31,3 +37,11 @@ ldd "$build_dir/dbms/src/Server/theflash" | grep '/' | grep '=>' | \ awk -F '=>' '{print $2}' | awk '{print $1}' | while read lib; do cp -f "$lib" "$install_dir" done + +# copy gtest binary under Debug mode +if [[ "${CMAKE_BUILD_TYPE}" = "Debug" && ${ENABLE_TEST} -ne 0 ]]; then + #ctest -V -j $(nproc || grep -c ^processor /proc/cpuinfo) + make -j ${NPROC} gtests_dbms gtests_libcommon + cp -f "$build_dir/dbms/gtests_dbms" "$install_dir/" + cp -f "$build_dir/libs/libcommon/src/tests/gtests_libcommon" "$install_dir/" +fi diff --git a/libs/libcommon/CMakeLists.txt b/libs/libcommon/CMakeLists.txt index c9de793e939..05810c44aa1 100644 --- a/libs/libcommon/CMakeLists.txt +++ b/libs/libcommon/CMakeLists.txt @@ -118,5 +118,5 @@ if (RT_LIBRARY) endif () if (ENABLE_TESTS) - add_subdirectory (src/tests) + add_subdirectory (src/tests EXCLUDE_FROM_ALL) endif () diff --git a/libs/libcommon/src/tests/CMakeLists.txt b/libs/libcommon/src/tests/CMakeLists.txt index c8aaf476842..f65f6222aed 100644 --- a/libs/libcommon/src/tests/CMakeLists.txt +++ b/libs/libcommon/src/tests/CMakeLists.txt @@ -17,9 +17,9 @@ target_link_libraries (date_lut_default_timezone common ${PLATFORM_LIBS}) target_link_libraries (multi_version common) add_check(multi_version) -add_executable (unit_tests_libcommon gtest_json_test.cpp gtest_strong_typedef.cpp) -target_link_libraries (unit_tests_libcommon gtest_main common) -add_check(unit_tests_libcommon) +add_executable (gtests_libcommon gtest_json_test.cpp gtest_strong_typedef.cpp) +target_link_libraries (gtests_libcommon gtest_main common) +add_check(gtests_libcommon) add_executable (dump_variable dump_variable.cpp) target_link_libraries (dump_variable clickhouse_common_io) diff --git a/libs/libglibc-compatibility/CMakeLists.txt b/libs/libglibc-compatibility/CMakeLists.txt index f9139d2ccde..0b60869cb1b 100644 --- a/libs/libglibc-compatibility/CMakeLists.txt +++ b/libs/libglibc-compatibility/CMakeLists.txt @@ -12,4 +12,4 @@ musl/syscall.s musl/syscall_ret.c musl/sched_cpucount.c) -add_subdirectory (tests) +add_subdirectory (tests EXCLUDE_FROM_ALL) diff --git a/libs/libmysqlxx/CMakeLists.txt b/libs/libmysqlxx/CMakeLists.txt index e3c9e836c22..ec38ebce8f0 100644 --- a/libs/libmysqlxx/CMakeLists.txt +++ b/libs/libmysqlxx/CMakeLists.txt @@ -52,5 +52,5 @@ target_link_libraries (mysqlxx common ${MYSQLCLIENT_LIBRARIES} ${OPENSSL_LIBRARI target_include_directories (mysqlxx PRIVATE ${OPENSSL_INCLUDE_DIR}) if (ENABLE_TESTS) - add_subdirectory (src/tests) + add_subdirectory (src/tests EXCLUDE_FROM_ALL) endif () diff --git a/tests/_env.sh b/tests/_env.sh index ad2591453a9..6a15a30fab6 100644 --- a/tests/_env.sh +++ b/tests/_env.sh @@ -3,11 +3,13 @@ # Executable path if [ `uname` == "Darwin" ]; then - export storage_bin="../../build_clang/dbms/src/Server/theflash" + export build_dir="../../build_clang" else - export storage_bin="../../build/dbms/src/Server/theflash" + export build_dir="../../build" fi +export storage_bin="$build_dir/dbms/src/Server/theflash" + # Serve config for launching export storage_server_config="../../running/config/config.xml" diff --git a/tests/docker/_env.sh b/tests/docker/_env.sh index ecf42b57626..ae6ce78f58c 100755 --- a/tests/docker/_env.sh +++ b/tests/docker/_env.sh @@ -1,7 +1,9 @@ #!/bin/bash +export build_dir="/tics" + # Executable path -export storage_bin="/tics/theflash" +export storage_bin="$build_dir/theflash" # Server address for connecting export storage_server="127.0.0.1" diff --git a/tests/docker/config/config.xml b/tests/docker/config/config.xml index e6911f1227e..cc43794a71e 100644 --- a/tests/docker/config/config.xml +++ b/tests/docker/config/config.xml @@ -19,6 +19,8 @@ 0.0.0.0:3930 /data/kvstore + + system 8123 diff --git a/tests/docker/config/tiflash.xml b/tests/docker/config/tiflash.xml index 6ec67cee0e0..8de552eab6e 100644 --- a/tests/docker/config/tiflash.xml +++ b/tests/docker/config/tiflash.xml @@ -22,6 +22,8 @@ pd0:2379 + + system 8123 diff --git a/tests/docker/docker-compose.yaml b/tests/docker/docker-compose.yaml index 3d14a4568ff..2729a116178 100644 --- a/tests/docker/docker-compose.yaml +++ b/tests/docker/docker-compose.yaml @@ -19,6 +19,16 @@ services: command: - --config-file - /config.xml + # tics-gtest container is for gtest cases + tics-gtest: + image: hub.pingcap.net/tiflash/tics:${TAG:-master} + volumes: + - ./config/config.xml:/config.xml:ro + - ./config/users.xml:/users.xml:ro + - ./log:/log + - ..:/tests + - ./_env.sh:/tests/_env.sh + entrypoint: sleep infinity # just wait pd0: image: hub.pingcap.net/tiflash/pd:190508 ports: diff --git a/tests/docker/run.sh b/tests/docker/run.sh index ab2d9a6ccae..bb205746fca 100755 --- a/tests/docker/run.sh +++ b/tests/docker/run.sh @@ -8,24 +8,25 @@ rm -rf ./data ./log ./build_learner_config.sh -docker-compose up -d --scale tics0=0 --scale tiflash0=0 --scale tikv-learner0=0 +docker-compose up -d --scale tics0=0 --scale tics-gtest=0 --scale tiflash0=0 --scale tikv-learner0=0 sleep 60 -docker-compose up -d --scale tics0=0 --scale tikv-learner0=0 --build +docker-compose up -d --scale tics0=0 --scale tics-gtest=0 --scale tikv-learner0=0 --build sleep 5 -docker-compose up -d --scale tics0=0 - +docker-compose up -d --scale tics0=0 --scale tics-gtest=0 docker-compose exec -T tiflash0 bash -c 'cd /tests ; ./run-test.sh fullstack-test true' - docker-compose down -docker-compose up -d --scale tiflash0=0 --scale tikv-learner0=0 --scale tikv0=0 --scale tidb0=0 --scale pd0=0 - +# (only tics0 up) +docker-compose up -d --scale tics-gtest=0 --scale tiflash0=0 --scale tikv-learner0=0 --scale tikv0=0 --scale tidb0=0 --scale pd0=0 docker-compose exec -T tics0 bash -c 'cd /tests ; ./run-test.sh mutable-test' - docker-compose down +# run gtest cases. (only tics-gtest up) +docker-compose up -d --scale tics0=0 --scale tiflash0=0 --scale tikv-learner0=0 --scale tikv0=0 --scale tidb0=0 --scale pd0=0 +docker-compose exec -T tics-gtest bash -c 'cd /tests && ./run-gtest.sh' +docker-compose down diff --git a/tests/mutable-test/txn_schema/drop_on_restart.test b/tests/mutable-test/txn_schema/drop_on_restart.test new file mode 100644 index 00000000000..63df70c6e41 --- /dev/null +++ b/tests/mutable-test/txn_schema/drop_on_restart.test @@ -0,0 +1,53 @@ +=> DBGInvoke __enable_schema_sync_service('false') + +=> DBGInvoke __drop_tidb_table(default, test) +=> DBGInvoke __drop_tidb_db(db3) +=> DBGInvoke __drop_tidb_db(db4) +=> drop table if exists default.test +=> DBGInvoke __refresh_schemas() + +=> DBGInvoke __set_flush_threshold(1000000, 1000000) + +=> DBGInvoke __mock_tidb_db(db3) +=> DBGInvoke __mock_tidb_db(db4) +=> DBGInvoke __mock_tidb_table(db3, test, 'col_1 String') +=> DBGInvoke __mock_tidb_table(db4, test, 'col_1 String') +=> DBGInvoke __refresh_schemas() +=> show databases +┌─name────┐ +│ db3 │ +│ db4 │ +│ default │ +│ system │ +└─────────┘ +=> DBGInvoke __reset_schemas() +=> DBGInvoke __drop_tidb_db(db3); +=> DBGInvoke __drop_tidb_table(db4, test); +=> DBGInvoke __refresh_schemas() +=> show databases +┌─name────┐ +│ db4 │ +│ default │ +│ system │ +└─────────┘ +=> select * from db4.test +Received exception from server (version {#WORD}): +Code: 60. DB::Exception: Received from {#WORD} DB::Exception: Table db4.test doesn't exist.. +=> DBGInvoke __mock_tidb_db(db3) +=> DBGInvoke __refresh_schemas() +=> show databases +┌─name────┐ +│ db3 │ +│ db4 │ +│ default │ +│ system │ +└─────────┘ +=> DBGInvoke __reset_schemas() +=> DBGInvoke __drop_tidb_db(db3); +=> DBGInvoke __drop_tidb_db(db4); +=> DBGInvoke __refresh_schemas() +=> show databases +┌─name────┐ +│ default │ +│ system │ +└─────────┘ diff --git a/tests/run-gtest.sh b/tests/run-gtest.sh new file mode 100755 index 00000000000..28191108e6e --- /dev/null +++ b/tests/run-gtest.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +function run_test() +{ + local name="$1" + local bin_path=$(find . -name "$name") + if [[ "$continue_on_error" -eq 1 ]]; then + ${bin_path} --gtest_catch_exceptions=1 + else + ${bin_path} --gtest_break_on_failure --gtest_catch_exceptions=0 + fi +} + +source ./_env.sh + +continue_on_error="${1:-1}" # default 1 +set -ex + +cd "$build_dir" + +tests=( + "gtests_dbms" + "gtests_libcommon" +) + +for test in ${tests[@]}; do + run_test "$test" +done