From: Tor Didriksen Date: January 28 2011 1:37pm Subject: bzr commit into mysql-trunk branch (tor.didriksen:3563) Bug#59794 List-Archive: http://lists.mysql.com/commits/129870 X-Bug: 59794 Message-Id: <20110128133721.11E7B373B@atum07.norway.sun.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============7197275574944457056==" --===============7197275574944457056== 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-thd-item/ based on revid:tor.didriksen@stripped 3563 Tor Didriksen 2011-01-28 Bug #59794 Enable unit testing of classes which depend on a working THD environment Large parts of the codebase depend on a THD instance in order to be tested. The THD needs to be modified, so it can be used in unit tests. Some global initialization also needs to be done. @ include/my_global.h MY_INTnn_NUM_DECIMAL_DIGITS are always used in unsigned context. @ sql/mysqld.cc init_thread_environment() must be callable by unit tests. @ sql/mysqld.h init_thread_environment() must be callable by unit tests. @ sql/sql_class.cc Disable plugins for unit tests. @ sql/sql_class.h Disable plugins for unit tests. @ sql/sql_plugin.cc Disable plugins for unit tests. @ unittest/gunit/CMakeLists.txt Add new linkage rules for unit tests which depend on server libraries. @ unittest/gunit/item-t.cc New unit test. added: unittest/gunit/item-t.cc modified: include/my_global.h sql/mysqld.cc sql/mysqld.h sql/sql_class.cc sql/sql_class.h sql/sql_plugin.cc unittest/gunit/CMakeLists.txt === modified file 'include/my_global.h' --- a/include/my_global.h 2011-01-11 09:09:21 +0000 +++ b/include/my_global.h 2011-01-28 13:37:15 +0000 @@ -1,4 +1,4 @@ -/* Copyright (C) 2000-2003 MySQL AB, 2009 Sun Microsystems, Inc +/* Copyright (c) 2000, 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 @@ -1377,10 +1377,10 @@ do { doubleget_union _tmp; \ #endif /* Length of decimal number represented by INT32. */ -#define MY_INT32_NUM_DECIMAL_DIGITS 11 +#define MY_INT32_NUM_DECIMAL_DIGITS 11U /* Length of decimal number represented by INT64. */ -#define MY_INT64_NUM_DECIMAL_DIGITS 21 +#define MY_INT64_NUM_DECIMAL_DIGITS 21U /* Define some useful general macros (should be done after all headers). */ #if !defined(max) === modified file 'sql/mysqld.cc' --- a/sql/mysqld.cc 2011-01-17 09:52:59 +0000 +++ b/sql/mysqld.cc 2011-01-28 13:37:15 +0000 @@ -1,4 +1,4 @@ -/* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2000, 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 @@ -944,7 +944,6 @@ static int get_options(int *argc_ptr, ch static bool add_terminator(DYNAMIC_ARRAY *options); extern "C" my_bool mysqld_get_one_option(int, const struct my_option *, char *); static void set_server_version(void); -static int init_thread_environment(); static char *get_relative_path(const char *path); static int fix_paths(void); void handle_connections_sockets(); @@ -3551,7 +3550,7 @@ You should consider changing lower_case_ } -static int init_thread_environment() +int init_thread_environment() { mysql_mutex_init(key_LOCK_thread_count, &LOCK_thread_count, MY_MUTEX_INIT_FAST); mysql_mutex_init(key_LOCK_status, &LOCK_status, MY_MUTEX_INIT_FAST); === modified file 'sql/mysqld.h' --- a/sql/mysqld.h 2011-01-14 13:42:41 +0000 +++ b/sql/mysqld.h 2011-01-28 13:37:15 +0000 @@ -1,4 +1,4 @@ -/* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2006, 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 @@ -72,6 +72,7 @@ bool one_thread_per_connection_end(THD * void flush_thread_cache(); void refresh_status(THD *thd); bool is_secure_file_path(char *path); +int init_thread_environment(); extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *system_charset_info; extern MYSQL_PLUGIN_IMPORT CHARSET_INFO *files_charset_info ; === modified file 'sql/sql_class.cc' --- a/sql/sql_class.cc 2011-01-27 15:31:18 +0000 +++ b/sql/sql_class.cc 2011-01-28 13:37:15 +0000 @@ -498,7 +498,7 @@ bool Drop_table_error_handler::handle_co } -THD::THD() +THD::THD(bool enable_plugins) :Statement(&main_lex, &main_mem_root, CONVENTIONAL_EXECUTION, /* statement id */ 0), rli_fake(0), @@ -527,6 +527,7 @@ THD::THD() #if defined(ENABLED_DEBUG_SYNC) debug_sync_control(0), #endif /* defined(ENABLED_DEBUG_SYNC) */ + m_enable_plugins(enable_plugins), main_warning_info(0) { ulong tmp; @@ -928,7 +929,8 @@ extern "C" THD *_current_thd_noinline( void THD::init(void) { mysql_mutex_lock(&LOCK_global_system_variables); - plugin_thdvar_init(this); + if (m_enable_plugins) + plugin_thdvar_init(this); /* variables= global_system_variables above has reset variables.pseudo_thread_id to 0. We need to correct it here to @@ -1102,7 +1104,8 @@ THD::~THD() mdl_context.destroy(); ha_close_connection(this); mysql_audit_release(this); - plugin_thdvar_cleanup(this); + if (m_enable_plugins) + plugin_thdvar_cleanup(this); DBUG_PRINT("info", ("freeing security context")); main_security_ctx.destroy(); === modified file 'sql/sql_class.h' --- a/sql/sql_class.h 2011-01-27 15:31:18 +0000 +++ b/sql/sql_class.h 2011-01-28 13:37:15 +0000 @@ -2233,7 +2233,11 @@ public: /* Debug Sync facility. See debug_sync.cc. */ struct st_debug_sync_control *debug_sync_control; #endif /* defined(ENABLED_DEBUG_SYNC) */ - THD(); + + // We don't want to load/unload plugins for unit tests. + bool m_enable_plugins; + + THD(bool enable_plugins= true); ~THD(); void init(void); === modified file 'sql/sql_plugin.cc' --- a/sql/sql_plugin.cc 2010-12-06 13:12:51 +0000 +++ b/sql/sql_plugin.cc 2011-01-28 13:37:15 +0000 @@ -1,4 +1,4 @@ -/* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2005, 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 @@ -1039,6 +1039,9 @@ void plugin_unlock_list(THD *thd, plugin LEX *lex= thd ? thd->lex : 0; DBUG_ENTER("plugin_unlock_list"); DBUG_ASSERT(list); + if (count == 0) + DBUG_VOID_RETURN; + mysql_mutex_lock(&LOCK_plugin); while (count--) intern_plugin_unlock(lex, *list++); === modified file 'unittest/gunit/CMakeLists.txt' --- a/unittest/gunit/CMakeLists.txt 2011-01-14 09:29:11 +0000 +++ b/unittest/gunit/CMakeLists.txt 2011-01-28 13:37:15 +0000 @@ -1,4 +1,4 @@ -# Copyright (C) 2009 Sun Microsystems,Inc +# Copyright (c) 2009, 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 @@ -122,7 +122,7 @@ IF(NOT GTEST_FOUND) FIND_PROGRAM(WGET_EXECUTABLE wget) MARK_AS_ADVANCED(WGET_EXECUTABLE) IF(WGET_EXECUTABLE) - EXECUTE_PROCESS(COMMAND ${WGET_EXECUTABLE} -T 30 ${GTEST_DOWNLOAD_URL} + EXECUTE_PROCESS(COMMAND ${WGET_EXECUTABLE} -T 30 ${GTEST_DOWNLOAD_URL} WORKING_DIRECTORY ${DOWNLOAD_ROOT} RESULT_VARIABLE ERR) IF(ERR EQUAL 0) SET(DOWNLOAD_SUCCEEDED 1) @@ -218,6 +218,11 @@ SET(TESTS thread_utils ) +# Add tests (link them with gunit library and the server libraries) +SET(SERVER_TESTS + item +) + FOREACH(test ${TESTS}) ADD_EXECUTABLE(${test}-t ${test}-t.cc) TARGET_LINK_LIBRARIES(${test}-t gunit sqlgunitlib strings dbug regex) @@ -226,3 +231,17 @@ FOREACH(test ${TESTS}) ENDIF() ADD_TEST(${test} ${test}-t) ENDFOREACH() + +FOREACH(test ${SERVER_TESTS}) + IF(WIN32) + ADD_EXECUTABLE(${test}-t ${test}-t.cc ../../sql/nt_servc.cc) + ELSE() + ADD_EXECUTABLE(${test}-t ${test}-t.cc) + ENDIF() + TARGET_LINK_LIBRARIES(${test}-t sql binlog rpl master slave sql) + TARGET_LINK_LIBRARIES(${test}-t gunit sqlgunitlib strings dbug regex) + IF (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro") + SET_TARGET_PROPERTIES(${test}-t PROPERTIES LINK_FLAGS "-library=stlport4") + ENDIF() + ADD_TEST(${test} ${test}-t) +ENDFOREACH() === added file 'unittest/gunit/item-t.cc' --- a/unittest/gunit/item-t.cc 1970-01-01 00:00:00 +0000 +++ b/unittest/gunit/item-t.cc 2011-01-28 13:37:15 +0000 @@ -0,0 +1,170 @@ +/* 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 "item.h" +#include "sql_class.h" +#include "rpl_handler.h" // delegates_init() + +namespace { + +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() + { + init_thread_environment(); + randominit(&sql_rand, 0, 0); + xid_cache_init(); + delegates_init(); + } + + static void TearDownTestCase() + { + delegates_destroy(); + xid_cache_free(); + } + + ItemTest() : m_thd(NULL) {} + + virtual void SetUp() + { + m_thd= new THD(false); + m_thd->thread_stack= (char*) &m_thd; + m_thd->store_globals(); + } + + virtual void TearDown() + { + m_thd->cleanup_after_query(); + delete m_thd; + } + +private: + THD *m_thd; +}; + + +/** + This is a simple mock Field class, which verifies that store() is called. + TODO: Introduce Google Mock to simplify writing of mock classes. +*/ +class Mock_field_long : public Field_long +{ +public: + Mock_field_long(uint32 lenght, longlong expected_value) + : Field_long(0, // ptr_arg + lenght, // len_arg + NULL, // null_ptr_arg + 0, // null_bit_arg + Field::NONE, // unireg_check_arg + 0, // field_name_arg + false, // zero_arg + false), // unsigned_arg + m_store_called(0), + m_expected_value(expected_value) + {} + + // The destructor verifies that store() has been called. + virtual ~Mock_field_long() + { + EXPECT_EQ(1, m_store_called); + } + + /* + This is the only member function we need to override. + We expect it to be called with specific arguments. + */ + virtual int store(longlong nr, bool unsigned_val) + { + EXPECT_EQ(m_expected_value, nr); + EXPECT_FALSE(unsigned_val); + ++m_store_called; + return 0; + } + +private: + int m_store_called; + longlong m_expected_value; +}; + + +TEST_F(ItemTest, item_int) +{ + const int32 val= 42; + char stringbuf[10]; + (void) my_snprintf(stringbuf, sizeof(stringbuf), "%d", val); + + // An Item expects to be owned by current_thd->free_list, + // so allocate with new, and do not delete it. + Item_int *item_int= new Item_int(val); + + EXPECT_EQ(Item::INT_ITEM, item_int->type()); + EXPECT_EQ(INT_RESULT, item_int->result_type()); + EXPECT_EQ(MYSQL_TYPE_LONGLONG, item_int->field_type()); + EXPECT_EQ(val, item_int->val_int()); + EXPECT_DOUBLE_EQ((double) val, item_int->val_real()); + EXPECT_TRUE(item_int->basic_const_item()); + + my_decimal decimal_val; + EXPECT_EQ(&decimal_val, item_int->val_decimal(&decimal_val)); + + String string_val; + EXPECT_EQ(&string_val, item_int->val_str(&string_val)); + EXPECT_STREQ(stringbuf, string_val.c_ptr_safe()); + + { + // New scope, since we have EXPECT_EQ in the destructor as well. + Mock_field_long field_val(item_int->max_length, val); + EXPECT_EQ(0, item_int->save_in_field(&field_val, true)); + } + + Item *clone= item_int->clone_item(); + EXPECT_TRUE(item_int->eq(clone, true)); + EXPECT_TRUE(item_int->eq(item_int, true)); + + String print_val; + item_int->print(&print_val, QT_ORDINARY); + EXPECT_STREQ(stringbuf, print_val.c_ptr_safe()); + + const uint precision= item_int->decimal_precision(); + EXPECT_EQ(MY_INT32_NUM_DECIMAL_DIGITS, precision); + + item_int->neg(); + EXPECT_EQ(-val, item_int->val_int()); + EXPECT_EQ(precision - 1, item_int->decimal_precision()); + + // Functions inherited from parent class(es). + const table_map tmap= 0; + EXPECT_EQ(tmap, item_int->used_tables()); + + /* + TODO: There are about 100 member functions in Item. + Figure out which ones are relevant for unit testing here. + */ +} + +} --===============7197275574944457056== 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\ # g4ghnpwwcfuw1y5u # target_branch: file:///export/home/didrik/repo/trunk-thd-item/ # testament_sha1: 9f011519f21b574fd1ef9032339798867426fc50 # timestamp: 2011-01-28 14:37:20 +0100 # base_revision_id: tor.didriksen@stripped\ # qo3gyazm32xcwsw8 # # Begin bundle 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 --===============7197275574944457056==--