From: Tor Didriksen Date: May 13 2011 9:36am Subject: bzr commit into mysql-trunk-mtr branch (tor.didriksen:3080) Bug#11788245 List-Archive: http://lists.mysql.com/commits/137299 X-Bug: 11788245 Message-Id: <20110513093621.0D6CF3793@atum07.norway.sun.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============6849718142791834566==" --===============6849718142791834566== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///export/home/didrik/repo/trunk-test-utils/ based on revid:alfranio.correia@stripped 3080 Tor Didriksen 2011-05-13 Bug #11788245 - 60110 DO MORE THD AND GLOBAL INITIALIZATION FOR UNIT TESTING Move server/THD initialization to separate utility classes in namespace my_testing. Add new test as an example of how to use the utility classes. @ unittest/gunit/CMakeLists.txt Add test_utils.cc @ unittest/gunit/item-t.cc Use new utility classes. @ unittest/gunit/opt_range-t.cc Another example of using the utility classes. @ unittest/gunit/test_utils.cc Code moved from Item test, into new utility classes. @ unittest/gunit/test_utils.h Code moved from Item test, into new utility classes. added: unittest/gunit/opt_range-t.cc unittest/gunit/test_utils.cc unittest/gunit/test_utils.h modified: unittest/gunit/CMakeLists.txt unittest/gunit/item-t.cc === modified file 'unittest/gunit/CMakeLists.txt' --- a/unittest/gunit/CMakeLists.txt 2011-04-13 11:31:44 +0000 +++ b/unittest/gunit/CMakeLists.txt 2011-05-13 09:36:13 +0000 @@ -219,6 +219,7 @@ SET(TESTS # Add tests (link them with gunit library and the server libraries) SET(SERVER_TESTS item + opt_range ) FOREACH(test ${TESTS}) @@ -232,9 +233,9 @@ ENDFOREACH() FOREACH(test ${SERVER_TESTS}) IF(WIN32) - ADD_EXECUTABLE(${test}-t ${test}-t.cc ../../sql/nt_servc.cc) + ADD_EXECUTABLE(${test}-t ${test}-t.cc test_utils.cc ../../sql/nt_servc.cc) ELSE() - ADD_EXECUTABLE(${test}-t ${test}-t.cc) + ADD_EXECUTABLE(${test}-t ${test}-t.cc test_utils.cc) ENDIF() TARGET_LINK_LIBRARIES(${test}-t sql binlog rpl master slave sql) TARGET_LINK_LIBRARIES(${test}-t gunit sqlgunitlib strings dbug regex mysys) === modified file 'unittest/gunit/item-t.cc' --- a/unittest/gunit/item-t.cc 2011-03-18 12:25:56 +0000 +++ b/unittest/gunit/item-t.cc 2011-05-13 09:36:13 +0000 @@ -18,112 +18,42 @@ #include "my_config.h" #include +#include "test_utils.h" + #include "item.h" #include "sql_class.h" -#include "rpl_handler.h" // delegates_init() namespace { -/* - A mock error handler for error_handler_hook. -*/ -uint expected_error= 0; -extern "C" void test_error_handler_hook(uint err, const char *str, myf MyFlags) -{ - EXPECT_EQ(expected_error, err) << str; -} - - -/** - A mock error handler which registers itself with the THD in the CTOR, - and unregisters in the DTOR. The function handle_condition() will - verify that it is called with the expected error number. - The DTOR will verify that handle_condition() has actually been called. -*/ -class Mock_error_handler : public Internal_error_handler -{ -public: - Mock_error_handler(THD *thd, uint expected_error) - : m_thd(thd), - m_expected_error(expected_error), - m_handle_called(0) - { - thd->push_internal_handler(this); - } - - virtual ~Mock_error_handler() - { - // Strange Visual Studio bug: have to store 'this' in local variable. - Internal_error_handler *me= this; - EXPECT_EQ(me, m_thd->pop_internal_handler()); - EXPECT_GE(m_handle_called, 0); - } - - virtual bool handle_condition(THD *thd, - uint sql_errno, - const char* sqlstate, - MYSQL_ERROR::enum_warning_level level, - const char* msg, - MYSQL_ERROR ** cond_hdl) - { - EXPECT_EQ(sql_errno, m_expected_error); - ++m_handle_called; - return true; - } -private: - THD *m_thd; - uint m_expected_error; - int m_handle_called; -}; - +using my_testing::Server_initializer; +using my_testing::Mock_error_handler; class ItemTest : public ::testing::Test { protected: - /* - This is the part of the server global things which have to be initialized - for this (very simple) unit test. Presumably the list will grow once - we start writing tests for more advanced classes. - TODO: Move to a common library. - */ static void SetUpTestCase() { - static char *my_name= strdup(my_progname); - char *argv[] = { my_name, 0 }; - set_remaining_args(1, argv); - init_common_variables(); - my_init_signals(); - randominit(&sql_rand, 0, 0); - xid_cache_init(); - delegates_init(); - error_handler_hook= test_error_handler_hook; + Server_initializer::SetUpTestCase(); } static void TearDownTestCase() { - delegates_destroy(); - xid_cache_free(); + Server_initializer::TearDownTestCase(); } - ItemTest() : m_thd(NULL) {} - virtual void SetUp() { - expected_error= 0; - m_thd= new THD(false); - THD *stack_thd= m_thd; - m_thd->thread_stack= (char*) &stack_thd; - m_thd->store_globals(); - lex_start(m_thd); + initializer.SetUp(); } virtual void TearDown() { - m_thd->cleanup_after_query(); - delete m_thd; + initializer.TearDown(); } - THD *m_thd; + THD *thd() { return initializer.thd(); } + + Server_initializer initializer; }; @@ -239,7 +169,7 @@ TEST_F(ItemTest, ItemFuncDesDecrypt) Item_func_des_decrypt *item_decrypt= new Item_func_des_decrypt(item_two, item_one); - EXPECT_FALSE(item_decrypt->fix_fields(m_thd, NULL)); + EXPECT_FALSE(item_decrypt->fix_fields(thd(), NULL)); EXPECT_EQ(length, item_one->max_length); EXPECT_EQ(length, item_two->max_length); EXPECT_LE(item_decrypt->max_length, length); @@ -256,9 +186,9 @@ TEST_F(ItemTest, ItemFuncIntDivOverflow) Item_float *divisor= new Item_float(divisor_str, sizeof(divisor_str)); Item_func_int_div* quotient= new Item_func_int_div(dividend, divisor); - Mock_error_handler error_handler(m_thd, ER_TRUNCATED_WRONG_VALUE); - EXPECT_FALSE(quotient->fix_fields(m_thd, NULL)); - expected_error= ER_DATA_OUT_OF_RANGE; + Mock_error_handler error_handler(thd(), ER_TRUNCATED_WRONG_VALUE); + EXPECT_FALSE(quotient->fix_fields(thd(), NULL)); + initializer.set_expected_error(ER_DATA_OUT_OF_RANGE); quotient->val_int(); } @@ -272,8 +202,8 @@ TEST_F(ItemTest, ItemFuncIntDivUnderflow Item_float *divisor= new Item_float(divisor_str, sizeof(divisor_str)); Item_func_int_div* quotient= new Item_func_int_div(dividend, divisor); - Mock_error_handler error_handler(m_thd, ER_TRUNCATED_WRONG_VALUE); - EXPECT_FALSE(quotient->fix_fields(m_thd, NULL)); + Mock_error_handler error_handler(thd(), ER_TRUNCATED_WRONG_VALUE); + EXPECT_FALSE(quotient->fix_fields(thd(), NULL)); EXPECT_EQ(0, quotient->val_int()); } @@ -291,8 +221,8 @@ TEST_F(ItemTest, ItemFuncSetUserVar) LEX_STRING var_name= { C_STRING_WITH_LEN("a") }; Item_func_set_user_var *user_var= new Item_func_set_user_var(var_name, item_str); - EXPECT_FALSE(user_var->set_entry(m_thd, true)); - EXPECT_FALSE(user_var->fix_fields(m_thd, NULL)); + EXPECT_FALSE(user_var->set_entry(thd(), true)); + EXPECT_FALSE(user_var->fix_fields(thd(), NULL)); EXPECT_EQ(val1, user_var->val_int()); my_decimal decimal; @@ -323,7 +253,7 @@ TEST_F(ItemTest, OutOfMemory) EXPECT_EQ(null_item, item); DBUG_SET("+d,simulate_out_of_memory"); - item= new (m_thd->mem_root) Item_int(42); + item= new (thd()->mem_root) Item_int(42); EXPECT_EQ(null_item, item); #endif } @@ -337,7 +267,7 @@ TEST_F(ItemTest, ItemFuncXor) Item_func_xor *item_xor= new Item_func_xor(item_zero, item_one_a); - EXPECT_FALSE(item_xor->fix_fields(m_thd, NULL)); + EXPECT_FALSE(item_xor->fix_fields(thd(), NULL)); EXPECT_EQ(1, item_xor->val_int()); EXPECT_EQ(1U, item_xor->decimal_precision()); @@ -346,7 +276,7 @@ TEST_F(ItemTest, ItemFuncXor) Item_func_xor *item_xor_same= new Item_func_xor(item_one_a, item_one_b); - EXPECT_FALSE(item_xor_same->fix_fields(m_thd, NULL)); + EXPECT_FALSE(item_xor_same->fix_fields(thd(), NULL)); EXPECT_EQ(0, item_xor_same->val_int()); EXPECT_FALSE(item_xor_same->val_bool()); EXPECT_FALSE(item_xor_same->is_null()); @@ -355,8 +285,8 @@ TEST_F(ItemTest, ItemFuncXor) item_xor->print(&print_buffer, QT_ORDINARY); EXPECT_STREQ("(0 xor 1)", print_buffer.c_ptr_safe()); - Item *neg_xor= item_xor->neg_transformer(m_thd); - EXPECT_FALSE(neg_xor->fix_fields(m_thd, NULL)); + Item *neg_xor= item_xor->neg_transformer(thd()); + EXPECT_FALSE(neg_xor->fix_fields(thd(), NULL)); EXPECT_EQ(0, neg_xor->val_int()); EXPECT_DOUBLE_EQ(0.0, neg_xor->val_real()); EXPECT_FALSE(neg_xor->val_bool()); @@ -368,7 +298,7 @@ TEST_F(ItemTest, ItemFuncXor) Item_func_xor *item_xor_null= new Item_func_xor(item_zero, new Item_null()); - EXPECT_FALSE(item_xor_null->fix_fields(m_thd, NULL)); + EXPECT_FALSE(item_xor_null->fix_fields(thd(), NULL)); EXPECT_EQ(0, item_xor_null->val_int()); EXPECT_TRUE(item_xor_null->is_null()); === added file 'unittest/gunit/opt_range-t.cc' --- a/unittest/gunit/opt_range-t.cc 1970-01-01 00:00:00 +0000 +++ b/unittest/gunit/opt_range-t.cc 2011-05-13 09:36:13 +0000 @@ -0,0 +1,150 @@ +/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +// First include (the generated) my_config.h, to get correct platform defines, +// then gtest.h (before any other MySQL headers), to avoid min() macros etc ... +#include "my_config.h" +#include + +#include "test_utils.h" + +#include "opt_range.cc" + +namespace { + +using my_testing::Server_initializer; + +class SelArgTest : public ::testing::Test +{ +protected: + static void SetUpTestCase() + { + Server_initializer::SetUpTestCase(); + } + + static void TearDownTestCase() + { + Server_initializer::TearDownTestCase(); + } + + SelArgTest() + { + memset(&m_opt_param, 0, sizeof(m_opt_param)); + } + + virtual void SetUp() + { + initializer.SetUp(); + m_opt_param.thd= thd(); + m_opt_param.mem_root= &m_alloc; + init_sql_alloc(&m_alloc, thd()->variables.range_alloc_block_size, 0); + } + + virtual void TearDown() + { + initializer.TearDown(); + free_root(&m_alloc, MYF(0)); + } + + THD *thd() { return initializer.thd(); } + + Server_initializer initializer; + MEM_ROOT m_alloc; + RANGE_OPT_PARAM m_opt_param; +}; + +/* + Experiment with these to measure performance of + 'new (thd->mem_root)' Foo vs. 'new Foo'. + With gcc 4.4.2 I see ~4% difference (in optimized mode). +*/ +const int num_iterations= 10; +const int num_allocs= 10; + +TEST_F(SelArgTest, AllocateExplicit) +{ + for (int ix= 0; ix < num_iterations; ++ix) + { + free_root(thd()->mem_root, MYF(MY_KEEP_PREALLOC)); + for (int ii= 0; ii < num_allocs; ++ii) + new (thd()->mem_root) SEL_ARG; + } +} + +TEST_F(SelArgTest, AllocateImplicit) +{ + for (int ix= 0; ix < num_iterations; ++ix) + { + free_root(thd()->mem_root, MYF(MY_KEEP_PREALLOC)); + for (int ii= 0; ii < num_allocs; ++ii) + new SEL_ARG; + } +} + +/* + We cannot do EXPECT_NE(NULL, get_mm_tree(...)) + because of limits in google test. + */ +const SEL_TREE *null_tree= NULL; + + +class Mock_field_long : public Field_long +{ +public: + Mock_field_long() + : Field_long(0, // ptr_arg + 8, // len_arg + NULL, // null_ptr_arg + 0, // null_bit_arg + Field::NONE, // unireg_check_arg + "field_name", // field_name_arg + false, // zero_arg + false) // unsigned_arg + { + m_table_name= "mock_table"; + memset(&m_share, 0, sizeof(m_share)); + const char *foo= "mock_db"; + m_share.db.str= const_cast(foo); + m_share.db.length= strlen(m_share.db.str); + + memset(&m_table, 0, sizeof(m_table)); + m_table.s= &m_share; + this->table_name= &m_table_name; + this->table= &m_table; + } + const char *m_table_name; + TABLE_SHARE m_share; + TABLE m_table; +}; + + +TEST_F(SelArgTest, SimpleCond) +{ + EXPECT_NE(null_tree, get_mm_tree(&m_opt_param, new Item_int(42))); +} + + +TEST_F(SelArgTest, EqualCond) +{ + Mock_field_long field_long; + EXPECT_EQ(null_tree, + get_mm_tree(&m_opt_param, + new Item_equal(new Item_int(42), + new Item_field(&field_long)))); +} + +} + + === added file 'unittest/gunit/test_utils.cc' --- a/unittest/gunit/test_utils.cc 1970-01-01 00:00:00 +0000 +++ b/unittest/gunit/test_utils.cc 2011-05-13 09:36:13 +0000 @@ -0,0 +1,105 @@ +/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +// First include (the generated) my_config.h, to get correct platform defines, +// then gtest.h (before any other MySQL headers), to avoid min() macros etc ... +#include "my_config.h" +#include + +#include "test_utils.h" +#include "rpl_handler.h" // delegates_init() + +namespace my_testing { + +/* + A mock error handler for error_handler_hook. +*/ +uint expected_error= 0; +extern "C" void test_error_handler_hook(uint err, const char *str, myf MyFlags) +{ + EXPECT_EQ(expected_error, err) << str; +} + +void Server_initializer::set_expected_error(uint val) +{ + expected_error= val; +} + +void Server_initializer::SetUpTestCase() +{ + static char *my_name= strdup(my_progname); + char *argv[] = { my_name, 0 }; + set_remaining_args(1, argv); + init_common_variables(); + my_init_signals(); + randominit(&sql_rand, 0, 0); + xid_cache_init(); + delegates_init(); + error_handler_hook= test_error_handler_hook; +} + +void Server_initializer::TearDownTestCase() +{ + delegates_destroy(); + xid_cache_free(); +} + +void Server_initializer::SetUp() +{ + expected_error= 0; + m_thd= new THD(false); + THD *stack_thd= m_thd; + m_thd->thread_stack= (char*) &stack_thd; + m_thd->store_globals(); + lex_start(m_thd); +} + +void Server_initializer::TearDown() +{ + m_thd->cleanup_after_query(); + delete m_thd; +} + + +Mock_error_handler::Mock_error_handler(THD *thd, uint expected_error) + : m_thd(thd), + m_expected_error(expected_error), + m_handle_called(0) +{ + thd->push_internal_handler(this); +} + +Mock_error_handler::~Mock_error_handler() +{ + // Strange Visual Studio bug: have to store 'this' in local variable. + Internal_error_handler *me= this; + EXPECT_EQ(me, m_thd->pop_internal_handler()); + EXPECT_GE(m_handle_called, 0); +} + +bool Mock_error_handler::handle_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + MYSQL_ERROR ** cond_hdl) +{ + EXPECT_EQ(m_expected_error, sql_errno); + ++m_handle_called; + return true; +} + + +} // namespace my_testing === added file 'unittest/gunit/test_utils.h' --- a/unittest/gunit/test_utils.h 1970-01-01 00:00:00 +0000 +++ b/unittest/gunit/test_utils.h 2011-05-13 09:36:13 +0000 @@ -0,0 +1,75 @@ +/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#ifndef TEST_UTILS_INCLUDED +#define TEST_UTILS_INCLUDED + +#include "sql_error.h" +#include "sql_class.h" + +namespace my_testing { + +/* + A class which wraps the necessary setup/teardown logic for + unit tests which depend on a working THD environment. + */ +class Server_initializer +{ +public: + Server_initializer() : m_thd(NULL) {} + + // Invoke these from corresponding functions in test fixture classes. + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); + + // Sets expected error for error_handler_hook. + static void set_expected_error(uint val); + + THD *thd() const { return m_thd; } +private: + THD *m_thd; +}; + +/** + A mock error handler which registers itself with the THD in the CTOR, + and unregisters in the DTOR. The function handle_condition() will + verify that it is called with the expected error number. + The DTOR will verify that handle_condition() has actually been called. +*/ +class Mock_error_handler : public Internal_error_handler +{ +public: + Mock_error_handler(THD *thd, uint expected_error); + virtual ~Mock_error_handler(); + + virtual bool handle_condition(THD *thd, + uint sql_errno, + const char* sqlstate, + MYSQL_ERROR::enum_warning_level level, + const char* msg, + MYSQL_ERROR ** cond_hdl); +private: + THD *m_thd; + uint m_expected_error; + int m_handle_called; +}; + + +} // namespace my_testing + +#endif // TEST_UTILS_INCLUDED --===============6849718142791834566== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/tor.didriksen@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: tor.didriksen@stripped\ # 6cugcprzhhujr39k # target_branch: file:///export/home/didrik/repo/trunk-test-utils/ # testament_sha1: 44bfaac346139fcfa9aec95fdca1094662f97343 # timestamp: 2011-05-13 11:36:20 +0200 # base_revision_id: alfranio.correia@stripped\ # c1b5kmum4h52g0ni # # Begin bundle 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 --===============6849718142791834566==--