xref: /openbmc/phosphor-logging/test/openpower-pels/fru_identity_test.cpp (revision 81a91e3ee4bf962111cf555ab9d3c3c51000fa3b)
1 /**
2  * Copyright © 2019 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 "extensions/openpower-pels/fru_identity.hpp"
17 
18 #include <gtest/gtest.h>
19 
20 using namespace openpower::pels;
21 using namespace openpower::pels::src;
22 
23 // Unflatten a FRUIdentity that is a HW FRU callout
24 TEST(FRUIdentityTest, TestHardwareFRU)
25 {
26     // Has PN, SN, CCIN
27     std::vector<uint8_t> data{'I', 'D', 0x1C, 0x1D, // type, size, flags
28                               '1', '2', '3',  '4',  // PN
29                               '5', '6', '7',  0x00, 'A', 'A', 'A', 'A', // CCIN
30                               '1', '2', '3',  '4',  '5', '6', '7', '8', // SN
31                               '9', 'A', 'B',  'C'};
32 
33     Stream stream{data};
34 
35     FRUIdentity fru{stream};
36 
37     EXPECT_EQ(fru.failingComponentType(), FRUIdentity::hardwareFRU);
38     EXPECT_EQ(fru.flattenedSize(), data.size());
39     EXPECT_EQ(fru.type(), 0x4944);
40 
41     EXPECT_EQ(fru.getPN().value(), "1234567");
42     EXPECT_EQ(fru.getCCIN().value(), "AAAA");
43     EXPECT_EQ(fru.getSN().value(), "123456789ABC");
44     EXPECT_FALSE(fru.getMaintProc());
45 
46     // Flatten
47     std::vector<uint8_t> newData;
48     Stream newStream{newData};
49     fru.flatten(newStream);
50     EXPECT_EQ(data, newData);
51 }
52 
53 // Unflatten a FRUIdentity that is a Maintenance Procedure callout
54 TEST(FRUIdentityTest, TestMaintProcedure)
55 {
56     // Only contains the maintenance procedure
57     std::vector<uint8_t> data{
58         0x49, 0x44, 0x0C, 0x42,                     // type, size, flags
59         '1',  '2',  '3',  '4',  '5', '6', '7', 0x00 // Procedure
60     };
61 
62     Stream stream{data};
63 
64     FRUIdentity fru{stream};
65 
66     EXPECT_EQ(fru.failingComponentType(), FRUIdentity::maintenanceProc);
67     EXPECT_EQ(fru.flattenedSize(), data.size());
68 
69     EXPECT_EQ(fru.getMaintProc().value(), "1234567");
70     EXPECT_FALSE(fru.getPN());
71     EXPECT_FALSE(fru.getCCIN());
72     EXPECT_FALSE(fru.getSN());
73 
74     // Flatten
75     std::vector<uint8_t> newData;
76     Stream newStream{newData};
77     fru.flatten(newStream);
78     EXPECT_EQ(data, newData);
79 }
80 
81 // Try to unflatten garbage data
82 TEST(FRUIdentityTest, BadDataTest)
83 {
84     std::vector<uint8_t> data{0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
85                               0xFF, 0xFF, 0xFF, 0xFF};
86 
87     Stream stream{data};
88 
89     EXPECT_THROW(FRUIdentity fru{stream}, std::out_of_range);
90 }
91 
92 void testHWCallout(const std::string& pn, const std::string ccin,
93                    const std::string& sn, const std::string& expectedPN,
94                    const std::string& expectedCCIN,
95                    const std::string& expectedSN)
96 {
97     FRUIdentity fru{pn, ccin, sn};
98 
99     EXPECT_EQ(fru.flattenedSize(), 28);
100     EXPECT_EQ(fru.type(), 0x4944);
101     EXPECT_EQ(fru.failingComponentType(), FRUIdentity::hardwareFRU);
102     EXPECT_EQ(fru.getPN().value(), expectedPN);
103     EXPECT_EQ(fru.getCCIN().value(), expectedCCIN);
104     EXPECT_EQ(fru.getSN().value(), expectedSN);
105     EXPECT_FALSE(fru.getMaintProc());
106 
107     // Flatten and unflatten, then compare again
108     std::vector<uint8_t> data;
109     Stream stream{data};
110     fru.flatten(stream);
111 
112     EXPECT_EQ(data.size(), fru.flattenedSize());
113 
114     stream.offset(0);
115     FRUIdentity newFRU{stream};
116 
117     EXPECT_EQ(newFRU.flattenedSize(), fru.flattenedSize());
118     EXPECT_EQ(newFRU.type(), fru.type());
119     EXPECT_EQ(newFRU.failingComponentType(), fru.failingComponentType());
120     EXPECT_EQ(newFRU.getPN().value(), fru.getPN().value());
121     EXPECT_EQ(newFRU.getCCIN().value(), fru.getCCIN().value());
122     EXPECT_EQ(newFRU.getSN().value(), fru.getSN().value());
123     EXPECT_FALSE(newFRU.getMaintProc());
124 }
125 
126 // Test the constructor that takes in a PN/SN/CCIN
127 TEST(FRUIdentityTest, CreateHardwareCalloutTest)
128 {
129     // The right sizes
130     testHWCallout("1234567", "1234", "123456789ABC",
131                   // expected
132                   "1234567", "1234", "123456789ABC");
133 
134     // Too long
135     testHWCallout("1234567long", "1234long", "123456789ABClong",
136                   // expected
137                   "1234567", "1234", "123456789ABC");
138     // Too short
139     testHWCallout("11", "22", "333",
140                   // expected
141                   "11", "22", "333");
142 
143     // empty
144     testHWCallout("", "", "",
145                   // expected
146                   "", "", "");
147 
148     // Leading spaces in the part number will be stripped
149     testHWCallout("    567", "1234", "123456789ABC",
150                   // expected
151                   "567", "1234", "123456789ABC");
152 
153     // All spaces in the part number
154     testHWCallout("       ", "1234", "123456789ABC",
155                   // expected
156                   "", "1234", "123456789ABC");
157 }
158 
159 // Test the constructor that takes in a maint procedure
160 TEST(FRUIdentityTest, CreateProcedureCalloutTest)
161 {
162     {
163         FRUIdentity fru{"no_vpd_for_fru"};
164 
165         EXPECT_EQ(fru.flattenedSize(), 12);
166         EXPECT_EQ(fru.type(), 0x4944);
167         EXPECT_EQ(fru.failingComponentType(), FRUIdentity::maintenanceProc);
168         EXPECT_EQ(fru.getMaintProc().value(), "BMCSP01");
169         EXPECT_FALSE(fru.getPN());
170         EXPECT_FALSE(fru.getCCIN());
171         EXPECT_FALSE(fru.getSN());
172 
173         // Flatten and unflatten, then compare again
174         std::vector<uint8_t> data;
175         Stream stream{data};
176         fru.flatten(stream);
177 
178         EXPECT_EQ(data.size(), fru.flattenedSize());
179 
180         stream.offset(0);
181         FRUIdentity newFRU{stream};
182 
183         EXPECT_EQ(newFRU.flattenedSize(), 12);
184         EXPECT_EQ(newFRU.type(), 0x4944);
185         EXPECT_EQ(newFRU.failingComponentType(), FRUIdentity::maintenanceProc);
186         EXPECT_EQ(newFRU.getMaintProc().value(), "BMCSP01");
187         EXPECT_FALSE(newFRU.getPN());
188         EXPECT_FALSE(newFRU.getCCIN());
189         EXPECT_FALSE(newFRU.getSN());
190     }
191 
192     {
193         // Invalid maintenance procedure
194         FRUIdentity fru{"invalid"};
195 
196         EXPECT_EQ(fru.flattenedSize(), 12);
197         EXPECT_EQ(fru.type(), 0x4944);
198         EXPECT_EQ(fru.failingComponentType(), FRUIdentity::maintenanceProc);
199         EXPECT_EQ(fru.getMaintProc().value(), "INVALID");
200         EXPECT_FALSE(fru.getPN());
201         EXPECT_FALSE(fru.getCCIN());
202         EXPECT_FALSE(fru.getSN());
203     }
204 }
205 
206 // Test the constructor that takes in a symbolic FRU.
207 TEST(FRUIdentityTest, CreateSymbolicFRUCalloutTest)
208 {
209     // Symbolic FRU (not trusted)
210     {
211         FRUIdentity fru{"service_docs", false};
212 
213         EXPECT_EQ(fru.flattenedSize(), 12);
214         EXPECT_EQ(fru.type(), 0x4944);
215         EXPECT_EQ(fru.failingComponentType(), FRUIdentity::symbolicFRU);
216         EXPECT_EQ(fru.getPN().value(), "SVCDOCS");
217         EXPECT_FALSE(fru.getMaintProc());
218         EXPECT_FALSE(fru.getCCIN());
219         EXPECT_FALSE(fru.getSN());
220 
221         // Flatten and unflatten, then compare again
222         std::vector<uint8_t> data;
223         Stream stream{data};
224         fru.flatten(stream);
225 
226         EXPECT_EQ(data.size(), fru.flattenedSize());
227 
228         stream.offset(0);
229         FRUIdentity newFRU{stream};
230 
231         EXPECT_EQ(newFRU.flattenedSize(), 12);
232         EXPECT_EQ(newFRU.type(), 0x4944);
233         EXPECT_EQ(newFRU.failingComponentType(), FRUIdentity::symbolicFRU);
234         EXPECT_EQ(newFRU.getPN().value(), "SVCDOCS");
235         EXPECT_FALSE(newFRU.getMaintProc());
236         EXPECT_FALSE(newFRU.getCCIN());
237         EXPECT_FALSE(newFRU.getSN());
238     }
239 
240     // Trusted symbolic FRU
241     {
242         FRUIdentity fru{"service_docs", true};
243 
244         EXPECT_EQ(fru.flattenedSize(), 12);
245         EXPECT_EQ(fru.type(), 0x4944);
246         EXPECT_EQ(fru.failingComponentType(),
247                   FRUIdentity::symbolicFRUTrustedLocCode);
248         EXPECT_EQ(fru.getPN().value(), "SVCDOCS");
249         EXPECT_FALSE(fru.getMaintProc());
250         EXPECT_FALSE(fru.getCCIN());
251         EXPECT_FALSE(fru.getSN());
252     }
253 
254     // Invalid symbolic FRU
255     {
256         FRUIdentity fru{"garbage", false};
257 
258         EXPECT_EQ(fru.flattenedSize(), 12);
259         EXPECT_EQ(fru.type(), 0x4944);
260         EXPECT_EQ(fru.failingComponentType(), FRUIdentity::symbolicFRU);
261         EXPECT_EQ(fru.getPN().value(), "INVALID");
262         EXPECT_FALSE(fru.getMaintProc());
263         EXPECT_FALSE(fru.getCCIN());
264         EXPECT_FALSE(fru.getSN());
265     }
266 }
267