/* Copyright (c) 2013, 2015, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /** This is unit test for the Global_THD_manager class. */ #include "my_config.h" #include #include "sql_class.h" #include "thread_utils.h" #include "mysqld.h" #include "mysqld_thd_manager.h" // Global_THD_manager using thread::Thread; using thread::Notification; namespace thd_manager_unittest { class ThreadManagerTest : public ::testing::Test { protected: ThreadManagerTest() { } void SetUp() { Global_THD_manager::create_instance(); thd_manager= Global_THD_manager::get_instance(); thd_manager->set_unit_test(); } void TearDown() { } Global_THD_manager *thd_manager; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadManagerTest); }; enum TEST_TYPE { TEST_WAIT=0, TEST_TIMED_WAIT=1 }; /* Verify add_thd(), remove_thd() methods */ TEST_F(ThreadManagerTest, AddRemoveTHDWithGuard) { THD thd1(false), thd2(false); thd1.server_id= 1; thd1.set_new_thread_id(); thd2.server_id= 2; thd2.set_new_thread_id(); EXPECT_EQ(0U, thd_manager->get_thd_count()); thd_manager->add_thd(&thd1); EXPECT_EQ(1U, thd_manager->get_thd_count()); thd_manager->add_thd(&thd2); thd_manager->remove_thd(&thd1); EXPECT_EQ(1U, thd_manager->get_thd_count()); thd_manager->remove_thd(&thd2); EXPECT_EQ(0U, thd_manager->get_thd_count()); } TEST_F(ThreadManagerTest, IncDecThreadRunning) { EXPECT_EQ(0, thd_manager->get_num_thread_running()); thd_manager->inc_thread_running(); EXPECT_EQ(1, thd_manager->get_num_thread_running()); thd_manager->dec_thread_running(); EXPECT_EQ(0, thd_manager->get_num_thread_running()); } TEST_F(ThreadManagerTest, IncThreadCreated) { EXPECT_EQ(0U, thd_manager->get_num_thread_created()); thd_manager->inc_thread_created(); EXPECT_EQ(1U, thd_manager->get_num_thread_created()); } /* Test function to validate do_for_all_thd, do_for_all_thd_copy. It emulates counter function to count number of thds in thd list. */ class TestFunc1 : public Do_THD_Impl { private: int cnt; public: TestFunc1() : cnt(0) {} int get_count() { return cnt; } void reset_count() { cnt= 0; } void operator() (THD* thd) { cnt= cnt + 1; } }; TEST_F(ThreadManagerTest, TestTHDCopyDoFunc) { THD thd1(false), thd2(false); thd1.server_id= 1; thd1.set_new_thread_id(); thd2.server_id= 2; thd2.set_new_thread_id(); // Add two THD into thd list. thd_manager->add_thd(&thd1); thd_manager->add_thd(&thd2); int cnt= 0; TestFunc1 testFunc1; thd_manager->do_for_all_thd_copy(&testFunc1); cnt= testFunc1.get_count(); EXPECT_EQ(2, cnt); testFunc1.reset_count(); thd_manager->do_for_all_thd(&testFunc1); cnt= testFunc1.get_count(); EXPECT_EQ(2, cnt); // Cleanup - Remove added THD. thd_manager->remove_thd(&thd1); thd_manager->remove_thd(&thd2); } /* Test class to verify find_thd() */ class TestFunc2 : public Find_THD_Impl { public: TestFunc2() : search_value(0) {} bool operator() (THD* thd) { if (thd->server_id == search_value) { return true; } return false; } void set_search_value(uint val) { search_value= val; } private: uint search_value; }; /* Test class to verify do_all_for_thd() function. Counts all thd whose server_id value is less than or equal to 2. */ class TestFunc3 : public Do_THD_Impl { public: TestFunc3() : count(0) {} void operator() (THD* thd) { if (thd->server_id <= 2) { count++; } } int get_count() { return count; } private: int count; }; TEST_F(ThreadManagerTest, TestTHDFindFunc) { THD thd1(false), thd2(false); thd1.server_id= 1; thd1.set_new_thread_id(); thd2.server_id= 2; thd2.set_new_thread_id(); thd_manager->add_thd(&thd1); thd_manager->add_thd(&thd2); TestFunc2 testFunc2; testFunc2.set_search_value(2); THD *thd= thd_manager->find_thd(&testFunc2); /* Returns the last thd which matches. */ EXPECT_EQ(2U, thd->server_id); testFunc2.set_search_value(6); thd= thd_manager->find_thd(&testFunc2); /* Find non existing thd with server_id value 6. Expected to return NULL. */ const THD* null_thd= NULL; EXPECT_EQ(null_thd, thd); // Cleanup - Remove added THD. thd_manager->remove_thd(&thd1); thd_manager->remove_thd(&thd2); } TEST_F(ThreadManagerTest, TestTHDCountFunc) { THD thd1(false), thd2(false), thd3(false); thd1.server_id= 1; thd1.set_new_thread_id(); thd2.server_id= 2; thd2.set_new_thread_id(); thd3.server_id= 3; thd3.set_new_thread_id(); thd_manager->add_thd(&thd1); thd_manager->add_thd(&thd2); thd_manager->add_thd(&thd3); TestFunc3 testFunc3; thd_manager->do_for_all_thd(&testFunc3); int ret=testFunc3.get_count(); // testFunc3 counts for thd->server_id values, 1 and 2. EXPECT_EQ(2, ret); // Cleanup - Remove added THD. thd_manager->remove_thd(&thd1); thd_manager->remove_thd(&thd2); thd_manager->remove_thd(&thd3); } TEST_F(ThreadManagerTest, ThreadID) { // Code assumes that the size of my_thread_id is 32 bit. ASSERT_EQ(4U, sizeof(my_thread_id)); // Reset the thread ID counter thd_manager->set_thread_id_counter(1); EXPECT_EQ(1U, thd_manager->get_thread_id()); // The counter is incremented after ID is assigned. EXPECT_EQ(1U, thd_manager->get_new_thread_id()); EXPECT_EQ(2U, thd_manager->get_thread_id()); // Two increments in a row EXPECT_EQ(2U, thd_manager->get_new_thread_id()); EXPECT_EQ(3U, thd_manager->get_new_thread_id()); EXPECT_EQ(4U, thd_manager->get_thread_id()); // Force wrap of the counter thd_manager->set_thread_id_counter(UINT_MAX32); EXPECT_EQ(UINT_MAX32, thd_manager->get_new_thread_id()); // We should not use the value reserved for temporary THDs (0). // The next available value should be 4. EXPECT_EQ(4U, thd_manager->get_new_thread_id()); EXPECT_EQ(5U, thd_manager->get_thread_id()); // Release thread ID 3 and reset counter. thd_manager->release_thread_id(3); thd_manager->set_thread_id_counter(1U); EXPECT_EQ(3U, thd_manager->get_new_thread_id()); // Releasing the reserved thread ID is allowed - multiple times. thd_manager->release_thread_id(Global_THD_manager::reserved_thread_id); thd_manager->release_thread_id(Global_THD_manager::reserved_thread_id); // Cleanup thd_manager->release_thread_id(1); thd_manager->release_thread_id(2); thd_manager->release_thread_id(3); thd_manager->release_thread_id(4); thd_manager->release_thread_id(UINT_MAX32); } #if !defined(DBUG_OFF) TEST_F(ThreadManagerTest, ThreadIDDeathTest) { ::testing::FLAGS_gtest_death_test_style = "threadsafe"; my_thread_id thread_id= thd_manager->get_new_thread_id(); thd_manager->release_thread_id(thread_id); // Releasing the same ID twice should assert. EXPECT_DEATH_IF_SUPPORTED(thd_manager->release_thread_id(thread_id), ".*Assertion .*1 == num_erased.*"); } #endif } // namespace