init push
This commit is contained in:
255
unittest/share/interrupt/test_interrupt_system.cpp
Normal file
255
unittest/share/interrupt/test_interrupt_system.cpp
Normal file
@ -0,0 +1,255 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OceanBase
|
||||
* OceanBase CE is licensed under Mulan PubL v2.
|
||||
* You can use this software according to the terms and conditions of the Mulan PubL v2.
|
||||
* You may obtain a copy of Mulan PubL v2 at:
|
||||
* http://license.coscl.org.cn/MulanPubL-2.0
|
||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||
* See the Mulan PubL v2 for more details.
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#define private public
|
||||
|
||||
#include "lib/coro/co.h"
|
||||
#include "lib/coro/testing.h"
|
||||
#include "share/interrupt/ob_interrupt_rpc_proxy.h"
|
||||
#include "share/interrupt/ob_global_interrupt_call.h"
|
||||
#include "rpc/testing.h"
|
||||
|
||||
using namespace oceanbase::obrpc;
|
||||
|
||||
namespace oceanbase {
|
||||
namespace common {
|
||||
|
||||
TEST(ObGlobalInterruptManager, normal)
|
||||
{
|
||||
|
||||
rpctesting::Service service;
|
||||
ObInterruptProcessor p;
|
||||
service.init();
|
||||
service.reg_processor(&p);
|
||||
ObInterruptRpcProxy proxy;
|
||||
service.get_proxy(proxy);
|
||||
|
||||
int ret = OB_SUCCESS;
|
||||
int temp_id = 1;
|
||||
int icode = 1;
|
||||
ObAddr local(ObAddr::IPV4, "127.0.0.1", 10086);
|
||||
ObAddr dst = service.get_dst();
|
||||
|
||||
/// Singleton acquisition
|
||||
ObGlobalInterruptManager* manager = ObGlobalInterruptManager::getInstance();
|
||||
ASSERT_EQ(false, nullptr == manager);
|
||||
|
||||
ObInterruptChecker* checker = nullptr;
|
||||
/// Perform various operations without initialization, correct feedback
|
||||
|
||||
ret = manager->interrupt(temp_id, icode);
|
||||
ASSERT_EQ(OB_NOT_INIT, ret);
|
||||
|
||||
ret = manager->interrupt(local, temp_id, icode);
|
||||
ASSERT_EQ(OB_NOT_INIT, ret);
|
||||
|
||||
ret = manager->register_checker(checker);
|
||||
ASSERT_EQ(OB_NOT_INIT, ret);
|
||||
|
||||
ret = manager->unregister_checker(checker);
|
||||
ASSERT_EQ(OB_NOT_INIT, ret);
|
||||
|
||||
/// No RPC initialization is illegal
|
||||
ret = manager->init(local, nullptr);
|
||||
ASSERT_EQ(OB_INVALID_ARGUMENT, ret);
|
||||
|
||||
/// Regular initialization
|
||||
ret = manager->init(local, &proxy);
|
||||
ASSERT_EQ(OB_SUCCESS, ret);
|
||||
|
||||
/// Initialize correctly and feedback error many times
|
||||
ret = manager->init(local, &proxy);
|
||||
ASSERT_EQ(OB_INIT_TWICE, ret);
|
||||
|
||||
ret = manager->register_checker(checker);
|
||||
ASSERT_EQ(OB_INVALID_ARGUMENT, ret);
|
||||
|
||||
ret = manager->unregister_checker(checker);
|
||||
ASSERT_EQ(OB_INVALID_ARGUMENT, ret);
|
||||
|
||||
/// Get the inspector
|
||||
checker = new ObInterruptChecker(true, temp_id);
|
||||
/// Test self-registration
|
||||
ret = checker->register_checker(temp_id);
|
||||
ASSERT_EQ(OB_SUCCESS, ret);
|
||||
|
||||
/// Test duplicate registration
|
||||
ret = checker->register_checker(temp_id);
|
||||
ASSERT_EQ(OB_INIT_TWICE, ret);
|
||||
ret = checker->register_checker(temp_id + 1);
|
||||
ASSERT_EQ(OB_INIT_TWICE, ret);
|
||||
ret = manager->register_checker(checker);
|
||||
ASSERT_EQ(OB_INIT_TWICE, ret);
|
||||
|
||||
/// Semaphore detection without interruption
|
||||
bool r = checker->is_interrupted();
|
||||
ASSERT_EQ(false, r);
|
||||
|
||||
/// Local execution interrupt check semaphore
|
||||
ret = manager->interrupt(temp_id, icode);
|
||||
ASSERT_EQ(OB_SUCCESS, ret);
|
||||
|
||||
r = checker->is_interrupted();
|
||||
ASSERT_EQ(true, r);
|
||||
|
||||
/// Release checker
|
||||
ret = manager->unregister_checker(checker);
|
||||
ASSERT_EQ(OB_SUCCESS, ret);
|
||||
|
||||
/// The interrupt can still be called after the checker is released
|
||||
ret = manager->interrupt(local, temp_id, icode);
|
||||
ASSERT_EQ(OB_SUCCESS, ret);
|
||||
|
||||
/// Downgrade to local interrupt test when remote interrupt is passed to local address
|
||||
manager->register_checker(checker);
|
||||
ret = manager->interrupt(local, temp_id, icode);
|
||||
ASSERT_EQ(OB_SUCCESS, ret);
|
||||
|
||||
r = checker->is_interrupted();
|
||||
ASSERT_EQ(true, r);
|
||||
|
||||
// Test status clear
|
||||
checker->clear_status();
|
||||
r = checker->is_interrupted();
|
||||
ASSERT_EQ(false, r);
|
||||
|
||||
manager->interrupt(temp_id, icode);
|
||||
r = checker->is_interrupted();
|
||||
ASSERT_EQ(true, r);
|
||||
|
||||
/// rpc call test
|
||||
checker->clear_status();
|
||||
ret = manager->interrupt(dst, temp_id, icode);
|
||||
ASSERT_EQ(OB_SUCCESS, ret);
|
||||
|
||||
r = checker->is_interrupted();
|
||||
ASSERT_EQ(true, r);
|
||||
|
||||
// Automatic logout of test destruction
|
||||
delete checker;
|
||||
|
||||
ret = manager->map_.get_refactored(temp_id, checker);
|
||||
EXPECT_EQ(OB_HASH_NOT_EXIST, ret);
|
||||
|
||||
// Test group registration, interruption and deregistration
|
||||
ObInterruptChecker* checker0 = new ObInterruptChecker(true, 1);
|
||||
ObInterruptChecker* checker1 = new ObInterruptChecker(true, 1);
|
||||
ObInterruptChecker* checker2 = new ObInterruptChecker(true, 1);
|
||||
ObInterruptChecker* checker3 = new ObInterruptChecker(true, 1);
|
||||
ret = manager->register_checker(checker0);
|
||||
EXPECT_EQ(OB_SUCCESS, ret);
|
||||
ret = manager->register_checker(checker1);
|
||||
EXPECT_EQ(OB_SUCCESS, ret);
|
||||
ret = manager->register_checker(checker2);
|
||||
EXPECT_EQ(OB_SUCCESS, ret);
|
||||
ret = manager->register_checker(checker3);
|
||||
EXPECT_EQ(OB_SUCCESS, ret);
|
||||
ret = manager->unregister_checker(checker0);
|
||||
EXPECT_EQ(OB_SUCCESS, ret);
|
||||
ret = manager->unregister_checker(checker1);
|
||||
EXPECT_EQ(OB_SUCCESS, ret);
|
||||
ret = manager->unregister_checker(checker2);
|
||||
EXPECT_EQ(OB_SUCCESS, ret);
|
||||
ret = manager->unregister_checker(checker3);
|
||||
EXPECT_EQ(OB_SUCCESS, ret);
|
||||
delete checker0;
|
||||
delete checker1;
|
||||
delete checker2;
|
||||
delete checker3;
|
||||
|
||||
// The following is in coroutine mode
|
||||
// Simulate regular usage scenarios
|
||||
// And test the use of several global functions
|
||||
|
||||
int total = -1;
|
||||
int fail = 0;
|
||||
int ready = 0;
|
||||
uint64_t n[40];
|
||||
|
||||
auto apool =
|
||||
cotesting::FlexPool{[&] {
|
||||
int idx = ATOMIC_AAF(&total, 1);
|
||||
uint64_t cid = CO_ID();
|
||||
n[idx] = cid;
|
||||
SET_INTERRUPTABLE(cid);
|
||||
/// The first 39 coroutines are waiting to be terminated
|
||||
if (idx < 39) {
|
||||
while (ready == 0) {
|
||||
this_routine::usleep(1000);
|
||||
}
|
||||
if (IS_INTERRUPTED()) {
|
||||
ASSERT_EQ(idx + 10, GET_INTERRUPT_CODE());
|
||||
return;
|
||||
}
|
||||
fail++;
|
||||
}
|
||||
/// The 40th coroutine is responsible for terminating them with three scenarios respectively
|
||||
else {
|
||||
for (int i = 0; i < 39; i++) {
|
||||
int k = i % 3;
|
||||
if (k == 0)
|
||||
manager->interrupt(n[i], i + 10);
|
||||
else if (k == 1)
|
||||
manager->interrupt(local, n[i], i + 10);
|
||||
else
|
||||
manager->interrupt(dst, n[i], i + 10);
|
||||
}
|
||||
ASSERT_EQ(false, IS_INTERRUPTED());
|
||||
ready++;
|
||||
}
|
||||
},
|
||||
4,
|
||||
10};
|
||||
apool.start(true);
|
||||
ASSERT_EQ(0, fail);
|
||||
|
||||
int xcnt = 0;
|
||||
// Test group interrupted
|
||||
SET_INTERRUPTABLE(10000);
|
||||
|
||||
auto bpool = cotesting::FlexPool{[&] {
|
||||
SET_INTERRUPTABLE(10000);
|
||||
ATOMIC_INC(&xcnt);
|
||||
while (!IS_INTERRUPTED()) {
|
||||
CO_YIELD();
|
||||
}
|
||||
EXPECT_EQ(1, GET_INTERRUPT_CODE());
|
||||
ATOMIC_DEC(&xcnt);
|
||||
},
|
||||
10,
|
||||
10};
|
||||
bpool.start(false);
|
||||
// Wait for all coroutines to execute set_interruptable
|
||||
while (xcnt != 100) {};
|
||||
|
||||
// Execute interrupt for taskid = 10000
|
||||
manager->interrupt(10000, 1);
|
||||
bpool.wait();
|
||||
// Coroutine interrupt count is cleared to 0
|
||||
ASSERT_EQ(0, xcnt);
|
||||
// The current thread also receives an interrupt signal
|
||||
ASSERT_EQ(true, IS_INTERRUPTED());
|
||||
ASSERT_EQ(1, GET_INTERRUPT_CODE());
|
||||
}
|
||||
|
||||
} // namespace common
|
||||
} // namespace oceanbase
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
oceanbase::common::ObLogger::get_logger().set_log_level("DEBUG");
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
Reference in New Issue
Block a user