1 #include <array>
2 #include "propertywatchimpl.hpp"
3 #include "propertywatchtest.hpp"
4 
5 using namespace std::string_literals;
6 using namespace phosphor::dbus::monitoring;
7 
8 const std::array<std::string, 4> paths = {
9     "/xyz/openbmc_project/testing/inst1"s,
10     "/xyz/openbmc_project/testing/inst2"s,
11     "/xyz/openbmc_project/testing/inst3"s,
12     "/xyz/openbmc_project/testing/inst4"s,
13 };
14 
15 const std::array<std::string, 2> interfaces = {
16     "xyz.openbmc_project.Iface1"s,
17     "xyz.openbmc_project.Iface2"s,
18 };
19 
20 const std::array<std::string, 2> properties = {
21     "Value1"s,
22     "Value2"s,
23 };
24 
25 const std::string meta;
26 
27 std::array<std::tuple<any_ns::any, any_ns::any>, 8> storage = {};
28 
29 const PropertyIndex watchIndex = {
30     {
31         {PropertyIndex::key_type{paths[0], interfaces[0], properties[0]},
32          PropertyIndex::mapped_type{meta, meta, storage[0]}},
33         {PropertyIndex::key_type{paths[0], interfaces[1], properties[1]},
34          PropertyIndex::mapped_type{meta, meta, storage[1]}},
35         {PropertyIndex::key_type{paths[1], interfaces[0], properties[0]},
36          PropertyIndex::mapped_type{meta, meta, storage[2]}},
37         {PropertyIndex::key_type{paths[1], interfaces[1], properties[1]},
38          PropertyIndex::mapped_type{meta, meta, storage[3]}},
39         {PropertyIndex::key_type{paths[2], interfaces[0], properties[0]},
40          PropertyIndex::mapped_type{meta, meta, storage[4]}},
41         {PropertyIndex::key_type{paths[2], interfaces[1], properties[1]},
42          PropertyIndex::mapped_type{meta, meta, storage[5]}},
43         {PropertyIndex::key_type{paths[3], interfaces[0], properties[0]},
44          PropertyIndex::mapped_type{meta, meta, storage[6]}},
45         {PropertyIndex::key_type{paths[3], interfaces[1], properties[1]},
46          PropertyIndex::mapped_type{meta, meta, storage[7]}},
47     },
48 };
49 
50 template <typename T> struct ExpectedValues
51 {
52 };
53 template <> struct ExpectedValues<uint8_t>
54 {
55     static auto& get(size_t i)
56     {
57         static const std::array<uint8_t, 8> values = {
58             {0, 1, 2, 3, 4, 5, 6, 7},
59         };
60         return values[i];
61     }
62 };
63 
64 template <> struct ExpectedValues<uint16_t>
65 {
66     static auto& get(size_t i)
67     {
68         static const std::array<uint16_t, 8> values = {
69             {88, 77, 66, 55, 44, 33, 22, 11},
70         };
71         return values[i];
72     }
73 };
74 
75 template <> struct ExpectedValues<uint32_t>
76 {
77     static auto& get(size_t i)
78     {
79         static const std::array<uint32_t, 8> values = {
80             {0xffffffff, 1, 3, 0, 5, 7, 9, 0xffffffff},
81         };
82         return values[i];
83     }
84 };
85 
86 template <> struct ExpectedValues<uint64_t>
87 {
88     static auto& get(size_t i)
89     {
90         static const std::array<uint64_t, 8> values = {
91             {0xffffffffffffffff, 3, 7, 12234, 0, 3, 9, 0xffffffff},
92         };
93         return values[i];
94     }
95 };
96 
97 template <> struct ExpectedValues<std::string>
98 {
99     static auto& get(size_t i)
100     {
101         static const std::array<std::string, 8> values = {
102             {""s, "foo"s, "bar"s, "baz"s, "hello"s, "string", "\x2\x3", "\\"},
103         };
104         return values[i];
105     }
106 };
107 
108 template <typename T> void testStart()
109 {
110     using ::testing::Return;
111     using ::testing::_;
112 
113     MockDBusInterface dbus;
114     MockDBusInterface::instance(dbus);
115 
116     const std::vector<std::string> expectedMapperInterfaces;
117     PropertyWatchOfType<T, MockDBusInterface> watch(watchIndex);
118 
119     auto ndx = static_cast<size_t>(0);
120     for (const auto& o : convert(watchIndex))
121     {
122         const auto& path = o.first.get();
123         const auto& interfaces = o.second;
124         std::vector<std::string> mapperResponse;
125         std::transform(interfaces.begin(), interfaces.end(),
126                        std::back_inserter(mapperResponse),
127                        // *INDENT-OFF*
128                        [](const auto& item) { return item.first; });
129         // *INDENT-ON*
130         EXPECT_CALL(dbus, mapperGetObject(MAPPER_BUSNAME, MAPPER_PATH,
131                                           MAPPER_INTERFACE, "GetObject", path,
132                                           expectedMapperInterfaces))
133             .WillOnce(Return(GetObject({{"", mapperResponse}})));
134         EXPECT_CALL(
135             dbus, fwdAddMatch(
136                       sdbusplus::bus::match::rules::member("InterfacesAdded") +
137                           sdbusplus::bus::match::rules::path(path) +
138                           sdbusplus::bus::match::rules::interface(
139                               "org.freedesktop.DBus.ObjectManager"),
140                       _));
141         for (const auto& i : interfaces)
142         {
143             const auto& interface = i.first.get();
144             const auto& properties = i.second;
145             EXPECT_CALL(
146                 dbus,
147                 fwdAddMatch(
148                     sdbusplus::bus::match::rules::member("PropertiesChanged") +
149                         sdbusplus::bus::match::rules::path(path) +
150                         sdbusplus::bus::match::rules::argN(0, interface) +
151                         sdbusplus::bus::match::rules::interface(
152                             "org.freedesktop.DBus.Properties"),
153                     _));
154 
155             PropertiesChanged<T> serviceResponse;
156             for (const auto& p : properties)
157             {
158                 serviceResponse[p] = ExpectedValues<T>::get(ndx);
159                 ++ndx;
160             }
161             Expect<T>::getProperties(dbus, path, interface)
162                 .WillOnce(Return(serviceResponse));
163         }
164     }
165 
166     watch.start();
167 
168     ndx = 0;
169     for (auto s : storage)
170     {
171         ASSERT_EQ(std::get<0>(s).empty(), false);
172         ASSERT_EQ(any_ns::any_cast<T>(s), ExpectedValues<T>::get(ndx));
173         ++ndx;
174     }
175 
176     // Make sure start logic only runs the first time.
177     watch.start();
178 }
179 
180 TEST(PropertyWatchTest, TestStart)
181 {
182     testStart<uint8_t>();
183     testStart<uint16_t>();
184     testStart<uint32_t>();
185     testStart<uint64_t>();
186     testStart<std::string>();
187 }
188 
189 MockDBusInterface* MockDBusInterface::ptr = nullptr;
190