1 /**
2  * Copyright © 2020 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "action_environment.hpp"
17 #include "action_error.hpp"
18 #include "compare_vpd_action.hpp"
19 #include "id_map.hpp"
20 #include "mock_services.hpp"
21 #include "mock_vpd.hpp"
22 
23 #include <exception>
24 #include <memory>
25 #include <stdexcept>
26 #include <string>
27 #include <utility>
28 
29 #include <gmock/gmock.h>
30 #include <gtest/gtest.h>
31 
32 using ::testing::Return;
33 using ::testing::Throw;
34 
35 using namespace phosphor::power::regulators;
36 
37 TEST(CompareVPDActionTests, Constructor)
38 {
39     // Value vector is not empty
40     {
41         std::vector<uint8_t> value{0x32, 0x44, 0x33, 0x35}; // "2D35"
42         CompareVPDAction action{
43             "/xyz/openbmc_project/inventory/system/chassis/disk_backplane",
44             "CCIN", value};
45         EXPECT_EQ(
46             action.getFRU(),
47             "/xyz/openbmc_project/inventory/system/chassis/disk_backplane");
48         EXPECT_EQ(action.getKeyword(), "CCIN");
49         EXPECT_EQ(action.getValue(), value);
50     }
51 
52     // Value vector is empty
53     {
54         std::vector<uint8_t> value{};
55         CompareVPDAction action{
56             "/xyz/openbmc_project/inventory/system/chassis/disk_backplane",
57             "CCIN", value};
58         EXPECT_EQ(
59             action.getFRU(),
60             "/xyz/openbmc_project/inventory/system/chassis/disk_backplane");
61         EXPECT_EQ(action.getKeyword(), "CCIN");
62         EXPECT_EQ(action.getValue(), value);
63     }
64 }
65 
66 TEST(CompareVPDActionTests, Execute)
67 {
68     // Test where works: Actual VPD value is not empty
69     {
70         std::string fru{"/xyz/openbmc_project/inventory/system"};
71         std::string keyword{"Model"};
72         std::vector<uint8_t> abcdValue{0x41, 0x42, 0x43, 0x44};
73 
74         // Create MockServices object.  VPD service will return "ABCD" as VPD
75         // value 3 times.
76         MockServices services{};
77         MockVPD& vpd = services.getMockVPD();
78         EXPECT_CALL(vpd, getValue(fru, keyword))
79             .Times(3)
80             .WillRepeatedly(Return(abcdValue));
81 
82         IDMap idMap{};
83         ActionEnvironment environment{idMap, "", services};
84 
85         // Test where returns true: actual value == expected value
86         {
87             CompareVPDAction action{fru, keyword, abcdValue};
88             EXPECT_TRUE(action.execute(environment));
89         }
90 
91         // Test where returns false: actual value != expected value
92         {
93             CompareVPDAction action{fru, keyword,
94                                     std::vector<uint8_t>{1, 2, 3, 4}};
95             EXPECT_FALSE(action.execute(environment));
96         }
97 
98         // Test where returns false: expected value is empty
99         {
100             CompareVPDAction action{fru, keyword, std::vector<uint8_t>{}};
101             EXPECT_FALSE(action.execute(environment));
102         }
103     }
104 
105     // Test where works: Actual VPD value is empty
106     {
107         std::string fru{"/xyz/openbmc_project/inventory/system"};
108         std::string keyword{"Model"};
109         std::vector<uint8_t> emptyValue{};
110 
111         // Create MockServices object.  VPD service will return empty VPD value
112         // 2 times.
113         MockServices services{};
114         MockVPD& vpd = services.getMockVPD();
115         EXPECT_CALL(vpd, getValue(fru, keyword))
116             .Times(2)
117             .WillRepeatedly(Return(emptyValue));
118 
119         IDMap idMap{};
120         ActionEnvironment environment{idMap, "", services};
121 
122         // Test where returns true: actual value == expected value
123         {
124             CompareVPDAction action{fru, keyword, emptyValue};
125             EXPECT_TRUE(action.execute(environment));
126         }
127 
128         // Test where returns false: actual value != expected value
129         {
130             CompareVPDAction action{fru, keyword,
131                                     std::vector<uint8_t>{1, 2, 3}};
132             EXPECT_FALSE(action.execute(environment));
133         }
134     }
135 
136     // Test where fails: Exception thrown when trying to get actual VPD value
137     {
138         std::string fru{"/xyz/openbmc_project/inventory/system"};
139         std::string keyword{"Model"};
140 
141         // Create MockServices object.  VPD service will throw an exception.
142         MockServices services{};
143         MockVPD& vpd = services.getMockVPD();
144         EXPECT_CALL(vpd, getValue(fru, keyword))
145             .Times(1)
146             .WillOnce(
147                 Throw(std::runtime_error{"D-Bus error: Invalid object path"}));
148 
149         IDMap idMap{};
150         ActionEnvironment environment{idMap, "", services};
151 
152         try
153         {
154             CompareVPDAction action{fru, keyword,
155                                     std::vector<uint8_t>{1, 2, 3}};
156             action.execute(environment);
157             ADD_FAILURE() << "Should not have reached this line.";
158         }
159         catch (const ActionError& e)
160         {
161             EXPECT_STREQ(e.what(),
162                          "ActionError: compare_vpd: { fru: "
163                          "/xyz/openbmc_project/inventory/system, "
164                          "keyword: Model, value: [ 0x1, 0x2, 0x3 ] }");
165             try
166             {
167                 // Re-throw inner exception
168                 std::rethrow_if_nested(e);
169                 ADD_FAILURE() << "Should not have reached this line.";
170             }
171             catch (const std::runtime_error& re)
172             {
173                 EXPECT_STREQ(re.what(), "D-Bus error: Invalid object path");
174             }
175             catch (...)
176             {
177                 ADD_FAILURE() << "Should not have caught exception.";
178             }
179         }
180         catch (...)
181         {
182             ADD_FAILURE() << "Should not have caught exception.";
183         }
184     }
185 }
186 
187 TEST(CompareVPDActionTests, GetFRU)
188 {
189     CompareVPDAction action{
190         "/xyz/openbmc_project/inventory/system/chassis/disk_backplane", "CCIN",
191         std::vector<uint8_t>{1, 2, 3, 4}};
192     EXPECT_EQ(action.getFRU(),
193               "/xyz/openbmc_project/inventory/system/chassis/disk_backplane");
194 }
195 
196 TEST(CompareVPDActionTests, GetKeyword)
197 {
198     CompareVPDAction action{
199         "/xyz/openbmc_project/inventory/system/chassis/disk_backplane", "CCIN",
200         std::vector<uint8_t>{1, 2, 3, 4}};
201     EXPECT_EQ(action.getKeyword(), "CCIN");
202 }
203 
204 TEST(CompareVPDActionTests, GetValue)
205 {
206     CompareVPDAction action{
207         "/xyz/openbmc_project/inventory/system/chassis/disk_backplane", "CCIN",
208         std::vector<uint8_t>{1, 2, 3, 4}};
209     EXPECT_EQ(action.getValue(), (std::vector<uint8_t>{0x1, 0x2, 0x3, 0x4}));
210 }
211 
212 TEST(CompareVPDActionTests, ToString)
213 {
214     // Test where value vector is not empty
215     {
216         CompareVPDAction action{
217             "/xyz/openbmc_project/inventory/system/chassis/disk_backplane",
218             "CCIN", std::vector<uint8_t>{0x01, 0xA3, 0x0, 0xFF}};
219         EXPECT_EQ(action.toString(), "compare_vpd: { fru: "
220                                      "/xyz/openbmc_project/inventory/system/"
221                                      "chassis/disk_backplane, keyword: "
222                                      "CCIN, value: [ 0x1, 0xA3, 0x0, 0xFF ] }");
223     }
224 
225     // Test where value vector is empty
226     {
227         CompareVPDAction action{
228             "/xyz/openbmc_project/inventory/system/chassis/disk_backplane",
229             "CCIN", std::vector<uint8_t>{}};
230         EXPECT_EQ(action.toString(), "compare_vpd: { fru: "
231                                      "/xyz/openbmc_project/inventory/system/"
232                                      "chassis/disk_backplane, keyword: "
233                                      "CCIN, value: [  ] }");
234     }
235 }
236