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 "elog_entry.hpp"
17 #include "extensions/openpower-pels/pel_types.hpp"
18 #include "extensions/openpower-pels/private_header.hpp"
19 #include "extensions/openpower-pels/user_header.hpp"
20 #include "mocks.hpp"
21 #include "pel_utils.hpp"
22 
23 #include <gtest/gtest.h>
24 
25 using namespace openpower::pels;
26 using ::testing::Return;
27 
28 TEST(UserHeaderTest, SizeTest)
29 {
30     EXPECT_EQ(UserHeader::flattenedSize(), 24);
31 }
32 
33 TEST(UserHeaderTest, UnflattenFlattenTest)
34 {
35     auto data = pelDataFactory(TestPELType::userHeaderSection);
36 
37     Stream stream(data);
38     UserHeader uh(stream);
39     EXPECT_EQ(uh.valid(), true);
40 
41     EXPECT_EQ(uh.header().id, 0x5548);
42     EXPECT_EQ(uh.header().size, UserHeader::flattenedSize());
43     EXPECT_EQ(uh.header().version, 0x01);
44     EXPECT_EQ(uh.header().subType, 0x0A);
45     EXPECT_EQ(uh.header().componentID, 0x0B0C);
46 
47     EXPECT_EQ(uh.subsystem(), 0x10);
48     EXPECT_EQ(uh.scope(), 0x04);
49     EXPECT_EQ(uh.severity(), 0x20);
50     EXPECT_EQ(uh.eventType(), 0x00);
51     EXPECT_EQ(uh.problemDomain(), 0x03);
52     EXPECT_EQ(uh.problemVector(), 0x04);
53     EXPECT_EQ(uh.actionFlags(), 0x80C0);
54 
55     // Now flatten into a vector and check that this vector
56     // matches the original one.
57     std::vector<uint8_t> newData;
58     Stream newStream(newData);
59 
60     uh.flatten(newStream);
61     EXPECT_EQ(data, newData);
62 }
63 
64 TEST(UserHeaderTest, ShortDataTest)
65 {
66     auto data = pelDataFactory(TestPELType::userHeaderSection);
67     data.resize(data.size() - 1);
68 
69     Stream stream(data);
70     UserHeader uh(stream);
71 
72     EXPECT_EQ(uh.valid(), false);
73 }
74 
75 TEST(UserHeaderTest, CorruptDataTest1)
76 {
77     auto data = pelDataFactory(TestPELType::userHeaderSection);
78     data.resize(data.size() - 1);
79 
80     data.at(0) = 0; // corrupt the section ID
81 
82     Stream stream(data);
83     UserHeader uh(stream);
84 
85     EXPECT_EQ(uh.valid(), false);
86 }
87 
88 TEST(UserHeaderTest, CorruptDataTest2)
89 {
90     auto data = pelDataFactory(TestPELType::userHeaderSection);
91 
92     data.at(4) = 0x22; // corrupt the version
93 
94     Stream stream(data);
95     UserHeader uh(stream);
96 
97     EXPECT_EQ(uh.valid(), false);
98 }
99 
100 // Construct the User Header from the message registry
101 TEST(UserHeaderTest, ConstructionTest)
102 {
103     using namespace openpower::pels::message;
104     {
105         Entry regEntry;
106 
107         regEntry.name = "test";
108         regEntry.subsystem = 5;
109         regEntry.severity = {{"", 0x40}};
110         regEntry.actionFlags = 0xC000;
111         regEntry.eventType = 1;
112         regEntry.eventScope = 2;
113 
114         MockDataInterface dataIface;
115         AdditionalData ad;
116 
117         UserHeader uh(regEntry, phosphor::logging::Entry::Level::Error, ad,
118                       dataIface);
119 
120         ASSERT_TRUE(uh.valid());
121         EXPECT_EQ(uh.header().id, 0x5548);
122         EXPECT_EQ(uh.header().size, UserHeader::flattenedSize());
123         EXPECT_EQ(uh.header().version, 0x01);
124         EXPECT_EQ(uh.header().subType, 0x00);
125         EXPECT_EQ(uh.header().componentID,
126                   static_cast<uint16_t>(ComponentID::phosphorLogging));
127 
128         EXPECT_EQ(uh.subsystem(), 5);
129         EXPECT_EQ(uh.severity(), 0x40);
130         EXPECT_EQ(uh.eventType(), 1);
131         EXPECT_EQ(uh.scope(), 2);
132         EXPECT_EQ(uh.problemDomain(), 0);
133         EXPECT_EQ(uh.problemVector(), 0);
134         EXPECT_EQ(uh.actionFlags(), 0xC000);
135 
136         {
137             // The same thing, but as if the action flags weren't specified
138             // in the registry so they are a nullopt.  The object should
139             // then set them to 0xFFFF.
140             regEntry.actionFlags = std::nullopt;
141 
142             UserHeader uh(regEntry, phosphor::logging::Entry::Level::Error, ad,
143                           dataIface);
144             EXPECT_EQ(uh.actionFlags(), 0xFFFF);
145         }
146     }
147 
148     // Test the system type based severity lookups
149     {
150         Entry regEntry;
151 
152         regEntry.name = "test";
153         regEntry.subsystem = 5;
154         regEntry.severity = {{"", 0x20}, {"systemB", 0x10}, {"systemA", 0x00}};
155 
156         AdditionalData ad;
157 
158         MockDataInterface dataIface;
159         std::vector<std::string> names1{"systemA"};
160         std::vector<std::string> names2{"systemB"};
161         std::vector<std::string> names3{"systemC"};
162 
163         EXPECT_CALL(dataIface, getSystemNames)
164             .WillOnce(Return(names1))
165             .WillOnce(Return(names2))
166             .WillOnce(Return(names3));
167 
168         {
169             UserHeader uh(regEntry, phosphor::logging::Entry::Level::Error, ad,
170                           dataIface);
171 
172             EXPECT_EQ(uh.severity(), 0x00);
173         }
174 
175         {
176             UserHeader uh(regEntry, phosphor::logging::Entry::Level::Error, ad,
177                           dataIface);
178 
179             EXPECT_EQ(uh.severity(), 0x10);
180         }
181 
182         {
183             UserHeader uh(regEntry, phosphor::logging::Entry::Level::Error, ad,
184                           dataIface);
185 
186             EXPECT_EQ(uh.severity(), 0x20);
187         }
188     }
189 }
190 
191 // Test that the severity comes from the event log if not
192 // in the message registry
193 TEST(UserHeaderTest, UseEventLogSevTest)
194 {
195     using namespace openpower::pels::message;
196     Entry regEntry;
197 
198     regEntry.name = "test";
199     regEntry.subsystem = 5;
200     regEntry.actionFlags = 0xC000;
201     regEntry.eventType = 1;
202     regEntry.eventScope = 2;
203     // Leave off severity
204 
205     MockDataInterface dataIface;
206     AdditionalData ad;
207 
208     UserHeader uh(regEntry, phosphor::logging::Entry::Level::Error, ad,
209                   dataIface);
210     ASSERT_EQ(uh.severity(), 0x40);
211 }
212 
213 // Test that the critical severity comes from the event log if not
214 // in the message registry
215 TEST(UserHeaderTest, UseEventLogSevCritTest)
216 {
217     using namespace openpower::pels::message;
218     Entry regEntry;
219 
220     regEntry.name = "test";
221     regEntry.subsystem = 5;
222     regEntry.actionFlags = 0xC000;
223     regEntry.eventType = 1;
224     regEntry.eventScope = 2;
225     // Leave off severity
226 
227     MockDataInterface dataIface;
228     AdditionalData ad;
229 
230     UserHeader uh(regEntry, phosphor::logging::Entry::Level::Critical, ad,
231                   dataIface);
232     ASSERT_EQ(uh.severity(), 0x50);
233 }
234 
235 // Test that the critical severity comes from the event log if not
236 // in the message registry and termination condition is set
237 TEST(UserHeaderTest, UseEventLogSevCritTermTest)
238 {
239     using namespace openpower::pels::message;
240     Entry regEntry;
241 
242     regEntry.name = "test";
243     regEntry.subsystem = 5;
244     regEntry.actionFlags = 0xC000;
245     regEntry.eventType = 1;
246     regEntry.eventScope = 2;
247     // Leave off severity
248 
249     MockDataInterface dataIface;
250     std::vector<std::string> adData{"SEVERITY_DETAIL=SYSTEM_TERM"};
251     AdditionalData ad{adData};
252 
253     UserHeader uh(regEntry, phosphor::logging::Entry::Level::Critical, ad,
254                   dataIface);
255     ASSERT_EQ(uh.severity(), 0x51);
256 }
257 
258 // Test that the optional event type & scope fields work
259 TEST(UserHeaderTest, DefaultEventTypeScopeTest)
260 {
261     using namespace openpower::pels::message;
262     Entry regEntry;
263 
264     regEntry.name = "test";
265     regEntry.subsystem = 5;
266     regEntry.severity = {{"", 0x40}};
267     regEntry.actionFlags = 0xC000;
268 
269     MockDataInterface dataIface;
270     AdditionalData ad;
271 
272     UserHeader uh(regEntry, phosphor::logging::Entry::Level::Error, ad,
273                   dataIface);
274 
275     ASSERT_EQ(uh.eventType(), 0);
276     ASSERT_EQ(uh.scope(), 0x03);
277 }
278 
279 // Test that the event severity & action flags override
280 // when QuiesceOnHwError is set
281 TEST(UserHeaderTest, UseEventLogQuiesceOnErrorTest)
282 {
283     using namespace openpower::pels::message;
284     Entry regEntry;
285 
286     regEntry.name = "test";
287     regEntry.subsystem = 5;
288     regEntry.actionFlags = 0xC000;
289     regEntry.eventType = 1;
290     regEntry.eventScope = 2;
291     regEntry.severity = {{"", 0x40}, {"systemB", 0x10}, {"systemA", 0x00}};
292 
293     // set the value for mfg severity and action flags
294     regEntry.mfgSeverity = {{"systemA", 0x20}};
295     regEntry.mfgActionFlags = 0xF000;
296 
297     std::vector<std::string> names{"systemA"};
298 
299     MockDataInterface dataIface;
300     AdditionalData ad;
301 
302     EXPECT_CALL(dataIface, getSystemNames).WillOnce(Return(names));
303     EXPECT_CALL(dataIface, getQuiesceOnError).WillOnce(Return(true));
304 
305     UserHeader uh(regEntry, phosphor::logging::Entry::Level::Error, ad,
306                   dataIface);
307 
308     EXPECT_EQ(uh.severity(), 0x20);
309     EXPECT_EQ(uh.actionFlags(), 0xF000);
310 }
311 
312 // Test that the PEL Subsystem omes from the event log if any
313 TEST(UserHeaderTest, UseEventLogPELSubsystem)
314 {
315     using namespace openpower::pels::message;
316 
317     {
318         Entry regEntry;
319 
320         regEntry.name = "test";
321         regEntry.subsystem = 5;
322         regEntry.actionFlags = 0xC000;
323         regEntry.eventType = 1;
324         regEntry.eventScope = 2;
325 
326         MockDataInterface dataIface;
327         std::vector<std::string> adData{"PEL_SUBSYSTEM=0x25"};
328         AdditionalData ad{adData};
329 
330         UserHeader uh(regEntry, phosphor::logging::Entry::Level::Critical, ad,
331                       dataIface);
332         ASSERT_EQ(uh.subsystem(), 0x25);
333     }
334     {
335         // No subsystem in registry, and invalid PEL_SUBSYSTEM
336         Entry regEntry;
337 
338         regEntry.name = "test";
339         regEntry.actionFlags = 0xC000;
340         regEntry.eventType = 1;
341         regEntry.eventScope = 2;
342 
343         MockDataInterface dataIface;
344         std::vector<std::string> adData{"PEL_SUBSYSTEM=0x99"};
345         AdditionalData ad{adData};
346 
347         UserHeader uh(regEntry, phosphor::logging::Entry::Level::Critical, ad,
348                       dataIface);
349         ASSERT_EQ(uh.subsystem(), 0x70); // others
350     }
351     {
352         // No subsystem in registry or PEL_SUBSYSTEM
353         Entry regEntry;
354 
355         regEntry.name = "test";
356         regEntry.actionFlags = 0xC000;
357         regEntry.eventType = 1;
358         regEntry.eventScope = 2;
359 
360         MockDataInterface dataIface;
361         std::vector<std::string> adData;
362         AdditionalData ad{adData};
363 
364         UserHeader uh(regEntry, phosphor::logging::Entry::Level::Critical, ad,
365                       dataIface);
366         ASSERT_EQ(uh.subsystem(), 0x70); // others
367     }
368 }
369