Skip to content

Commit b5539f7

Browse files
rkavitha-hclKAVITHA RAMALINGAM
authored and
KAVITHA RAMALINGAM
committedDec 13, 2024
gNOI Cold Reboot - Integrated tests
1 parent 68416e9 commit b5539f7

File tree

6 files changed

+688
-66
lines changed

6 files changed

+688
-66
lines changed
 

‎src/sonic-framework/rebootbackend/gnoi_reboot_dbus.h

-65
This file was deleted.

‎src/sonic-framework/rebootbackend/rebootbe.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
#include "rebootbe.h"
2-
32
#include <google/protobuf/util/json_util.h>
43
#include <unistd.h>
54

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#pragma once
2+
#include <gmock/gmock.h>
3+
4+
#include "reboot_interfaces.h"
5+
#include "selectableevent.h"
6+
#include "system/system.pb.h"
7+
8+
namespace rebootbackend {
9+
10+
class MockDbusInterface : public DbusInterface {
11+
public:
12+
MOCK_METHOD(DbusInterface::DbusResponse, Reboot, (const std::string &),
13+
(override));
14+
MOCK_METHOD(DbusInterface::DbusResponse, RebootStatus, (const std::string &),
15+
(override));
16+
};
17+
18+
} // namespace rebootbackend
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
#include "reboot_thread.h"
2+
3+
#include <gmock/gmock.h>
4+
#include <google/protobuf/util/json_util.h>
5+
#include <gtest/gtest.h>
6+
#include <unistd.h>
7+
8+
#include <string>
9+
#include <thread>
10+
#include <vector>
11+
12+
#include "mock_reboot_interfaces.h"
13+
#include "reboot_common.h"
14+
#include "reboot_interfaces.h"
15+
#include "select.h"
16+
#include "selectableevent.h"
17+
#include "status_code_util.h"
18+
#include "system/system.pb.h"
19+
#include "timestamp.h"
20+
21+
namespace rebootbackend {
22+
23+
24+
namespace gpu = ::google::protobuf::util;
25+
using Progress = ::rebootbackend::RebootThread::Progress;
26+
using RebootThread = ::rebootbackend::RebootThread;
27+
using ::testing::_;
28+
using ::testing::ExplainMatchResult;
29+
using ::testing::HasSubstr;
30+
using ::testing::NiceMock;
31+
using ::testing::Return;
32+
using ::testing::StrEq;
33+
using ::testing::StrictMock;
34+
35+
MATCHER_P2(IsStatus, status, message, "") {
36+
return (arg.status().status() == status &&
37+
ExplainMatchResult(message, arg.status().message(), result_listener));
38+
}
39+
40+
class RebootStatusTest : public ::testing::Test {
41+
protected:
42+
RebootStatusTest() : m_status() {}
43+
ThreadStatus m_status;
44+
};
45+
46+
TEST_F(RebootStatusTest, TestInit) {
47+
gnoi::system::RebootStatusResponse response = m_status.get_response();
48+
49+
EXPECT_FALSE(response.active());
50+
EXPECT_THAT(response.reason(), StrEq(""));
51+
EXPECT_EQ(response.count(), 0);
52+
EXPECT_EQ(response.method(), gnoi::system::RebootMethod::UNKNOWN);
53+
EXPECT_EQ(
54+
response.status().status(),
55+
gnoi::system::RebootStatus_Status::RebootStatus_Status_STATUS_UNKNOWN);
56+
EXPECT_THAT(response.status().message(), StrEq(""));
57+
58+
EXPECT_FALSE(m_status.get_active());
59+
}
60+
61+
TEST_F(RebootStatusTest, TestGetStatus) {
62+
std::chrono::nanoseconds curr_ns =
63+
std::chrono::high_resolution_clock::now().time_since_epoch();
64+
65+
m_status.set_start_status(gnoi::system::RebootMethod::COLD, "reboot because");
66+
67+
gnoi::system::RebootStatusResponse response = m_status.get_response();
68+
EXPECT_EQ(
69+
response.status().status(),
70+
gnoi::system::RebootStatus_Status::RebootStatus_Status_STATUS_UNKNOWN);
71+
72+
m_status.set_completed_status(
73+
gnoi::system::RebootStatus_Status::RebootStatus_Status_STATUS_SUCCESS,
74+
"anything");
75+
76+
response = m_status.get_response();
77+
78+
// message should be empty while reboot is active
79+
EXPECT_THAT(response.status().message(), StrEq(""));
80+
81+
uint64_t reboot_ns = response.when();
82+
EXPECT_TRUE(reboot_ns > (uint64_t)curr_ns.count());
83+
84+
m_status.set_inactive();
85+
response = m_status.get_response();
86+
EXPECT_THAT(response.status().message(), StrEq("anything"));
87+
EXPECT_EQ(
88+
response.status().status(),
89+
gnoi::system::RebootStatus_Status::RebootStatus_Status_STATUS_SUCCESS);
90+
EXPECT_EQ(0, response.when());
91+
}
92+
93+
class RebootThreadTest : public ::testing::Test {
94+
protected:
95+
RebootThreadTest()
96+
: m_dbus_interface(),
97+
m_db("STATE_DB", 0),
98+
m_config_db("CONFIG_DB", 0),
99+
m_reboot_thread(m_dbus_interface, m_finished) {
100+
sigterm_requested = false;
101+
}
102+
103+
void overwrite_reboot_timeout(uint32_t timeout_seconds) {
104+
m_reboot_thread.m_reboot_timeout = timeout_seconds;
105+
}
106+
107+
gnoi::system::RebootStatusResponse get_response(void) {
108+
return m_reboot_thread.m_status.get_response();
109+
}
110+
111+
void set_start_status(const gnoi::system::RebootMethod &method,
112+
const std::string &reason) {
113+
return m_reboot_thread.m_status.set_start_status(method, reason);
114+
}
115+
116+
void set_completed_status(const gnoi::system::RebootStatus_Status &status,
117+
const std::string &message) {
118+
return m_reboot_thread.m_status.set_completed_status(status, message);
119+
}
120+
121+
void force_inactive(void) { return m_reboot_thread.m_status.set_inactive(); }
122+
123+
void force_active(void) { return m_reboot_thread.m_status.set_inactive(); }
124+
125+
void do_reboot(void) { return m_reboot_thread.do_reboot(); }
126+
127+
void wait_for_finish(swss::Select &s, swss::SelectableEvent &finished,
128+
long timeout_seconds) {
129+
swss::Selectable *sel;
130+
131+
int ret = s.select(&sel, timeout_seconds * 1000);
132+
EXPECT_EQ(ret, swss::Select::OBJECT);
133+
EXPECT_EQ(sel, &finished);
134+
}
135+
136+
Progress wait_for_platform_reboot(swss::Select &s) {
137+
return m_reboot_thread.wait_for_platform_reboot(s);
138+
}
139+
140+
swss::SelectableEvent &return_m_stop_reference() {
141+
return m_reboot_thread.m_stop;
142+
}
143+
144+
swss::DBConnector m_db;
145+
swss::DBConnector m_config_db;
146+
NiceMock<MockDbusInterface> m_dbus_interface;
147+
swss::SelectableEvent m_finished;
148+
RebootThread m_reboot_thread;
149+
};
150+
151+
MATCHER_P2(Status, status, message, "") {
152+
return (arg.status().status() == status && arg.status().message() == message);
153+
}
154+
155+
TEST_F(RebootThreadTest, TestStop) {
156+
EXPECT_CALL(m_dbus_interface, Reboot(_))
157+
.Times(1)
158+
.WillOnce(Return(DbusInterface::DbusResponse{
159+
DbusInterface::DbusStatus::DBUS_SUCCESS, ""}));
160+
gnoi::system::RebootRequest request;
161+
request.set_method(gnoi::system::RebootMethod::COLD);
162+
overwrite_reboot_timeout(2);
163+
m_reboot_thread.Start(request);
164+
m_reboot_thread.Stop();
165+
m_reboot_thread.Join();
166+
gnoi::system::RebootStatusResponse response = m_reboot_thread.GetResponse();
167+
EXPECT_THAT(
168+
response,
169+
IsStatus(
170+
gnoi::system::RebootStatus_Status::RebootStatus_Status_STATUS_UNKNOWN,
171+
""));
172+
}
173+
174+
TEST_F(RebootThreadTest, TestCleanExit) {
175+
EXPECT_CALL(m_dbus_interface, Reboot(_))
176+
.Times(1)
177+
.WillOnce(Return(DbusInterface::DbusResponse{
178+
DbusInterface::DbusStatus::DBUS_SUCCESS, ""}));
179+
180+
overwrite_reboot_timeout(1);
181+
182+
swss::Select s;
183+
s.addSelectable(&m_finished);
184+
185+
gnoi::system::RebootRequest request;
186+
request.set_method(gnoi::system::RebootMethod::COLD);
187+
request.set_message("time to reboot");
188+
m_reboot_thread.Start(request);
189+
wait_for_finish(s, m_finished, 5);
190+
191+
// Status should be active until we call join
192+
gnoi::system::RebootStatusResponse response = get_response();
193+
EXPECT_TRUE(response.active());
194+
EXPECT_THAT(response.reason(), StrEq("time to reboot"));
195+
EXPECT_EQ(response.count(), 1);
196+
197+
EXPECT_THAT(response.status().message(), StrEq(""));
198+
199+
m_reboot_thread.Join();
200+
201+
response = get_response();
202+
EXPECT_FALSE(response.active());
203+
EXPECT_THAT(response.status().message(), StrEq("platform failed to reboot"));
204+
}
205+
206+
TEST_F(RebootThreadTest, TestJoinWithoutStart) {
207+
bool ret = m_reboot_thread.Join();
208+
EXPECT_FALSE(ret);
209+
}
210+
211+
// Call Start a second time while first thread is still executing.
212+
TEST_F(RebootThreadTest, TestStartWhileRunning) {
213+
EXPECT_CALL(m_dbus_interface, Reboot(_))
214+
.Times(1)
215+
.WillOnce(Return(DbusInterface::DbusResponse{
216+
DbusInterface::DbusStatus::DBUS_SUCCESS, ""}));
217+
218+
overwrite_reboot_timeout(2);
219+
220+
gnoi::system::RebootRequest request;
221+
request.set_method(gnoi::system::RebootMethod::COLD);
222+
request.set_message("time to reboot");
223+
m_reboot_thread.Start(request);
224+
225+
// First thread is still running ...
226+
NotificationResponse response = m_reboot_thread.Start(request);
227+
EXPECT_EQ(response.status, swss::StatusCode::SWSS_RC_IN_USE);
228+
EXPECT_THAT(response.json_string,
229+
StrEq("RebootThread: can't Start while active"));
230+
231+
bool ret = m_reboot_thread.Join();
232+
EXPECT_TRUE(ret);
233+
}
234+
235+
// Call Start a second time after first thread completed
236+
// but before first thread was joined.
237+
// Second start should fail.
238+
TEST_F(RebootThreadTest, TestStartWithoutJoin) {
239+
EXPECT_CALL(m_dbus_interface, Reboot(_))
240+
.Times(1)
241+
.WillOnce(Return(DbusInterface::DbusResponse{
242+
DbusInterface::DbusStatus::DBUS_SUCCESS, ""}));
243+
244+
overwrite_reboot_timeout(1);
245+
246+
swss::Select s;
247+
s.addSelectable(&m_finished);
248+
249+
gnoi::system::RebootRequest request;
250+
request.set_method(gnoi::system::RebootMethod::COLD);
251+
request.set_message("time to reboot");
252+
m_reboot_thread.Start(request);
253+
wait_for_finish(s, m_finished, 3);
254+
255+
// First thread has stopped: we need to join before
256+
// restart will succeed
257+
NotificationResponse response = m_reboot_thread.Start(request);
258+
EXPECT_EQ(response.status, swss::StatusCode::SWSS_RC_IN_USE);
259+
260+
// This should join the first start.
261+
bool ret = m_reboot_thread.Join();
262+
EXPECT_TRUE(ret);
263+
}
264+
265+
TEST_F(RebootThreadTest, TestUnsupportedRebootType) {
266+
gnoi::system::RebootRequest request;
267+
request.set_method(gnoi::system::RebootMethod::POWERDOWN);
268+
269+
NotificationResponse response = m_reboot_thread.Start(request);
270+
EXPECT_EQ(response.status, swss::StatusCode::SWSS_RC_INVALID_PARAM);
271+
EXPECT_EQ(response.json_string,
272+
"RebootThread: Start rx'd unsupported method");
273+
}
274+
275+
TEST_F(RebootThreadTest, TestInvalidMethodfDoReboot) {
276+
set_start_status(gnoi::system::RebootMethod::POWERUP, "time to reboot");
277+
do_reboot();
278+
force_inactive();
279+
gnoi::system::RebootStatusResponse response = m_reboot_thread.GetResponse();
280+
EXPECT_THAT(
281+
response,
282+
IsStatus(
283+
gnoi::system::RebootStatus_Status::RebootStatus_Status_STATUS_UNKNOWN,
284+
""));
285+
}
286+
287+
} // namespace rebootbackend

0 commit comments

Comments
 (0)