#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 <gtest/gtest.h>
+#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 <gtest/gtest.h>
+
+#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<char*>(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 <gtest/gtest.h>
+
+#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
Attachment: [text/bzr-bundle] bzr/tor.didriksen@oracle.com-20110513093613-6cugcprzhhujr39k.bundle
| Thread |
|---|
| • bzr commit into mysql-trunk-mtr branch (tor.didriksen:3080) Bug#11788245 | Tor Didriksen | 13 May |