List:Commits« Previous MessageNext Message »
From:Tor Didriksen Date:January 28 2011 1:37pm
Subject:bzr commit into mysql-trunk branch (tor.didriksen:3563) Bug#59794
View as plain text  
#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 <gtest/gtest.h>
+
+#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.
+  */
+}
+
+}


Attachment: [text/bzr-bundle] bzr/tor.didriksen@oracle.com-20110128133715-g4ghnpwwcfuw1y5u.bundle
Thread
bzr commit into mysql-trunk branch (tor.didriksen:3563) Bug#59794Tor Didriksen28 Jan
  • Re: bzr commit into mysql-trunk branch (tor.didriksen:3563) Bug#59794Jon Olav Hauglid31 Jan