344 lines
10 KiB
C++

/* 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 <gtest/gtest.h>
#include <gmock/gmock.h>
#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<Item> *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<List<Item>*>(NULL),
true, // manage_defaults
DUP_UPDATE)
{}
Mock_COPY_INFO_insert(List<Item> *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<Item> 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<Item> columns;
List<Item> 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<Item> 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<List<Item>*>(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<Item> inserted_columns;
List<Item> 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<Item> columns;
List<Item> 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<List<Item>*>(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<Mock_field> a(Field::TIMESTAMP_UN_FIELD);
StrictMock<Mock_field> b(Field::TIMESTAMP_DNUN_FIELD);
StrictMock<Mock_field> 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<Item> 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);
}
}