1 #include "MCTPEndpoint.hpp"
2 #include "MCTPReactor.hpp"
3 #include "Utils.hpp"
4
5 #include <cstdint>
6 #include <functional>
7 #include <memory>
8 #include <string>
9 #include <system_error>
10 #include <vector>
11
12 #include <gmock/gmock.h>
13 #include <gtest/gtest.h>
14
15 class MockMCTPDevice : public MCTPDevice
16 {
17 public:
18 ~MockMCTPDevice() override = default;
19
20 MOCK_METHOD(void, setup,
21 (std::function<void(const std::error_code& ec,
22 const std::shared_ptr<MCTPEndpoint>& ep)> &&
23 added),
24 (override));
25 MOCK_METHOD(void, remove, (), (override));
26 MOCK_METHOD(std::string, describe, (), (const, override));
27 };
28
29 class MockMCTPEndpoint : public MCTPEndpoint
30 {
31 public:
32 ~MockMCTPEndpoint() override = default;
33
34 MOCK_METHOD(int, network, (), (const, override));
35 MOCK_METHOD(uint8_t, eid, (), (const, override));
36 MOCK_METHOD(void, subscribe,
37 (Event && degraded, Event&& available, Event&& removed),
38 (override));
39 MOCK_METHOD(void, remove, (), (override));
40 MOCK_METHOD(std::string, describe, (), (const, override));
41 MOCK_METHOD(std::shared_ptr<MCTPDevice>, device, (), (const, override));
42 };
43
44 class MockAssociationServer : public AssociationServer
45 {
46 public:
47 ~MockAssociationServer() override = default;
48
49 MOCK_METHOD(void, associate,
50 (const std::string& path,
51 const std::vector<Association>& associations),
52 (override));
53 MOCK_METHOD(void, disassociate, (const std::string& path), (override));
54 };
55
56 class MCTPReactorFixture : public testing::Test
57 {
58 protected:
SetUp()59 void SetUp() override
60 {
61 reactor = std::make_shared<MCTPReactor>(assoc);
62 device = std::make_shared<MockMCTPDevice>();
63 EXPECT_CALL(*device, describe())
64 .WillRepeatedly(testing::Return("mock device"));
65
66 endpoint = std::make_shared<MockMCTPEndpoint>();
67 EXPECT_CALL(*endpoint, device())
68 .WillRepeatedly(testing::Return(device));
69 EXPECT_CALL(*endpoint, describe())
70 .WillRepeatedly(testing::Return("mock endpoint"));
71 EXPECT_CALL(*endpoint, eid()).WillRepeatedly(testing::Return(9));
72 EXPECT_CALL(*endpoint, network()).WillRepeatedly(testing::Return(1));
73 }
74
TearDown()75 void TearDown() override
76 {
77 // https://stackoverflow.com/a/10289205
78 EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(endpoint.get()));
79 EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(device.get()));
80 }
81
82 MockAssociationServer assoc;
83 std::shared_ptr<MCTPReactor> reactor;
84 std::shared_ptr<MockMCTPDevice> device;
85 std::shared_ptr<MockMCTPEndpoint> endpoint;
86 };
87
TEST_F(MCTPReactorFixture,manageNullDevice)88 TEST_F(MCTPReactorFixture, manageNullDevice)
89 {
90 reactor->manageMCTPDevice("/test", {});
91 reactor->unmanageMCTPDevice("/test");
92 }
93
TEST_F(MCTPReactorFixture,manageMockDeviceSetupFailure)94 TEST_F(MCTPReactorFixture, manageMockDeviceSetupFailure)
95 {
96 EXPECT_CALL(*device, remove());
97 EXPECT_CALL(*device, setup(testing::_))
98 .WillOnce(testing::InvokeArgument<0>(
99 std::make_error_code(std::errc::permission_denied), endpoint));
100
101 reactor->manageMCTPDevice("/test", device);
102 reactor->unmanageMCTPDevice("/test");
103 }
104
TEST_F(MCTPReactorFixture,manageMockDevice)105 TEST_F(MCTPReactorFixture, manageMockDevice)
106 {
107 std::function<void(const std::shared_ptr<MCTPEndpoint>& ep)> removeHandler;
108
109 std::vector<Association> requiredAssociation{
110 {"configured_by", "configures", "/test"}};
111 EXPECT_CALL(assoc,
112 associate("/au/com/codeconstruct/mctp1/networks/1/endpoints/9",
113 requiredAssociation));
114 EXPECT_CALL(
115 assoc,
116 disassociate("/au/com/codeconstruct/mctp1/networks/1/endpoints/9"));
117
118 EXPECT_CALL(*endpoint, remove()).WillOnce(testing::Invoke([&]() {
119 removeHandler(endpoint);
120 }));
121 EXPECT_CALL(*endpoint, subscribe(testing::_, testing::_, testing::_))
122 .WillOnce(testing::SaveArg<2>(&removeHandler));
123
124 EXPECT_CALL(*device, remove()).WillOnce(testing::Invoke([&]() {
125 endpoint->remove();
126 }));
127 EXPECT_CALL(*device, setup(testing::_))
128 .WillOnce(testing::InvokeArgument<0>(std::error_code(), endpoint));
129
130 reactor->manageMCTPDevice("/test", device);
131 reactor->unmanageMCTPDevice("/test");
132 }
133
TEST_F(MCTPReactorFixture,manageMockDeviceDeferredSetup)134 TEST_F(MCTPReactorFixture, manageMockDeviceDeferredSetup)
135 {
136 std::function<void(const std::shared_ptr<MCTPEndpoint>& ep)> removeHandler;
137
138 std::vector<Association> requiredAssociation{
139 {"configured_by", "configures", "/test"}};
140 EXPECT_CALL(assoc,
141 associate("/au/com/codeconstruct/mctp1/networks/1/endpoints/9",
142 requiredAssociation));
143 EXPECT_CALL(
144 assoc,
145 disassociate("/au/com/codeconstruct/mctp1/networks/1/endpoints/9"));
146
147 EXPECT_CALL(*endpoint, remove()).WillOnce(testing::Invoke([&]() {
148 removeHandler(endpoint);
149 }));
150 EXPECT_CALL(*endpoint, subscribe(testing::_, testing::_, testing::_))
151 .WillOnce(testing::SaveArg<2>(&removeHandler));
152
153 EXPECT_CALL(*device, remove()).WillOnce(testing::Invoke([&]() {
154 endpoint->remove();
155 }));
156 EXPECT_CALL(*device, setup(testing::_))
157 .WillOnce(testing::InvokeArgument<0>(
158 std::make_error_code(std::errc::permission_denied), endpoint))
159 .WillOnce(testing::InvokeArgument<0>(std::error_code(), endpoint));
160
161 reactor->manageMCTPDevice("/test", device);
162 reactor->tick();
163 reactor->unmanageMCTPDevice("/test");
164 }
165
TEST_F(MCTPReactorFixture,manageMockDeviceRemoved)166 TEST_F(MCTPReactorFixture, manageMockDeviceRemoved)
167 {
168 std::function<void(const std::shared_ptr<MCTPEndpoint>& ep)> removeHandler;
169
170 std::vector<Association> requiredAssociation{
171 {"configured_by", "configures", "/test"}};
172 EXPECT_CALL(assoc,
173 associate("/au/com/codeconstruct/mctp1/networks/1/endpoints/9",
174 requiredAssociation))
175 .Times(2);
176 EXPECT_CALL(
177 assoc,
178 disassociate("/au/com/codeconstruct/mctp1/networks/1/endpoints/9"))
179 .Times(2);
180
181 EXPECT_CALL(*endpoint, remove()).WillOnce(testing::Invoke([&]() {
182 removeHandler(endpoint);
183 }));
184 EXPECT_CALL(*endpoint, subscribe(testing::_, testing::_, testing::_))
185 .Times(2)
186 .WillRepeatedly(testing::SaveArg<2>(&removeHandler));
187
188 EXPECT_CALL(*device, remove()).WillOnce(testing::Invoke([&]() {
189 endpoint->remove();
190 }));
191 EXPECT_CALL(*device, setup(testing::_))
192 .Times(2)
193 .WillRepeatedly(
194 testing::InvokeArgument<0>(std::error_code(), endpoint));
195
196 reactor->manageMCTPDevice("/test", device);
197 removeHandler(endpoint);
198 reactor->tick();
199 reactor->unmanageMCTPDevice("/test");
200 }
201
TEST(MCTPReactor,replaceConfiguration)202 TEST(MCTPReactor, replaceConfiguration)
203 {
204 MockAssociationServer assoc{};
205 auto reactor = std::make_shared<MCTPReactor>(assoc);
206 std::function<void(const std::shared_ptr<MCTPEndpoint>& ep)> removeHandler;
207
208 std::vector<Association> requiredAssociation{
209 {"configured_by", "configures", "/test"}};
210
211 EXPECT_CALL(assoc,
212 associate("/au/com/codeconstruct/mctp1/networks/1/endpoints/9",
213 requiredAssociation))
214 .Times(2);
215 EXPECT_CALL(
216 assoc,
217 disassociate("/au/com/codeconstruct/mctp1/networks/1/endpoints/9"))
218 .Times(2);
219
220 auto endpoint = std::make_shared<MockMCTPEndpoint>();
221 EXPECT_CALL(*endpoint, describe())
222 .WillRepeatedly(testing::Return("mock endpoint"));
223 EXPECT_CALL(*endpoint, eid()).WillRepeatedly(testing::Return(9));
224 EXPECT_CALL(*endpoint, network()).WillRepeatedly(testing::Return(1));
225 EXPECT_CALL(*endpoint, remove())
226 .Times(2)
227 .WillRepeatedly(testing::Invoke([&]() { removeHandler(endpoint); }));
228 EXPECT_CALL(*endpoint, subscribe(testing::_, testing::_, testing::_))
229 .Times(2)
230 .WillRepeatedly(testing::SaveArg<2>(&removeHandler));
231
232 auto initial = std::make_shared<MockMCTPDevice>();
233 EXPECT_CALL(*initial, describe())
234 .WillRepeatedly(testing::Return("mock device: initial"));
235 EXPECT_CALL(*initial, setup(testing::_))
236 .WillOnce(testing::InvokeArgument<0>(std::error_code(), endpoint));
237 EXPECT_CALL(*initial, remove()).WillOnce(testing::Invoke([&]() {
238 endpoint->remove();
239 }));
240
241 auto replacement = std::make_shared<MockMCTPDevice>();
242 EXPECT_CALL(*replacement, describe())
243 .WillRepeatedly(testing::Return("mock device: replacement"));
244 EXPECT_CALL(*replacement, setup(testing::_))
245 .WillOnce(testing::InvokeArgument<0>(std::error_code(), endpoint));
246 EXPECT_CALL(*replacement, remove()).WillOnce(testing::Invoke([&]() {
247 endpoint->remove();
248 }));
249
250 EXPECT_CALL(*endpoint, device())
251 .WillOnce(testing::Return(initial))
252 .WillOnce(testing::Return(initial))
253 .WillOnce(testing::Return(replacement))
254 .WillOnce(testing::Return(replacement));
255
256 reactor->manageMCTPDevice("/test", initial);
257 reactor->manageMCTPDevice("/test", replacement);
258 reactor->tick();
259 reactor->unmanageMCTPDevice("/test");
260
261 EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(initial.get()));
262 EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(replacement.get()));
263 EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(endpoint.get()));
264 }
265