From 9a33cf4d3ecbc4cdfabf4dd88277ad951926b8f2 Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Tue, 14 Mar 2017 18:59:42 +0200 Subject: [PATCH] Add smoke-test for qc_get_trx_type_mask_using Use the query classifier test files and compare that the result returned by qc_sqlite and the custom parser agree for every statement. --- server/core/test/CMakeLists.txt | 11 ++ server/core/test/testtrxcompare.cc | 237 +++++++++++++++++++++++++++++ 2 files changed, 248 insertions(+) create mode 100644 server/core/test/testtrxcompare.cc diff --git a/server/core/test/CMakeLists.txt b/server/core/test/CMakeLists.txt index 41daf2f6f..1c0dfb992 100644 --- a/server/core/test/CMakeLists.txt +++ b/server/core/test/CMakeLists.txt @@ -13,6 +13,7 @@ add_executable(test_queuemanager testqueuemanager.c) add_executable(test_server testserver.c) add_executable(test_service testservice.c) add_executable(test_spinlock testspinlock.c) +add_executable(test_trxcompare testtrxcompare.cc ../../../query_classifier/test/testreader.cc) add_executable(test_trxtracking testtrxtracking.cc) add_executable(test_users testusers.c) add_executable(testfeedback testfeedback.c) @@ -34,6 +35,7 @@ target_link_libraries(test_queuemanager maxscale-common) target_link_libraries(test_server maxscale-common) target_link_libraries(test_service maxscale-common) target_link_libraries(test_spinlock maxscale-common) +target_link_libraries(test_trxcompare maxscale-common) target_link_libraries(test_trxtracking maxscale-common) target_link_libraries(test_users maxscale-common) target_link_libraries(testfeedback maxscale-common) @@ -61,6 +63,15 @@ add_test(TestUsers test_users) add_test(TestModulecmd testmodulecmd) add_test(TestConfig testconfig) add_test(TestTrxTracking test_trxtracking) +add_test(TestTrxCompare_Create test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/../../../query_classifier/test/create.test) +add_test(TestTrxCompare_Delete test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/../../../query_classifier/test/delete.test) +add_test(TestTrxCompare_Insert test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/../../../query_classifier/test/insert.test) +add_test(TestTrxCompare_Join test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/../../../query_classifier/test/join.test) +add_test(TestTrxCompare_Select test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/../../../query_classifier/test/select.test) +add_test(TestTrxCompare_Set test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/../../../query_classifier/test/set.test) +add_test(TestTrxCompare_Update test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/../../../query_classifier/test/update.test) +add_test(TestTrxCompare_MaxScale test_trxcompare ${CMAKE_CURRENT_SOURCE_DIR}/../../../query_classifier/test/maxscale.test) + # This test requires external dependencies and thus cannot be run # as a part of the core test set diff --git a/server/core/test/testtrxcompare.cc b/server/core/test/testtrxcompare.cc new file mode 100644 index 000000000..ae85f91c5 --- /dev/null +++ b/server/core/test/testtrxcompare.cc @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2016 MariaDB Corporation Ab + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file and at www.mariadb.com/bsl11. + * + * Change Date: 2019-07-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2 or later of the General + * Public License. + */ + +#include +#include +#include +#include +#include +#include "../maxscale/query_classifier.h" +#include +#include +#include +#include "../../../query_classifier/test/testreader.hh" + +using namespace std; + +namespace +{ + +char USAGE[] = + "test_trxcompare [-v] (-s stmt)|[file]" + "\n" + "-s test single statement\n" + "-v 0, only return code\n" + " 1, failed cases (default)\n" + " 2, successful transactional cases\n" + " 4, successful cases\n" + " 7, all cases\n"; + +enum verbosity_t +{ + VERBOSITY_NOTHING = 0, // 000 + VERBOSITY_FAILED = 1, // 001 + VERBOSITY_SUCCESSFUL_TRANSACTIONAL = 2, // 010 + VERBOSITY_SUCCESSFUL = 4, // 100 + VERBOSITY_ALL = 7, // 111 +}; + +GWBUF* create_gwbuf(const char* zStmt) +{ + size_t len = strlen(zStmt); + size_t payload_len = len + 1; + size_t gwbuf_len = MYSQL_HEADER_LEN + payload_len; + + GWBUF* pBuf = gwbuf_alloc(gwbuf_len); + + *((unsigned char*)((char*)GWBUF_DATA(pBuf))) = payload_len; + *((unsigned char*)((char*)GWBUF_DATA(pBuf) + 1)) = (payload_len >> 8); + *((unsigned char*)((char*)GWBUF_DATA(pBuf) + 2)) = (payload_len >> 16); + *((unsigned char*)((char*)GWBUF_DATA(pBuf) + 3)) = 0x00; + *((unsigned char*)((char*)GWBUF_DATA(pBuf) + 4)) = 0x03; + memcpy((char*)GWBUF_DATA(pBuf) + 5, zStmt, len); + + return pBuf; +} + + +class Tester +{ +public: + Tester(uint32_t verbosity) + : m_verbosity(verbosity) + { + } + + int run(const char* zStmt) + { + int rc = EXIT_SUCCESS; + + GWBUF* pStmt = create_gwbuf(zStmt); + + uint32_t type_mask_qc = qc_get_trx_type_mask_using(pStmt, QC_TRX_PARSE_USING_QC); + uint32_t type_mask_parser = qc_get_trx_type_mask_using(pStmt, QC_TRX_PARSE_USING_PARSER); + + gwbuf_free(pStmt); + + if (type_mask_qc == type_mask_parser) + { + if ((m_verbosity & VERBOSITY_SUCCESSFUL) || + ((m_verbosity & VERBOSITY_SUCCESSFUL_TRANSACTIONAL) && (type_mask_qc != 0))) + { + char* zType_mask = qc_typemask_to_string(type_mask_qc); + + cout << zStmt << ": " << zType_mask << endl; + + MXS_FREE(zType_mask); + } + } + else + { + if (m_verbosity & VERBOSITY_FAILED) + { + char* zType_mask_qc = qc_typemask_to_string(type_mask_qc); + char* zType_mask_parser = qc_typemask_to_string(type_mask_parser); + + cout << zStmt << "\n" + << " QC : " << zType_mask_qc << "\n" + << " PARSER: " << zType_mask_parser << endl; + + MXS_FREE(zType_mask_qc); + MXS_FREE(zType_mask_parser); + } + + rc = EXIT_FAILURE; + } + + return rc; + } + + int run(istream& in) + { + int rc = EXIT_SUCCESS; + + maxscale::TestReader reader(in); + + string stmt; + + while (reader.get_statement(stmt) == maxscale::TestReader::RESULT_STMT) + { + if (run(stmt.c_str()) == EXIT_FAILURE) + { + rc = EXIT_FAILURE; + } + } + + return rc; + } + +private: + Tester(const Tester&); + Tester& operator = (const Tester&); + +private: + uint32_t m_verbosity; +}; + +} + + + +int main(int argc, char* argv[]) +{ + int rc = EXIT_SUCCESS; + + int verbosity = VERBOSITY_FAILED; + const char* zStatement = NULL; + + int c; + while ((c = getopt(argc, argv, "s:v:")) != -1) + { + switch (c) + { + case 's': + zStatement = optarg; + break; + + case 'v': + verbosity = atoi(optarg); + break; + + default: + rc = EXIT_FAILURE; + } + } + + if ((rc == EXIT_SUCCESS) && (verbosity >= VERBOSITY_NOTHING) && (verbosity <= VERBOSITY_ALL)) + { + rc = EXIT_FAILURE; + + set_datadir(strdup("/tmp")); + set_langdir(strdup(".")); + set_process_datadir(strdup("/tmp")); + + if (mxs_log_init(NULL, ".", MXS_LOG_TARGET_DEFAULT)) + { + // We have to setup something in order for the regexes to be compiled. + if (qc_setup("qc_sqlite", NULL) && qc_process_init(QC_INIT_BOTH)) + { + Tester tester(verbosity); + + int n = argc - (optind - 1); + + if (zStatement) + { + rc = tester.run(zStatement); + } + else if (n == 1) + { + rc = tester.run(cin); + } + else + { + ss_dassert(n == 2); + + ifstream in(argv[argc - 1]); + + if (in) + { + rc = tester.run(in); + } + else + { + cerr << "error: Could not open " << argv[argc - 1] << "." << endl; + } + } + + qc_process_end(QC_INIT_BOTH); + } + else + { + cerr << "error: Could not initialize qc_sqlite." << endl; + } + + mxs_log_finish(); + } + else + { + cerr << "error: Could not initialize log." << endl; + } + } + else + { + cout << USAGE << endl; + } + + return rc; +}