224 lines
6.7 KiB
C++

/*
Copyright (c) 2015, 2016, 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-1301 USA */
// First include (the generated) my_config.h, to get correct platform defines.
#include "my_config.h"
#include <gtest/gtest.h>
#include "mysys_err.h"
#include "my_sys.h"
extern "C" void mock_error_handler_hook(uint err, const char *str, myf MyFlags);
/**
An alternative error_handler for non-server unit tests since it does
not rely on THD. It sets the global error handler function.
*/
class Mock_global_error_handler
{
public:
Mock_global_error_handler(uint expected_error):
m_expected_error(expected_error),
m_handle_called(0)
{
current= this;
m_old_error_handler_hook= error_handler_hook;
error_handler_hook = mock_error_handler_hook;
}
virtual ~Mock_global_error_handler()
{
if (m_expected_error == 0)
{
EXPECT_EQ(0, m_handle_called);
}
else
{
EXPECT_GT(m_handle_called, 0);
}
error_handler_hook= m_old_error_handler_hook;
current= NULL;
}
void error_handler(uint err)
{
EXPECT_EQ(m_expected_error, err);
++m_handle_called;
}
int handle_called() const { return m_handle_called; }
static Mock_global_error_handler *current;
private:
uint m_expected_error;
int m_handle_called;
void (*m_old_error_handler_hook)(uint, const char *, myf);
};
Mock_global_error_handler *Mock_global_error_handler::current= NULL;
/*
Error handler function.
*/
extern "C" void mock_error_handler_hook(uint err, const char *str, myf MyFlags)
{
if (Mock_global_error_handler::current)
Mock_global_error_handler::current->error_handler(err);
}
namespace my_alloc_unittest {
const size_t num_iterations= 1ULL;
class MyAllocTest : public ::testing::TestWithParam<size_t>
{
protected:
virtual void SetUp()
{
init_alloc_root(PSI_NOT_INSTRUMENTED, &m_root, 1024, 0);
}
virtual void TearDown()
{
free_root(&m_root, MYF(0));
}
size_t m_num_objects;
MEM_ROOT m_root;
};
class MyPreAllocTest : public ::testing::Test
{
protected:
virtual void SetUp()
{
init_alloc_root(PSI_NOT_INSTRUMENTED, &m_prealloc_root, 1024, 2048);
}
virtual void TearDown()
{
free_root(&m_prealloc_root, MYF(0));
}
size_t m_num_objects;
MEM_ROOT m_prealloc_root;
};
size_t test_values[]= {100, 1000, 10000, 100000 };
INSTANTIATE_TEST_CASE_P(MyAlloc, MyAllocTest,
::testing::ValuesIn(test_values));
TEST_P(MyAllocTest, NoMemoryLimit)
{
m_num_objects= GetParam();
for (size_t ix= 0; ix < num_iterations; ++ix)
{
for (size_t objcount= 0; objcount < m_num_objects; ++objcount)
alloc_root(&m_root, 100);
}
}
TEST_P(MyAllocTest, WithMemoryLimit)
{
m_num_objects= GetParam();
set_memroot_max_capacity(&m_root, num_iterations * m_num_objects * 100);
for (size_t ix= 0; ix < num_iterations; ++ix)
{
for (size_t objcount= 0; objcount < m_num_objects; ++objcount)
alloc_root(&m_root, 100);
}
}
TEST_F(MyAllocTest, CheckErrorReporting)
{
const void *null_pointer= NULL;
EXPECT_TRUE(alloc_root(&m_root, 1000));
set_memroot_max_capacity(&m_root, 100);
EXPECT_EQ(null_pointer, alloc_root(&m_root, 1000));
set_memroot_error_reporting(&m_root, true);
Mock_global_error_handler error_handler(EE_CAPACITY_EXCEEDED);
EXPECT_TRUE(alloc_root(&m_root, 1000));
EXPECT_EQ(1, error_handler.handle_called());
}
TEST_F(MyPreAllocTest, PreAlloc)
{
// PREALLOCATE_MEMORY_CHUNKS is not defined for valgrind and ASAN
#if !defined(HAVE_VALGRIND) && !defined(HAVE_ASAN)
const void *null_pointer= NULL;
// MEMROOT has pre-allocated 2048 bytes memory plus some overhead
size_t pre_allocated= m_prealloc_root.allocated_size;
EXPECT_LT((unsigned int)2048, pre_allocated);
// This will eat of pre-allocated memory, no more should be allocated
EXPECT_TRUE(alloc_root(&m_prealloc_root, 1000));
EXPECT_EQ(pre_allocated, m_prealloc_root.allocated_size);
set_memroot_max_capacity(&m_prealloc_root, 100);
// Sufficient memory has been pre-allocated, so first alloc below will succeed
EXPECT_TRUE(alloc_root(&m_prealloc_root, 1000));
EXPECT_EQ(null_pointer, alloc_root(&m_prealloc_root, 100));
EXPECT_EQ(pre_allocated, m_prealloc_root.allocated_size);
// Setting error reporting. Error is flagged but allocation succeeds
set_memroot_error_reporting(&m_prealloc_root, true);
{
Mock_global_error_handler error_handler(EE_CAPACITY_EXCEEDED);
EXPECT_TRUE(alloc_root(&m_prealloc_root, 1000));
EXPECT_EQ(1, error_handler.handle_called());
EXPECT_LT(pre_allocated, m_prealloc_root.allocated_size);
pre_allocated= m_prealloc_root.allocated_size;
}
set_memroot_error_reporting(&m_prealloc_root, false);
//This will just mark the blocks free.
free_root(&m_prealloc_root, MY_MARK_BLOCKS_FREE);
EXPECT_EQ(pre_allocated, m_prealloc_root.allocated_size);
set_memroot_max_capacity(&m_prealloc_root, 2048);
reset_root_defaults(&m_prealloc_root, 1024, 0);
EXPECT_EQ(pre_allocated, m_prealloc_root.allocated_size);
reset_root_defaults(&m_prealloc_root, 1024, 1024);
EXPECT_LT((unsigned int)1024, m_prealloc_root.allocated_size);
reset_root_defaults(&m_prealloc_root, 512, 1024);
EXPECT_LT((unsigned int)1024, m_prealloc_root.allocated_size);
pre_allocated= m_prealloc_root.allocated_size;
// This allocation will use pre-alocated memory
EXPECT_TRUE(alloc_root(&m_prealloc_root, 1024));
EXPECT_EQ(pre_allocated, m_prealloc_root.allocated_size);
// Will allocate more memory
EXPECT_TRUE(alloc_root(&m_prealloc_root, 512));
EXPECT_LT((unsigned int)1526, m_prealloc_root.allocated_size);
pre_allocated= m_prealloc_root.allocated_size;
// This will not succeed
EXPECT_EQ(null_pointer, alloc_root(&m_prealloc_root, 512));
free_root(&m_prealloc_root, MY_KEEP_PREALLOC);
EXPECT_LT((unsigned int)1024, m_prealloc_root.allocated_size);
// Specified pre_alloc_size is above capacity. Expect no pre-allocation
reset_root_defaults(&m_prealloc_root, 512, 4096);
EXPECT_EQ((unsigned int)0, m_prealloc_root.allocated_size);
free_root(&m_prealloc_root, 0);
EXPECT_EQ((unsigned int)0, m_prealloc_root.allocated_size);
#endif
}
}