1 #include "sensors/host.hpp"
2 
3 #include <chrono>
4 #include <gmock/gmock.h>
5 #include <gtest/gtest.h>
6 #include <memory>
7 #include <sdbusplus/test/sdbus_mock.hpp>
8 #include <string>
9 #include <vector>
10 
11 #include "test/helpers.hpp"
12 
13 using ::testing::IsNull;
14 using ::testing::Return;
15 using ::testing::StrEq;
16 
17 TEST(HostSensorTest, BoringConstructorTest) {
18     // WARN: The host sensor is not presently meant to be created this way,
19     // TODO: Can I move the constructor into private?
20 }
21 
22 TEST(HostSensorTest, CreateHostTempSensorTest) {
23     // The normal case for this sensor is to be a temperature sensor, where
24     // the value is treated as a margin sensor.
25 
26     sdbusplus::SdBusMock sdbus_mock;
27     auto bus_mock = sdbusplus::get_mocked_new(&sdbus_mock);
28     std::string name = "fleeting0";
29     int64_t timeout = 1;
30     const char *objPath = "/asdf/asdf0";
31     bool defer = false;
32     std::string interface = "xyz.openbmc_project.Sensor.Value";
33 
34     // Scale is the only property we change in the code.  Also,
35     // emit_object_added isn't called twice.
36     // Temperature is the default for type, and everything, so those aren't
37     // updated.
38     std::vector<std::string> properties = {"Scale"};
39     int i;
40 
41     // The CreateTemp updates all the properties, however, only Scale is set
42     // to non-default.
43     SetupDbusObject(
44         &sdbus_mock,
45         defer,
46         objPath,
47         interface,
48         properties,
49         &i);
50 
51     // This is called during object destruction.
52     EXPECT_CALL(sdbus_mock,
53                 sd_bus_emit_object_removed(IsNull(), StrEq(objPath)))
54         .WillOnce(Return(0));
55 
56     std::unique_ptr<Sensor> s = HostSensor::CreateTemp(
57         name, timeout, bus_mock, objPath, defer);
58 }
59 
60 TEST(HostSensorTest, VerifyWriteThenReadMatches) {
61     // Verify that when value is updated, the information matches
62     // what we expect when read back.
63 
64     sdbusplus::SdBusMock sdbus_mock;
65     auto bus_mock = sdbusplus::get_mocked_new(&sdbus_mock);
66     std::string name = "fleeting0";
67     int64_t timeout = 1;
68     const char *objPath = "/asdf/asdf0";
69     bool defer = false;
70     std::string interface = "xyz.openbmc_project.Sensor.Value";
71 
72     // Scale is the only property we change in the code.  Also,
73     // emit_object_added isn't called twice.
74     // Temperature is the default for type, and everything, so those aren't
75     // updated.
76     std::vector<std::string> properties = {"Scale"};
77     int i;
78 
79     SetupDbusObject(
80         &sdbus_mock,
81         defer,
82         objPath,
83         interface,
84         properties,
85         &i);
86 
87     EXPECT_CALL(sdbus_mock,
88                 sd_bus_emit_object_removed(IsNull(), StrEq(objPath)))
89         .WillOnce(Return(0));
90 
91     std::unique_ptr<Sensor> s = HostSensor::CreateTemp(
92         name, timeout, bus_mock, objPath, defer);
93 
94     // Value is updated from dbus calls only (normally).
95     HostSensor *hs = static_cast<HostSensor *>(s.get());
96     int64_t new_value = 2;
97 
98     ReadReturn r = hs->read();
99     EXPECT_EQ(r.value, 0);
100 
101     EXPECT_CALL(sdbus_mock,
102                     sd_bus_emit_properties_changed_strv(
103                     IsNull(),
104                     StrEq(objPath),
105                     StrEq(interface),
106                     NotNull()))
107         .WillOnce(
108             Invoke([=](sd_bus *bus,
109                        const char *path,
110                        const char *interface,
111                        char **names) {
112                 EXPECT_STREQ("Value", names[0]);
113                 return 0;
114             })
115         );
116 
117     std::chrono::high_resolution_clock::time_point t1 =
118         std::chrono::high_resolution_clock::now();
119 
120     hs->value(new_value);
121     r = hs->read();
122     EXPECT_EQ(r.value, new_value * 0.001);
123 
124     auto duration = std::chrono::duration_cast<std::chrono::seconds>(
125         t1 - r.updated).count();
126 
127     // Verify it was updated within the last second.
128     EXPECT_TRUE(duration < 1);
129 }
130