/* Copyright (c) 2011, 2014, 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, 51 Franklin Street, Suite 500, Boston, MA 02110-1335 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 #include "mock_field_timestamp.h" #include "fake_table.h" #include "test_utils.h" #include "sql_data_change.h" namespace copy_info_unittest { using my_testing::Server_initializer; using my_testing::Mock_error_handler; using ::testing::StrictMock; using ::testing::_; /* Tests for the functionality of the COPY_INFO class. We test all public interfaces, and some of the protected parts: - COPY_INFO::get_function_default_columns, and - COPY_INFO::get_cached_bitmap */ class CopyInfoTest : public ::testing::Test { protected: virtual void SetUp() { initializer.SetUp(); } virtual void TearDown() { initializer.TearDown(); } Server_initializer initializer; }; /** This is a simple mock Field class, which verifies that store_timestamp is called. We inherit Field_long, but the data type does not matter. */ class Mock_field : public Field_long { uchar null_byte; public: Mock_field(utype unireg) : Field_long(NULL, 0, &null_byte, 0, unireg, "", false, false) {} MOCK_METHOD1(store_timestamp, void(const timeval*)); }; /* Compares two COPY_INFO::Statistics and makes sure they are equal. */ void check_equality(const COPY_INFO::Statistics a, const COPY_INFO::Statistics b) { EXPECT_EQ(a.records, b.records); EXPECT_EQ(a.deleted, b.deleted); EXPECT_EQ(a.updated, b.updated); EXPECT_EQ(a.copied, b.copied); EXPECT_EQ(a.error_count, b.error_count); EXPECT_EQ(a.touched, b.touched); } /* Convenience class for creating a COPY_INFO to represent an insert operation. */ class Mock_COPY_INFO: public COPY_INFO { public: Mock_COPY_INFO(operation_type optype, List *inserted_columns, enum_duplicates duplicate_handling) : COPY_INFO(optype, inserted_columns, true, // manage_defaults duplicate_handling) {} // Import protected member functions, so we can test them. using COPY_INFO::get_function_default_columns; using COPY_INFO::get_cached_bitmap; }; /* Convenience class for creating a COPY_INFO to represent an insert operation. */ class Mock_COPY_INFO_insert : public COPY_INFO { public: Mock_COPY_INFO_insert() : COPY_INFO(COPY_INFO::INSERT_OPERATION, static_cast*>(NULL), true, // manage_defaults DUP_UPDATE) {} Mock_COPY_INFO_insert(List *fields) : COPY_INFO(COPY_INFO::INSERT_OPERATION, fields, true, // manage_defaults DUP_UPDATE) {} // Import protected member functions, so we can test them. using COPY_INFO::get_function_default_columns; using COPY_INFO::get_cached_bitmap; }; /* Convenience class for creating a COPY_INFO to represent an update operation. */ class Mock_COPY_INFO_update : public COPY_INFO { public: Mock_COPY_INFO_update() : COPY_INFO(COPY_INFO::UPDATE_OPERATION, NULL, NULL) {} // Import protected member functions, so we can test them. using COPY_INFO::get_function_default_columns; using COPY_INFO::get_cached_bitmap; }; /* Tests that constuctors initialize the stats object properly. */ TEST_F(CopyInfoTest, constructors) { List inserted_columns; COPY_INFO insert(COPY_INFO::INSERT_OPERATION, &inserted_columns, true, // manage_defaults DUP_UPDATE); EXPECT_EQ(0U, insert.stats.records); EXPECT_EQ(0U, insert.stats.deleted); EXPECT_EQ(0U, insert.stats.updated); EXPECT_EQ(0U, insert.stats.copied); EXPECT_EQ(0U, insert.stats.error_count); EXPECT_EQ(0U, insert.stats.touched); List columns; List values; COPY_INFO update(COPY_INFO::UPDATE_OPERATION, &columns, &values); EXPECT_EQ(0U, update.stats.records); EXPECT_EQ(0U, update.stats.deleted); EXPECT_EQ(0U, update.stats.updated); EXPECT_EQ(0U, update.stats.copied); EXPECT_EQ(0U, update.stats.error_count); EXPECT_EQ(0U, update.stats.touched); } /* Tests the accessors when the COPY_INFO represents an insert operation. */ TEST_F(CopyInfoTest, insertAccessors) { List inserted_columns; COPY_INFO insert(COPY_INFO::INSERT_OPERATION, &inserted_columns, true, // manage_defaults DUP_REPLACE); EXPECT_EQ(COPY_INFO::INSERT_OPERATION, insert.get_operation_type()); EXPECT_EQ(&inserted_columns, insert.get_changed_columns()); EXPECT_EQ(static_cast*>(NULL), insert.get_changed_columns2()); EXPECT_TRUE(insert.get_manage_defaults()); EXPECT_EQ(DUP_REPLACE, insert.get_duplicate_handling()); } /* Tests the accessors when the COPY_INFO represents a load data infile operation. */ TEST_F(CopyInfoTest, loadDataAccessors) { List inserted_columns; List inserted_columns2; COPY_INFO load_data(COPY_INFO::INSERT_OPERATION, &inserted_columns, &inserted_columns2, true, // manage_defaults DUP_UPDATE, 123); EXPECT_EQ(COPY_INFO::INSERT_OPERATION, load_data.get_operation_type()); EXPECT_EQ(&inserted_columns, load_data.get_changed_columns()); EXPECT_EQ(&inserted_columns2, load_data.get_changed_columns2()); EXPECT_TRUE(load_data.get_manage_defaults()); EXPECT_EQ(DUP_UPDATE, load_data.get_duplicate_handling()); } /* Tests the accessors when the COPY_INFO represents an update operation. */ TEST_F(CopyInfoTest, updateAccessors) { List columns; List values; COPY_INFO update(COPY_INFO::UPDATE_OPERATION, &columns, &values); EXPECT_EQ(COPY_INFO::UPDATE_OPERATION, update.get_operation_type()); EXPECT_EQ(&columns, update.get_changed_columns()); EXPECT_EQ(static_cast*>(NULL), update.get_changed_columns2()); EXPECT_TRUE(update.get_manage_defaults()); EXPECT_EQ(DUP_ERROR, update.get_duplicate_handling()); } Field_long make_field() { static uchar unused_null_byte; Field_long a(NULL, 0, &unused_null_byte, 0, Field::TIMESTAMP_DN_FIELD, "a", false, false); return a; } /* Test of the lazy instantiation performed by get_function_default_columns(). - The bitmap pointer is initially NULL. - That calling get_function_default_columns() indeed points the member to a lazily instantiated bitmap. - That on a second call to get_function_default_columns(), a new bitmap is not allocated. We repeat the test for insert and update operations. */ TEST_F(CopyInfoTest, getFunctionDefaultColumns) { Mock_COPY_INFO_insert insert; Mock_COPY_INFO_update update; Field_long a= make_field(); Fake_TABLE table(&a); MY_BITMAP *initial_value= NULL; EXPECT_EQ(initial_value, insert.get_cached_bitmap()); insert.get_function_default_columns(&table); EXPECT_NE(initial_value, insert.get_cached_bitmap()) << "The output parameter must be set!"; const MY_BITMAP *function_default_columns= insert.get_cached_bitmap(); insert.get_function_default_columns(&table); EXPECT_EQ(function_default_columns, insert.get_cached_bitmap()) << "Not supposed to allocate a new bitmap on second call."; EXPECT_EQ(initial_value, update.get_cached_bitmap()); update.get_function_default_columns(&table); EXPECT_NE(initial_value, update.get_cached_bitmap()) << "The output parameter must be set!"; function_default_columns= update.get_cached_bitmap(); update.get_function_default_columns(&table); EXPECT_EQ(function_default_columns, update.get_cached_bitmap()) << "Not supposed to allocate a new bitmap on second call."; } /* Here we test that calling COPY_INFO::set_function_defaults() indeed causes store_timestamp to be called on the columns that are not on the list of assigned_columns. We seize the opportunity to test COPY_INFO::function_defaults_apply() since we have to call it anyways in order for set_function_defaults() not to assert. */ TEST_F(CopyInfoTest, setFunctionDefaults) { StrictMock a(Field::TIMESTAMP_UN_FIELD); StrictMock b(Field::TIMESTAMP_DNUN_FIELD); StrictMock c(Field::TIMESTAMP_DNUN_FIELD); EXPECT_TRUE(a.has_update_default_function()); EXPECT_TRUE(b.has_update_default_function()); EXPECT_TRUE(c.has_update_default_function()); Fake_TABLE table(&a, &b, &c); List assigned_columns; assigned_columns.push_front(new Item_field(&a)); Mock_COPY_INFO insert(COPY_INFO::INSERT_OPERATION, &assigned_columns, DUP_ERROR); ASSERT_FALSE(insert.get_function_default_columns(&table)) << "Out of memory"; insert.ignore_last_columns(&table, 1); // 'c' insert.add_function_default_columns(&table, table.write_set); EXPECT_FALSE(bitmap_is_set(table.write_set, 0)); EXPECT_TRUE (bitmap_is_set(table.write_set, 1)); EXPECT_FALSE(bitmap_is_set(table.write_set, 2)); EXPECT_TRUE(insert.function_defaults_apply(&table)) << "They do apply"; // We expect store_timestamp() to be called for b and not for c. // We do not care about the argument to store_timestamp(). EXPECT_CALL(b, store_timestamp(_)).Times(1); EXPECT_CALL(c, store_timestamp(_)).Times(0); insert.set_function_defaults(&table); } }