xref: /openbmc/telemetry/tests/src/test_sensor.cpp (revision 94f71c51)
1 #include "dbus_environment.hpp"
2 #include "helpers.hpp"
3 #include "mocks/sensor_listener_mock.hpp"
4 #include "sensor.hpp"
5 #include "sensor_cache.hpp"
6 #include "stubs/dbus_sensor_object.hpp"
7 #include "utils/clock.hpp"
8 
9 #include <sdbusplus/asio/property.hpp>
10 
11 #include <thread>
12 
13 #include <gmock/gmock.h>
14 
15 using namespace testing;
16 using namespace std::chrono_literals;
17 
18 class TestSensor : public Test
19 {
20   public:
21     void SetUp() override
22     {
23         sensorObject->setValue(42.7);
24     }
25 
26     void TearDown() override
27     {
28         DbusEnvironment::synchronizeIoc();
29     }
30 
31     void
32         registerForUpdates(std::shared_ptr<interfaces::SensorListener> listener)
33     {
34         sut->registerForUpdates(listener);
35         DbusEnvironment::synchronizeIoc();
36     }
37 
38     void unregisterFromUpdates(
39         std::shared_ptr<interfaces::SensorListener> listener)
40     {
41         sut->unregisterFromUpdates(listener);
42         DbusEnvironment::synchronizeIoc();
43     }
44 
45     static std::unique_ptr<stubs::DbusSensorObject> makeSensorObject()
46     {
47         return std::make_unique<stubs::DbusSensorObject>(
48             DbusEnvironment::getIoc(), DbusEnvironment::getBus(),
49             DbusEnvironment::getObjServer());
50     }
51 
52     std::unique_ptr<stubs::DbusSensorObject> sensorObject = makeSensorObject();
53 
54     SensorCache sensorCache;
55     Milliseconds timestamp = Clock().steadyTimestamp();
56     std::shared_ptr<Sensor> sut = sensorCache.makeSensor<Sensor>(
57         DbusEnvironment::serviceName(), sensorObject->path(), "metadata",
58         DbusEnvironment::getIoc(), DbusEnvironment::getBus());
59     std::shared_ptr<SensorListenerMock> listenerMock =
60         std::make_shared<StrictMock<SensorListenerMock>>();
61     std::shared_ptr<SensorListenerMock> listenerMock2 =
62         std::make_shared<StrictMock<SensorListenerMock>>();
63     MockFunction<void()> checkPoint;
64 };
65 
66 TEST_F(TestSensor, createsCorretlyViaSensorCache)
67 {
68     ASSERT_THAT(sut->id(),
69                 Eq(Sensor::Id("Sensor", DbusEnvironment::serviceName(),
70                               sensorObject->path())));
71 }
72 
73 TEST_F(TestSensor, notifiesWithValueAfterRegister)
74 {
75     EXPECT_CALL(*listenerMock, sensorUpdated(Ref(*sut), Ge(timestamp), 42.7))
76         .WillOnce(InvokeWithoutArgs(DbusEnvironment::setPromise("async_read")));
77 
78     registerForUpdates(listenerMock);
79 
80     ASSERT_TRUE(DbusEnvironment::waitForFuture("async_read"));
81 }
82 
83 TEST_F(TestSensor, notifiesOnceWithValueAfterRegister)
84 {
85     EXPECT_CALL(*listenerMock, sensorUpdated(Ref(*sut), Ge(timestamp), 42.7))
86         .WillOnce(InvokeWithoutArgs(DbusEnvironment::setPromise("async_read")));
87     EXPECT_CALL(*listenerMock2, sensorUpdated(Ref(*sut), Ge(timestamp), 42.7))
88         .WillOnce(
89             InvokeWithoutArgs(DbusEnvironment::setPromise("async_read2")));
90 
91     DbusEnvironment::synchronizedPost([this] {
92         sut->registerForUpdates(listenerMock);
93         sut->registerForUpdates(listenerMock2);
94     });
95 
96     ASSERT_TRUE(DbusEnvironment::waitForFuture("async_read"));
97     ASSERT_TRUE(DbusEnvironment::waitForFuture("async_read2"));
98 }
99 
100 TEST_F(TestSensor, getLabeledInfoReturnsCorrectly)
101 {
102     auto expected = LabeledSensorInfo(DbusEnvironment::serviceName(),
103                                       sensorObject->path(), "metadata");
104     EXPECT_EQ(sut->getLabeledSensorInfo(), expected);
105 }
106 
107 TEST_F(TestSensor, getNameReturnsPathWhenMetadataIsNotSet)
108 {
109     static const char* path = "/telemetry/ut/DbusSensorObject2";
110     sut = sensorCache.makeSensor<Sensor>(DbusEnvironment::serviceName(), path,
111                                          "", DbusEnvironment::getIoc(),
112                                          DbusEnvironment::getBus());
113     EXPECT_EQ(sut->getName(), path);
114 }
115 
116 TEST_F(TestSensor, getNameReturnsMetadataWhenMetadataIsSet)
117 {
118     static const char* path = "/telemetry/ut/DbusSensorObject2";
119     sut = sensorCache.makeSensor<Sensor>(DbusEnvironment::serviceName(), path,
120                                          "metadata2", DbusEnvironment::getIoc(),
121                                          DbusEnvironment::getBus());
122     EXPECT_EQ(sut->getName(), "metadata2");
123 }
124 
125 class TestSensorNotification : public TestSensor
126 {
127   public:
128     void SetUp() override
129     {
130         EXPECT_CALL(*listenerMock, sensorUpdated(Ref(*sut), Ge(timestamp), 0.))
131             .WillOnce(
132                 InvokeWithoutArgs(DbusEnvironment::setPromise("async_read")));
133 
134         registerForUpdates(listenerMock);
135 
136         ASSERT_TRUE(DbusEnvironment::waitForFuture("async_read"));
137     }
138 };
139 
140 TEST_F(TestSensorNotification, notifiesListenerWithValueWhenChangeOccurs)
141 {
142     EXPECT_CALL(*listenerMock, sensorUpdated(Ref(*sut), Ge(timestamp), 42.7))
143         .WillOnce(InvokeWithoutArgs(DbusEnvironment::setPromise("notify")));
144 
145     sensorObject->setValue(42.7);
146 
147     ASSERT_TRUE(DbusEnvironment::waitForFuture("notify"));
148 }
149 
150 TEST_F(TestSensorNotification, notifiesListenerWithValueWhenNoChangeOccurs)
151 {
152     InSequence seq;
153 
154     EXPECT_CALL(*listenerMock, sensorUpdated(Ref(*sut), Ge(timestamp), 42.7));
155     EXPECT_CALL(*listenerMock, sensorUpdated(Ref(*sut), Ge(timestamp)))
156         .WillOnce(InvokeWithoutArgs(DbusEnvironment::setPromise("notify")));
157 
158     sensorObject->setValue(42.7);
159     sensorObject->setValue(42.7);
160 
161     ASSERT_TRUE(DbusEnvironment::waitForFuture("notify"));
162 }
163 
164 TEST_F(TestSensorNotification, doesntNotifyExpiredListener)
165 {
166     InSequence seq;
167     EXPECT_CALL(*listenerMock2, sensorUpdated(Ref(*sut), Ge(timestamp), 0.));
168     EXPECT_CALL(*listenerMock2, sensorUpdated(Ref(*sut), Ge(timestamp), 42.7))
169         .WillOnce(InvokeWithoutArgs(DbusEnvironment::setPromise("notify")));
170 
171     registerForUpdates(listenerMock2);
172     listenerMock = nullptr;
173 
174     sensorObject->setValue(42.7);
175 
176     ASSERT_TRUE(DbusEnvironment::waitForFuture("notify"));
177 }
178 
179 TEST_F(TestSensorNotification, notifiesWithValueDuringRegister)
180 {
181     EXPECT_CALL(*listenerMock2, sensorUpdated(Ref(*sut), Ge(timestamp), 0.));
182 
183     registerForUpdates(listenerMock2);
184 }
185 
186 TEST_F(TestSensorNotification, notNotifiesWithValueWhenUnregistered)
187 {
188     EXPECT_CALL(*listenerMock2, sensorUpdated(Ref(*sut), Ge(timestamp), 0.));
189     EXPECT_CALL(*listenerMock, sensorUpdated(Ref(*sut), Ge(timestamp), 42.7))
190         .Times(0);
191     EXPECT_CALL(*listenerMock2, sensorUpdated(Ref(*sut), Ge(timestamp), 42.7))
192         .WillOnce(InvokeWithoutArgs(DbusEnvironment::setPromise("notify")));
193 
194     registerForUpdates(listenerMock2);
195     unregisterFromUpdates(listenerMock);
196 
197     sensorObject->setValue(42.7);
198 
199     ASSERT_TRUE(DbusEnvironment::waitForFuture("notify"));
200 }
201 
202 TEST_F(TestSensorNotification,
203        dbusSensorIsAddedToSystemAfterSensorIsCreatedThenValueIsUpdated)
204 {
205     InSequence seq;
206 
207     EXPECT_CALL(*listenerMock,
208                 sensorUpdated(Ref(*sut), Ge(timestamp), DoubleEq(42.7)))
209         .WillOnce(
210             InvokeWithoutArgs(DbusEnvironment::setPromise("notify-change")));
211     EXPECT_CALL(checkPoint, Call());
212     EXPECT_CALL(*listenerMock,
213                 sensorUpdated(Ref(*sut), Ge(timestamp), DoubleEq(0.)))
214         .WillOnce(
215             InvokeWithoutArgs(DbusEnvironment::setPromise("notify-create")));
216 
217     sensorObject->setValue(42.7);
218     DbusEnvironment::waitForFuture("notify-change");
219 
220     checkPoint.Call();
221 
222     sensorObject = nullptr;
223     sensorObject = makeSensorObject();
224     DbusEnvironment::waitForFuture("notify-create");
225 }
226