xref: /openbmc/dbus-sensors/src/tests/test_MCTPReactor.cpp (revision 19d1fda609a4c39caca73858c90ebee823028362)
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