From 130eabc369583883f1e820a3a2323d77f7e5d82f Mon Sep 17 00:00:00 2001 From: Megh Bhatt Date: Sat, 6 Jun 2015 00:50:35 -0700 Subject: [PATCH] Sandesh session delete happens in the sandesh client state machine context and the session is used to enqueue messages from client context and these can be executing concurrently causing the session to be deleted when being used from the client context. The fix is to enqueue the messages from the client to the state machine - EvSandeshSend and from the state machine context enqueue on to the session send queue. Enabled sandesh client state machine unit tests. Change-Id: I2d33c9348f71c99108bfc5fdfc2966b42231b214 Closes-Bug: #1460946 (cherry picked from commit 31994e0f072345f6c19e166ed2a0859cbbb80fc1) --- library/cpp/sandesh_client.cc | 12 +- library/cpp/sandesh_client.h | 6 +- library/cpp/sandesh_client_sm.cc | 41 ++- library/cpp/sandesh_client_sm.h | 3 + library/cpp/sandesh_client_sm_priv.h | 4 + library/cpp/test/SConscript | 11 +- library/cpp/test/sandesh_client_test.cc | 247 ++++++++---------- .../cpp/test/sandesh_state_machine_test.cc | 53 +--- library/cpp/test/sandesh_test_common.cc | 64 +++++ library/cpp/test/sandesh_test_common.h | 10 + 10 files changed, 228 insertions(+), 223 deletions(-) create mode 100644 library/cpp/test/sandesh_test_common.cc create mode 100644 library/cpp/test/sandesh_test_common.h diff --git a/library/cpp/sandesh_client.cc b/library/cpp/sandesh_client.cc index 0ec2a4b9..cb76feee 100644 --- a/library/cpp/sandesh_client.cc +++ b/library/cpp/sandesh_client.cc @@ -114,17 +114,7 @@ void SandeshClient::Shutdown() { } bool SandeshClient::SendSandesh(Sandesh *snh) { - if (!sm_->session() || sm_->session()->IsClosed()) { - return false; - } - SandeshClientSM::State state = sm_->state(); - if (state != SandeshClientSM::CLIENT_INIT && - state != SandeshClientSM::ESTABLISHED) { - return false; - } - // XXX No bounded work queue - sm_->session()->send_queue()->Enqueue(snh); - return true; + return sm_->SendSandesh(snh); } bool SandeshClient::ReceiveCtrlMsg(const std::string &msg, diff --git a/library/cpp/sandesh_client.h b/library/cpp/sandesh_client.h index 678f84ee..7949baf0 100644 --- a/library/cpp/sandesh_client.h +++ b/library/cpp/sandesh_client.h @@ -47,7 +47,7 @@ class SandeshClient : public TcpServer, public SandeshClientSM::Mgr { void Initiate(); void Shutdown(); - SandeshSession *CreateSMSession( + virtual SandeshSession *CreateSMSession( TcpSession::EventObserver eocb, SandeshReceiveMsgCb rmcb, TcpServer::Endpoint ep); @@ -82,6 +82,10 @@ class SandeshClient : public TcpServer, public SandeshClientSM::Mgr { return sm_->session(); } + SandeshClientSM* state_machine() const { + return sm_.get(); + } + void SetSessionWaterMarkInfo(Sandesh::QueueWaterMarkInfo &scwm); void ResetSessionWaterMarkInfo(); void GetSessionWaterMarkInfo( diff --git a/library/cpp/sandesh_client_sm.cc b/library/cpp/sandesh_client_sm.cc index df739eb1..27a7375c 100644 --- a/library/cpp/sandesh_client_sm.cc +++ b/library/cpp/sandesh_client_sm.cc @@ -491,14 +491,21 @@ struct ClientInit : public sc::state { sc::result react(const EvSandeshSend &event) { SandeshClientSMImpl *state_machine = &context(); - SM_LOG(DEBUG, state_machine->StateName() << " : " << event.Name() << " : " << event.snh->Name()); - if (dynamic_cast(event.snh)) { - SM_LOG(INFO, "Received UVE message in wrong state : " << event.snh->Name()); - event.snh->Release(); + Sandesh *snh(event.snh); + SM_LOG(DEBUG, state_machine->StateName() << " : " << event.Name() << + " : " << snh->Name()); + if (dynamic_cast(snh)) { + if (snh->IsLoggingDroppedAllowed()) { + SANDESH_LOG(ERROR, "SANDESH: Send FAILED: " << + snh->ToString()); + } + Sandesh::UpdateSandeshStats(snh->Name(), 0, true, true); + SM_LOG(INFO, "Received UVE message in wrong state : " << snh->Name()); + snh->Release(); return discard_event(); } - if (!state_machine->send_session(event.snh)) { - SM_LOG(ERROR, "Could not EnQ Sandesh " << event.snh->Name()); + if (!state_machine->send_session(snh)) { + SM_LOG(INFO, "Could not EnQ Sandesh :" << snh->Name()); // If Enqueue encounters an error, it will release the Sandesh } return discard_event(); @@ -634,7 +641,7 @@ struct Established : public sc::state { void SandeshClientSMImpl::SetAdminState(bool down) { if (down) { - Enqueue(scm::EvStop(false)); + Enqueue(scm::EvStop()); } else { reset_idle_hold_time(); // On fresh restart of state machine, all previous state should be reset @@ -659,8 +666,14 @@ void SandeshClientSMImpl::OnIdle(const Ev &event) { template void SandeshClientSMImpl::ReleaseSandesh(const Ev &event) { - SM_LOG(DEBUG, "Wrong state: " << StateName() << " for event: " << event.Name()); - event.snh->Release(); + Sandesh *snh(event.snh); + if (snh->IsLoggingDroppedAllowed()) { + SANDESH_LOG(ERROR, "SANDESH: Send FAILED: " << snh->ToString()); + } + Sandesh::UpdateSandeshStats(snh->Name(), 0, true, true); + SM_LOG(DEBUG, "Wrong state: " << StateName() << " for event: " << + event.Name() << " message: " << snh->Name()); + snh->Release(); } template @@ -766,6 +779,11 @@ bool SandeshClientSMImpl::SendSandeshUVE(Sandesh * snh) { return true; } +bool SandeshClientSMImpl::SendSandesh(Sandesh * snh) { + Enqueue(scm::EvSandeshSend(snh)); + return true; +} + void SandeshClientSMImpl::OnMessage(SandeshSession *session, const std::string &msg) { // Demux based on Sandesh message type @@ -796,6 +814,11 @@ static const std::string state_names[] = { "Established", }; +const string &SandeshClientSMImpl::StateName( + SandeshClientSM::State state) const { + return state_names[state]; +} + const string &SandeshClientSMImpl::StateName() const { return state_names[state_]; } diff --git a/library/cpp/sandesh_client_sm.h b/library/cpp/sandesh_client_sm.h index 94a78844..21fb717f 100644 --- a/library/cpp/sandesh_client_sm.h +++ b/library/cpp/sandesh_client_sm.h @@ -80,6 +80,9 @@ class SandeshClientSM { // This function is used to send UVE sandesh's to the server virtual bool SendSandeshUVE(Sandesh* snh) = 0; + // This function is used to send sandesh's to the server + virtual bool SendSandesh(Sandesh* snh) = 0; + virtual ~SandeshClientSM() {} protected: diff --git a/library/cpp/sandesh_client_sm_priv.h b/library/cpp/sandesh_client_sm_priv.h index 0df579e1..613cc420 100644 --- a/library/cpp/sandesh_client_sm_priv.h +++ b/library/cpp/sandesh_client_sm_priv.h @@ -63,6 +63,7 @@ class SandeshClientSMImpl : public SandeshClientSM, void GetCandidates(TcpServer::Endpoint& active, TcpServer::Endpoint &backup) const; bool SendSandeshUVE(Sandesh* snh); + bool SendSandesh(Sandesh* snh); void EnqueDelSession(SandeshSession * session); // Feed session events into the state machine. @@ -95,6 +96,7 @@ class SandeshClientSMImpl : public SandeshClientSM, int GetConnectTime() const; const std::string &StateName() const; + const std::string &StateName(SandeshClientSM::State state) const; const std::string &LastStateName() const; void set_state(State state) { @@ -178,6 +180,8 @@ class SandeshClientSMImpl : public SandeshClientSM, std::string generator_key_; SandeshEventStatistics event_stats_; + friend class SandeshClientStateMachineTest; + DISALLOW_COPY_AND_ASSIGN(SandeshClientSMImpl); }; diff --git a/library/cpp/test/SConscript b/library/cpp/test/SConscript index 0a3750b9..29e65f28 100644 --- a/library/cpp/test/SConscript +++ b/library/cpp/test/SConscript @@ -122,17 +122,18 @@ sandesh_http_test = env.UnitTest('sandesh_http_test', env.Alias('src/sandesh:sandesh_http_test', sandesh_http_test) env.Requires(sandesh_http_test, '#/build/include/libxml2/libxml/tree.h') +sandesh_test_common_obj = env.Object('sandesh_test_common.cc') sandesh_state_machine_test = env.UnitTest('sandesh_state_machine_test', - ['sandesh_state_machine_test.cc'] + ['sandesh_state_machine_test.cc'] + + sandesh_test_common_obj ) env.Alias('src/sandesh:sandesh_state_machine_test', sandesh_state_machine_test) -''' sandesh_client_test = env.UnitTest('sandesh_client_test', - ['sandesh_client_test.cc'] + ['sandesh_client_test.cc'] + + sandesh_test_common_obj ) env.Alias('src/sandesh:sandesh_client_test', sandesh_client_test) -''' test_suite = [sandesh_message_test, sandesh_rw_test, @@ -141,7 +142,7 @@ test_suite = [sandesh_message_test, sandesh_http_test, sandesh_state_machine_test, sandesh_perf_test, -# sandesh_client_test, + sandesh_client_test, ] test = env.TestSuite('sandesh-test', test_suite) diff --git a/library/cpp/test/sandesh_client_test.cc b/library/cpp/test/sandesh_client_test.cc index e63a9d89..756a57cf 100644 --- a/library/cpp/test/sandesh_client_test.cc +++ b/library/cpp/test/sandesh_client_test.cc @@ -16,14 +16,13 @@ #include "io/event_manager.h" #include "testing/gunit.h" -#include -#include #include #include -#include #include -#include "sandesh_factory.h" -#include "sandesh_client.h" +#include +#include +#include "sandesh_client_sm_priv.h" +#include "sandesh_test_common.h" using namespace std; using namespace boost::assign; @@ -32,6 +31,8 @@ using boost::system::error_code; using namespace contrail::sandesh::protocol; using namespace contrail::sandesh::transport; +typedef boost::asio::ip::tcp::endpoint Endpoint; + class SandeshSessionMock : public SandeshSession { public: enum State { @@ -46,7 +47,11 @@ class SandeshSessionMock : public SandeshSession { }; SandeshSessionMock(TcpServer *server, State state, Direction direction) - : SandeshSession(server, NULL), state_(state), direction_(direction) { + : SandeshSession(server, NULL, Task::kTaskInstanceAny, + TaskScheduler::GetInstance()->GetTaskId("sandesh::Test::ClientSM"), + TaskScheduler::GetInstance()->GetTaskId("io::ReaderTask")), + state_(state), + direction_(direction) { } ~SandeshSessionMock() { @@ -57,6 +62,11 @@ class SandeshSessionMock : public SandeshSession { return true; } + void Close() { + state_ = SandeshSessionMock::CLOSE; + SandeshSession::Close(); + } + virtual bool Connected(Endpoint remote) { state_ = SandeshSessionMock::CLIENT_INIT; EventObserver obs = observer(); @@ -66,11 +76,6 @@ class SandeshSessionMock : public SandeshSession { return true; } - void Close() { - state_ = SandeshSessionMock::CLOSE; - SandeshSession::Close(); - } - State state() { return state_; } Direction direction() { return direction_; } @@ -79,7 +84,6 @@ class SandeshSessionMock : public SandeshSession { Direction direction_; }; - class SandeshClientMock : public SandeshClient { public: SandeshClientMock(EventManager *evm, Endpoint dummy) : @@ -95,6 +99,17 @@ class SandeshClientMock : public SandeshClient { virtual void Connect(TcpSession *session, Endpoint remote) { } + virtual SandeshSession *CreateSMSession( + TcpSession::EventObserver eocb, + SandeshReceiveMsgCb rmcb, + TcpServer::Endpoint ep) { + SandeshSession *session(dynamic_cast( + CreateSession())); + session->SetReceiveMsgCb(rmcb); + session->set_observer(eocb); + return session; + } + virtual TcpSession *CreateSession() { if (session_) { assert(!old_session_); @@ -121,7 +136,7 @@ class SandeshClientMock : public SandeshClient { virtual bool ReceiveSandeshMsg(SandeshSession *session, const string& cmsg, const string& message_type, - const SandeshHeader& header, uint32_t xml_offset) { + const SandeshHeader& header, uint32_t xml_offset) { return true; } @@ -132,57 +147,14 @@ class SandeshClientMock : public SandeshClient { SandeshSessionMock *old_session_; }; -const std::string FakeMessageSandeshBegin(""); - -static void CreateFakeMessage(uint8_t *data, size_t length) { - size_t offset = 0; - SandeshHeader header; - // Populate the header - header.set_Namespace("Test"); - header.set_Timestamp(123456); - header.set_Module("SandeshStateMachineTest"); - header.set_Source("TestMachine"); - header.set_Context(""); - header.set_SequenceNum(0); - header.set_VersionSig(0); - header.set_Type(SandeshType::SYSTEM); - header.set_Hints(0); - header.set_Level(SandeshLevel::SYS_DEBUG); - header.set_Category("SSM"); - boost::shared_ptr btrans = - boost::shared_ptr( - new TMemoryBuffer(512)); - boost::shared_ptr prot = - boost::shared_ptr( - new TXMLProtocol(btrans)); - // Write the sandesh header - int ret = header.write(prot); - EXPECT_GT(ret, 0); - EXPECT_GT(length, offset + ret); - // Get the buffer - uint8_t *hbuffer; - uint32_t hlen; - btrans->getBuffer(&hbuffer, &hlen); - EXPECT_EQ(hlen, ret); - memcpy(data + offset, hbuffer, hlen); - offset += hlen; - EXPECT_GT(length, offset + FakeMessageSandeshBegin.size()); - memcpy(data + offset, FakeMessageSandeshBegin.c_str(), - FakeMessageSandeshBegin.size()); - offset += FakeMessageSandeshBegin.size(); - memset(data + offset, '0', length - offset); - offset += length - offset; - EXPECT_EQ(offset, length); -} - - class SandeshClientStateMachineTest : public ::testing::Test { protected: SandeshClientStateMachineTest() : - client_(new SandeshClientMock((&evm_), dummy_)), - timer_(TimerManager::CreateTimer(*evm_.io_service(), "Dummy timer")) { + client_(new SandeshClientMock((&evm_), Endpoint())), + timer_(TimerManager::CreateTimer(*evm_.io_service(), "Dummy timer")), + sm_(dynamic_cast(client_->state_machine())) { task_util::WaitForIdle(); - client_->set_idle_hold_time(1); + sm_->set_idle_hold_time(1); } ~SandeshClientStateMachineTest() { @@ -207,11 +179,11 @@ class SandeshClientStateMachineTest : public ::testing::Test { return false; } - void RunToState(scm::SsmState state) { + void RunToState(SandeshClientSM::State state) { timer_->Start(15000, boost::bind(&SandeshClientStateMachineTest::DummyTimerHandler, this)); task_util::WaitForIdle(); - for (int count = 0; count < 100 && client_->get_state() != state; count++) { + for (int count = 0; count < 100 && sm_->get_state() != state; count++) { evm_.RunOnce(); task_util::WaitForIdle(); } @@ -219,24 +191,24 @@ class SandeshClientStateMachineTest : public ::testing::Test { VerifyState(state); } - void GetToState(scm::SsmState state) { + void GetToState(SandeshClientSM::State state) { switch (state) { - case scm::IDLE: { + case SandeshClientSM::IDLE: { EvAdminDown(); VerifyState(state); break; } - case scm::CONNECT: { - GetToState(scm::IDLE); + case SandeshClientSM::CONNECT: { + GetToState(SandeshClientSM::IDLE); EvAdminUp(); RunToState(state); break; } - case scm::CLIENT_INIT: { - GetToState(scm::CONNECT); + case SandeshClientSM::CLIENT_INIT: { + GetToState(SandeshClientSM::CONNECT); Endpoint endpoint; client_->session()->Connected(endpoint); - VerifyState(scm::CLIENT_INIT); + VerifyState(SandeshClientSM::CLIENT_INIT); break; } default: { @@ -246,25 +218,25 @@ class SandeshClientStateMachineTest : public ::testing::Test { } } - void VerifyState(scm::SsmState state) { + void VerifyState(SandeshClientSM::State state) { task_util::WaitForIdle(); TaskScheduler::GetInstance()->Stop(); LOG(DEBUG, "VerifyState " << state); - EXPECT_EQ(state, client_->get_state()); + EXPECT_EQ(state, sm_->get_state()); switch (state) { - case scm::IDLE: + case SandeshClientSM::IDLE: EXPECT_TRUE(!ConnectTimerRunning()); EXPECT_TRUE(client_->session() == NULL); break; - case scm::CONNECT: + case SandeshClientSM::CONNECT: EXPECT_TRUE(ConnectTimerRunning()); EXPECT_TRUE(!IdleHoldTimerRunning()); EXPECT_TRUE(client_->session() != NULL); break; - case scm::CLIENT_INIT: - EXPECT_TRUE(!ConnectTimerRunning()); + case SandeshClientSM::CLIENT_INIT: + EXPECT_TRUE(ConnectTimerRunning()); EXPECT_TRUE(!IdleHoldTimerRunning()); EXPECT_TRUE(client_->session() != NULL); break; @@ -289,50 +261,44 @@ class SandeshClientStateMachineTest : public ::testing::Test { return session; } - void EvStart() { - client_->Initiate(); - } - void EvStop() { - client_->Shutdown(); - } void EvAdminUp() { - client_->SetAdminState(false); - client_->set_idle_hold_time(1); + sm_->SetAdminState(false); + sm_->set_idle_hold_time(1); } void EvAdminDown() { - client_->SetAdminState(true); - client_->set_idle_hold_time(1); + sm_->SetAdminState(true); + sm_->set_idle_hold_time(1); } void EvConnectTimerExpired() { - client_->FireConnectTimer(); + sm_->FireConnectTimer(); } void EvTcpConnected() { - client_->OnSessionEvent(client_->session(), + sm_->OnSessionEvent(client_->session(), TcpSession::CONNECT_COMPLETE); } void EvTcpConnectFail() { - client_->OnSessionEvent(client_->session(), + sm_->OnSessionEvent(client_->session(), TcpSession::CONNECT_FAILED); } void EvTcpClose(SandeshSessionMock *session = NULL) { if (!session) session = client_->session(); - client_->OnSessionEvent(session, TcpSession::CLOSE); + sm_->OnSessionEvent(session, TcpSession::CLOSE); } void EvSandeshMessageRecv(SandeshSessionMock *session = NULL) { session = GetSession(session); uint8_t msg[1024]; CreateFakeMessage(msg, sizeof(msg)); string xml((const char *)msg, sizeof(msg)); - client_->OnMessage(session, xml); + sm_->OnMessage(session, xml); } - bool IdleHoldTimerRunning() { return client_->idle_hold_timer_->running(); } - bool ConnectTimerRunning() { return client_->connect_timer_->running(); } + bool IdleHoldTimerRunning() { return sm_->IdleHoldTimerRunning(); } + bool ConnectTimerRunning() { return sm_->ConnectTimerRunning(); } EventManager evm_; SandeshClientMock *client_; + SandeshClientSMImpl *sm_; Timer *timer_; - Endpoint dummy_; }; typedef boost::function EvGen; @@ -343,7 +309,7 @@ struct EvGenComp { TEST_F(SandeshClientStateMachineTest, Matrix) { boost::asio::io_service::work work(*evm_.io_service()); - typedef std::map Transitions; + typedef std::map Transitions; #define CLIENT_SSM_TRANSITION(F, E) \ ((EvGen) boost::bind(&SandeshClientStateMachineTest_Matrix_Test::F, this), E) @@ -352,36 +318,37 @@ TEST_F(SandeshClientStateMachineTest, Matrix) { (SandeshSessionMock *) NULL), E) Transitions idle = map_list_of - CLIENT_SSM_TRANSITION(EvAdminUp, scm::CONNECT); + CLIENT_SSM_TRANSITION(EvAdminUp, SandeshClientSM::CONNECT); Transitions none = map_list_of - CLIENT_SSM_TRANSITION(EvStop, scm::IDLE); + CLIENT_SSM_TRANSITION(EvAdminDown, SandeshClientSM::IDLE); Transitions connect = map_list_of - CLIENT_SSM_TRANSITION(EvStop, scm::IDLE) - CLIENT_SSM_TRANSITION(EvConnectTimerExpired, scm::CONNECT) - CLIENT_SSM_TRANSITION(EvTcpConnected, scm::CLIENT_INIT) - CLIENT_SSM_TRANSITION(EvTcpConnectFail, scm::IDLE) - CLIENT_SSM_TRANSITION2(EvTcpClose, scm::CONNECT); + CLIENT_SSM_TRANSITION(EvAdminDown, SandeshClientSM::IDLE) + CLIENT_SSM_TRANSITION(EvConnectTimerExpired, SandeshClientSM::IDLE) + CLIENT_SSM_TRANSITION(EvTcpConnected, SandeshClientSM::CLIENT_INIT) + CLIENT_SSM_TRANSITION(EvTcpConnectFail, SandeshClientSM::IDLE) + CLIENT_SSM_TRANSITION2(EvTcpClose, SandeshClientSM::IDLE); Transitions client_init = map_list_of - CLIENT_SSM_TRANSITION2(EvTcpClose, scm::CONNECT) - CLIENT_SSM_TRANSITION2(EvSandeshMessageRecv, scm::CLIENT_INIT); + CLIENT_SSM_TRANSITION2(EvTcpClose, SandeshClientSM::IDLE) + CLIENT_SSM_TRANSITION2(EvSandeshMessageRecv, SandeshClientSM::CLIENT_INIT); Transitions matrix[] = - { idle, connect, none, client_init }; + { idle, none, connect, client_init }; - for (int k = scm::IDLE; k <= scm::CLIENT_INIT; k++) { - scm::SsmState i = static_cast (k); - // Ignore ESTABLISHED in SandeshClientStateMachine - if (i == scm::ESTABLISHED) { + for (int k = SandeshClientSM::IDLE; k <= SandeshClientSM::CLIENT_INIT; k++) { + SandeshClientSM::State i = static_cast(k); + // Ignore DISCONNECT and ESTABLISHED in SandeshClientSM + if (i == SandeshClientSM::ESTABLISHED || i == SandeshClientSM::DISCONNECT) { continue; } int count = 0; for (Transitions::iterator j = matrix[i].begin(); j != matrix[i].end(); j++) { - LOG(DEBUG, "Starting test " << count++ << " in state " << i - << " expecting " << j->second << " *********************"); + LOG(DEBUG, "Starting test " << count++ << " in state " << sm_->StateName(i) + << " expecting " << sm_->StateName(j->second)<< + " *********************"); GetToState(i); j->first(); RunToState(j->second); @@ -389,10 +356,9 @@ TEST_F(SandeshClientStateMachineTest, Matrix) { } } - class SandeshClientStateMachineConnectTest : public SandeshClientStateMachineTest { virtual void SetUp() { - GetToState(scm::CONNECT); + GetToState(SandeshClientSM::CONNECT); } virtual void TearDown() { @@ -401,36 +367,37 @@ class SandeshClientStateMachineConnectTest : public SandeshClientStateMachineTes // Old State: Connect // Event: EvTcpConnected -// New State: Established -// Timers: None should be running. +// New State: ClientInit +// Timers: Connect timer must be running again. // Messages: None. TEST_F(SandeshClientStateMachineConnectTest, TcpConnected) { EvTcpConnected(); - VerifyState(scm::CLIENT_INIT); - EXPECT_TRUE(!ConnectTimerRunning()); + VerifyState(SandeshClientSM::CLIENT_INIT); + EXPECT_TRUE(ConnectTimerRunning()); EXPECT_TRUE(client_->session() != NULL); } // Old State: Connect // Event: EvConnectTimerExpired -// New State: Active -// Timers: Connect timer must be running again. +// New State: Idle. +// Timers: Idle hold timer must be running. Connect timer should not be running. // Messages: None. TEST_F(SandeshClientStateMachineConnectTest, ConnectTimerExpired) { EvConnectTimerExpired(); - VerifyState(scm::CONNECT); - EXPECT_TRUE(ConnectTimerRunning()); - EXPECT_TRUE(client_->session() != NULL); + VerifyState(SandeshClientSM::IDLE); + EXPECT_TRUE(!ConnectTimerRunning()); + EXPECT_TRUE(IdleHoldTimerRunning()); + EXPECT_TRUE(client_->session() == NULL); } // Old State: Connect // Event: EvTcpConnectFail -// New State: Idle +// New State: Idle. // Timers: Idle hold timer must be running. Connect timer should not be running. // Messages: None. TEST_F(SandeshClientStateMachineConnectTest, TcpConnectFail) { EvTcpConnectFail(); - VerifyState(scm::IDLE); + VerifyState(SandeshClientSM::IDLE); EXPECT_TRUE(!ConnectTimerRunning()); EXPECT_TRUE(IdleHoldTimerRunning()); EXPECT_TRUE(client_->session() == NULL); @@ -438,7 +405,7 @@ TEST_F(SandeshClientStateMachineConnectTest, TcpConnectFail) { // Old State: Connect // Event: EvTcpConnected + EvConnectTimerExpired -// New State: ClientInit +// New State: Idle // Messages: None. // Other: The Connect timer has expired before it can be cancelled while // processing EvTcpConnected. @@ -447,15 +414,15 @@ TEST_F(SandeshClientStateMachineConnectTest, TcpConnectedThenConnectTimerExpired EvTcpConnected(); EvConnectTimerExpired(); TaskScheduler::GetInstance()->Start(); - VerifyState(scm::CLIENT_INIT); - EXPECT_TRUE(client_->session() != NULL); + VerifyState(SandeshClientSM::IDLE); + EXPECT_TRUE(client_->session() == NULL); EXPECT_TRUE(!ConnectTimerRunning()); - EXPECT_TRUE(!IdleHoldTimerRunning()); + EXPECT_TRUE(IdleHoldTimerRunning()); } // Old State: Connect // Event: EvConnectTimerExpired + EvTcpConnected -// New State: Connect +// New State: Idle // Messages: None. // Other: The Connect timer expired before we see EvTcpConnected, thus // the session would already have been deleted when we process @@ -465,16 +432,15 @@ TEST_F(SandeshClientStateMachineConnectTest, ConnectTimerExpiredThenTcpConnected EvConnectTimerExpired(); EvTcpConnected(); TaskScheduler::GetInstance()->Start(); - VerifyState(scm::CONNECT); - EXPECT_TRUE(client_->session() != NULL); - EXPECT_TRUE(ConnectTimerRunning()); - EXPECT_TRUE(!IdleHoldTimerRunning()); + VerifyState(SandeshClientSM::IDLE); + EXPECT_TRUE(client_->session() == NULL); + EXPECT_TRUE(!ConnectTimerRunning()); + EXPECT_TRUE(IdleHoldTimerRunning()); } -#if 0 class SandeshClientStateMachineEstablishedTest : public SandeshClientStateMachineTest { virtual void SetUp() { - GetToState(scm::CLIENT_INIT); + GetToState(SandeshClientSM::CLIENT_INIT); VerifyDirection(SandeshSessionMock::ACTIVE); } @@ -486,19 +452,10 @@ class SandeshClientStateMachineEstablishedTest : public SandeshClientStateMachin // Event: EvTcpClose // New State: Idle TEST_F(SandeshClientStateMachineEstablishedTest, TcpClose) { - TaskScheduler::GetInstance()->Stop(); EvTcpClose(); - TcpSession *session = client_->session(); - TaskScheduler::GetInstance()->Start(); - TASK_UTIL_EXPECT_EQ(true, !session->IsEstablished(), - "Wait for session to close"); - Endpoint endpoint; - TASK_UTIL_EXPECT_EQ(false, session->Connected(endpoint), - "Wait for session to close"); - VerifyState(scm::ESTABLISHED); - VerifyDirection(SandeshSessionMock::ACTIVE); + VerifyState(SandeshClientSM::IDLE); + EXPECT_TRUE(sm_->session() == NULL); } -#endif int main(int argc, char **argv) { LoggingInit(); diff --git a/library/cpp/test/sandesh_state_machine_test.cc b/library/cpp/test/sandesh_state_machine_test.cc index 3d4525f8..b427d11b 100644 --- a/library/cpp/test/sandesh_state_machine_test.cc +++ b/library/cpp/test/sandesh_state_machine_test.cc @@ -17,22 +17,18 @@ #include "io/event_manager.h" #include "testing/gunit.h" -#include -#include #include #include #include #include #include "sandesh_connection.h" -#include "sandesh_client.h" #include "sandesh_state_machine.h" +#include "sandesh_test_common.h" using namespace std; using namespace boost::assign; using namespace boost::posix_time; using boost::system::error_code; -using namespace contrail::sandesh::protocol; -using namespace contrail::sandesh::transport; typedef boost::asio::ip::tcp::endpoint Endpoint; @@ -134,53 +130,6 @@ class SandeshServerMock : public SandeshServer { SandeshSessionMock *old_session_; }; -const std::string FakeMessageSandeshBegin(""); -const std::string FakeMessageSandeshEnd(""); - -static void CreateFakeMessage(uint8_t *data, size_t length) { - size_t offset = 0; - SandeshHeader header; - // Populate the header - header.set_Namespace("Test"); - header.set_Timestamp(123456); - header.set_Module("SandeshStateMachineTest"); - header.set_Source("TestMachine"); - header.set_Context(""); - header.set_SequenceNum(0); - header.set_VersionSig(0); - header.set_Type(SandeshType::SYSTEM); - header.set_Hints(0); - header.set_Level(SandeshLevel::SYS_DEBUG); - header.set_Category("SSM"); - boost::shared_ptr btrans = - boost::shared_ptr( - new TMemoryBuffer(512)); - boost::shared_ptr prot = - boost::shared_ptr( - new TXMLProtocol(btrans)); - // Write the sandesh header - int ret = header.write(prot); - EXPECT_GT(ret, 0); - EXPECT_GT(length, offset + ret); - // Get the buffer - uint8_t *hbuffer; - uint32_t hlen; - btrans->getBuffer(&hbuffer, &hlen); - EXPECT_EQ(hlen, ret); - memcpy(data + offset, hbuffer, hlen); - offset += hlen; - EXPECT_GT(length, offset + FakeMessageSandeshBegin.size()); - memcpy(data + offset, FakeMessageSandeshBegin.c_str(), - FakeMessageSandeshBegin.size()); - offset += FakeMessageSandeshBegin.size(); - memset(data + offset, '0', length - offset - FakeMessageSandeshEnd.size()); - offset += length - offset - FakeMessageSandeshEnd.size(); - memcpy(data + offset, FakeMessageSandeshEnd.c_str(), - FakeMessageSandeshEnd.size()); - offset += FakeMessageSandeshEnd.size(); - EXPECT_EQ(offset, length); -} - class SandeshServerStateMachineTest : public ::testing::Test { protected: SandeshServerStateMachineTest() : diff --git a/library/cpp/test/sandesh_test_common.cc b/library/cpp/test/sandesh_test_common.cc new file mode 100644 index 00000000..86408efb --- /dev/null +++ b/library/cpp/test/sandesh_test_common.cc @@ -0,0 +1,64 @@ +// +// Copyright (c) 2015 Juniper Networks, Inc. All rights reserved. +// + +// +// sandesh_test_common.cc +// + +#include "testing/gunit.h" + +#include +#include +#include +#include + +using namespace contrail::sandesh::protocol; +using namespace contrail::sandesh::transport; + +static const std::string FakeMessageSandeshBegin(""); +static const std::string FakeMessageSandeshEnd(""); + +void CreateFakeMessage(uint8_t *data, size_t length) { + size_t offset = 0; + SandeshHeader header; + // Populate the header + header.set_Namespace("Test"); + header.set_Timestamp(123456); + header.set_Module("SandeshStateMachineTest"); + header.set_Source("TestMachine"); + header.set_Context(""); + header.set_SequenceNum(0); + header.set_VersionSig(0); + header.set_Type(SandeshType::SYSTEM); + header.set_Hints(0); + header.set_Level(SandeshLevel::SYS_DEBUG); + header.set_Category("SSM"); + boost::shared_ptr btrans = + boost::shared_ptr( + new TMemoryBuffer(512)); + boost::shared_ptr prot = + boost::shared_ptr( + new TXMLProtocol(btrans)); + // Write the sandesh header + int ret = header.write(prot); + EXPECT_GT(ret, 0); + EXPECT_GT(length, offset + ret); + // Get the buffer + uint8_t *hbuffer; + uint32_t hlen; + btrans->getBuffer(&hbuffer, &hlen); + EXPECT_EQ(hlen, ret); + memcpy(data + offset, hbuffer, hlen); + offset += hlen; + EXPECT_GT(length, offset + FakeMessageSandeshBegin.size()); + memcpy(data + offset, FakeMessageSandeshBegin.c_str(), + FakeMessageSandeshBegin.size()); + offset += FakeMessageSandeshBegin.size(); + memset(data + offset, '0', length - offset - FakeMessageSandeshEnd.size()); + offset += length - offset - FakeMessageSandeshEnd.size(); + memcpy(data + offset, FakeMessageSandeshEnd.c_str(), + FakeMessageSandeshEnd.size()); + offset += FakeMessageSandeshEnd.size(); + EXPECT_EQ(offset, length); +} diff --git a/library/cpp/test/sandesh_test_common.h b/library/cpp/test/sandesh_test_common.h new file mode 100644 index 00000000..8a7802db --- /dev/null +++ b/library/cpp/test/sandesh_test_common.h @@ -0,0 +1,10 @@ +// +// Copyright (c) 2015 Juniper Networks, Inc. All rights reserved. +// + +#ifndef SANDESH_LIBRARY_CPP_TEST_SANDESH_TEST_COMMON_H_ +#define SANDESH_LIBRARY_CPP_TEST_SANDESH_TEST_COMMON_H_ + +void CreateFakeMessage(uint8_t *data, size_t length); + +#endif // SANDESH_LIBRARY_CPP_TEST_SANDESH_TEST_COMMON_H_