blob: c2000661140010e52541a2eb30eef9148c135a30 [file] [log] [blame]
Matt Spinlerb96fa322018-03-27 13:39:33 -05001/**
2 * Copyright © 2018 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 */
Matt Spinler62011e22018-03-27 15:27:39 -050016#include "policy_find.hpp"
Matt Spinler66e07072018-09-12 10:36:14 -050017#include "policy_table.hpp"
18
19#include <experimental/filesystem>
20#include <fstream>
21
22#include <gtest/gtest.h>
Matt Spinlerb96fa322018-03-27 13:39:33 -050023
24using namespace ibm::logging;
25namespace fs = std::experimental::filesystem;
26
Matt Spinlerc57aa4b2018-09-28 10:32:24 -050027static constexpr auto HOST_EVENT = "org.open_power.Host.Error.Event";
28
29// ESEL contents all of the way up to right before the severity
30// byte in the UH section
31static const std::string eSELBase =
32 "ESEL="
33 "00 00 df 00 00 00 00 20 00 04 07 5a 04 aa 00 00 50 48 00 30 01 00 e5 00 "
34 "00 00 f6 ca c9 da 5b b7 00 00 f6 ca d1 8a 2d e6 42 00 00 08 00 00 00 00 "
35 "00 00 00 00 00 00 00 00 89 00 03 44 89 00 03 44 55 48 00 18 01 00 e5 00 "
36 "13 03 ";
37
38static const std::string noUHeSEL =
39 "ESEL="
40 "00 00 df 00 00 00 00 20 00 04 07 5a 04 aa 00 00 50 48 00 30 01 00 e5 00 "
41 "00 00 f6 ca c9 da 5b b7 00 00 f6 ca d1 8a 2d e6 42 00 00 08 00 00 00 00 "
42 "00 00 00 00 00 00 00 00 89 00 03 44 89 00 03 44 00 00 00 18 01 00 e5 00 "
43 "13 03 10";
44
45// ESEL Severity bytes
46static const std::string SEV_RECOVERED = "10";
47static const std::string SEV_PREDICTIVE = "20";
48static const std::string SEV_UNRECOV = "40";
49static const std::string SEV_CRITICAL = "50";
50static const std::string SEV_DIAG = "60";
51
Matt Spinlerb96fa322018-03-27 13:39:33 -050052static constexpr auto json = R"(
53[
54 {
55 "dtls":[
56 {
57 "CEID":"ABCD1234",
58 "mod":"",
59 "msg":"Error ABCD1234"
60 }
61 ],
62 "err":"xyz.openbmc_project.Error.Test1"
63 },
64
65 {
66 "dtls":[
67 {
68 "CEID":"XYZ222",
69 "mod":"",
70 "msg":"Error XYZ222"
71 }
72 ],
73 "err":"xyz.openbmc_project.Error.Test2"
74 },
75
76 {
77 "dtls":[
78 {
79 "CEID":"AAAAAA",
80 "mod":"mod1",
81 "msg":"Error AAAAAA"
82 },
83 {
84 "CEID":"BBBBBB",
85 "mod":"mod2",
86 "msg":"Error BBBBBB"
87 },
88 {
89 "CEID":"CCCCCC",
90 "mod":"mod3",
91 "msg":"Error CCCCCC"
92 }
93 ],
94 "err":"xyz.openbmc_project.Error.Test3"
95 },
96
97 {
98 "dtls":[
99 {
100 "CEID":"DDDDDDDD",
101 "mod":"I2C",
102 "msg":"Error DDDDDDDD"
103 },
104 {
105 "CEID":"EEEEEEEE",
106 "mod":"FSI",
107 "msg":"Error EEEEEEEE"
108 }
109 ],
110 "err":"xyz.openbmc_project.Error.Test4"
111 },
112
113 {
114 "dtls":[
115 {
116 "CEID":"FFFFFFFF",
117 "mod":"6D",
118 "msg":"Error FFFFFFFF"
119 }
120 ],
Matt Spinlerb96fa322018-03-27 13:39:33 -0500121 "err":"xyz.openbmc_project.Error.Test5"
122 },
Matt Spinlerc57aa4b2018-09-28 10:32:24 -0500123
Matt Spinlerb96fa322018-03-27 13:39:33 -0500124 {
125 "dtls":[
126 {
127 "CEID":"GGGGGGGG",
128 "mod":"RAIL_5",
129 "msg":"Error GGGGGGGG"
130 }
131 ],
Matt Spinlerb96fa322018-03-27 13:39:33 -0500132 "err":"xyz.openbmc_project.Error.Test6"
133 },
Matt Spinlerc57aa4b2018-09-28 10:32:24 -0500134
Matt Spinlerb96fa322018-03-27 13:39:33 -0500135 {
136 "dtls":[
137 {
138 "CEID":"HHHHHHHH",
139 "mod":"INPUT_42",
140 "msg":"Error HHHHHHHH"
141 }
142 ],
143 "err":"xyz.openbmc_project.Error.Test7"
Matt Spinlerc57aa4b2018-09-28 10:32:24 -0500144 },
145
146 {
147 "dtls":[
148 {
149 "CEID":"IIIIIII",
150 "mod":"/match/this/path",
151 "msg":"Error IIIIIII"
152 }
153 ],
154 "err":"xyz.openbmc_project.Error.Test8"
155 },
156
157 {
158 "dtls":[
159 {
160 "CEID":"JJJJJJJJ",
161 "mod":"/inventory/core0||Warning",
162 "msg":"Error JJJJJJJJ"
163 },
164 {
165 "CEID":"KKKKKKKK",
166 "mod":"/inventory/core1||Informational",
167 "msg":"Error KKKKKKKK"
168 },
169 {
170 "CEID":"LLLLLLLL",
171 "mod":"/inventory/core2||Critical",
172 "msg":"Error LLLLLLLL"
173 },
174 {
175 "CEID":"MMMMMMMM",
176 "mod":"/inventory/core3||Critical",
177 "msg":"Error MMMMMMMM"
178 },
179 {
180 "CEID":"NNNNNNNN",
181 "mod":"/inventory/core4||Critical",
182 "msg":"Error NNNNNNNN"
183 },
184 {
185 "CEID":"OOOOOOOO",
186 "mod":"/inventory/core5",
187 "msg":"Error OOOOOOOO"
188 },
189 {
190 "CEID":"PPPPPPPP",
191 "mod":"/inventory/core5||Critical",
192 "msg":"Error PPPPPPPP"
193 }
194 ],
195 "err":"org.open_power.Host.Error.Event"
Matt Spinlerb96fa322018-03-27 13:39:33 -0500196 }
197])";
198
Matt Spinlerb96fa322018-03-27 13:39:33 -0500199/**
200 * Helper class to write the above json to a file and then
201 * remove it when the tests are over.
202 */
203class PolicyTableTest : public ::testing::Test
204{
Matt Spinler259e7272018-03-29 10:57:17 -0500205 protected:
206 virtual void SetUp()
207 {
208 char dir[] = {"./jsonTestXXXXXX"};
Matt Spinlerb96fa322018-03-27 13:39:33 -0500209
Matt Spinler259e7272018-03-29 10:57:17 -0500210 jsonDir = mkdtemp(dir);
211 jsonFile = jsonDir / "policy.json";
Matt Spinlerb96fa322018-03-27 13:39:33 -0500212
Matt Spinler259e7272018-03-29 10:57:17 -0500213 std::ofstream f{jsonFile};
214 f << json;
215 }
Matt Spinlerb96fa322018-03-27 13:39:33 -0500216
Matt Spinler259e7272018-03-29 10:57:17 -0500217 virtual void TearDown()
218 {
219 fs::remove_all(jsonDir);
220 }
Matt Spinlerb96fa322018-03-27 13:39:33 -0500221
Matt Spinler259e7272018-03-29 10:57:17 -0500222 fs::path jsonDir;
223 fs::path jsonFile;
Matt Spinlerb96fa322018-03-27 13:39:33 -0500224};
225
Matt Spinlerb96fa322018-03-27 13:39:33 -0500226/**
227 * Test finding entries in the policy table
228 */
229TEST_F(PolicyTableTest, TestTable)
230{
231 policy::Table policy{jsonFile};
232 ASSERT_EQ(policy.isLoaded(), true);
233
234 ////////////////////////////////////
Matt Spinler259e7272018-03-29 10:57:17 -0500235 // Basic search, no modifier
Matt Spinlerb96fa322018-03-27 13:39:33 -0500236 std::string err{"xyz.openbmc_project.Error.Test2"};
237 std::string mod;
238
239 auto details = policy.find(err, mod);
240 ASSERT_EQ(static_cast<bool>(details), true);
241 if (details)
242 {
243 ASSERT_EQ((*details).get().ceid, "XYZ222");
244 ASSERT_EQ((*details).get().msg, "Error XYZ222");
245 }
246
247 /////////////////////////////////////
Matt Spinler259e7272018-03-29 10:57:17 -0500248 // Not found
Matt Spinlerb96fa322018-03-27 13:39:33 -0500249 err = "foo";
250 details = policy.find(err, mod);
251 ASSERT_EQ(static_cast<bool>(details), false);
252
253 /////////////////////////////////////
Matt Spinler259e7272018-03-29 10:57:17 -0500254 // Test with a modifier
Matt Spinlerb96fa322018-03-27 13:39:33 -0500255 err = "xyz.openbmc_project.Error.Test3";
256 mod = "mod3";
257
258 details = policy.find(err, mod);
259 ASSERT_EQ(static_cast<bool>(details), true);
260 if (details)
261 {
262 ASSERT_EQ((*details).get().ceid, "CCCCCC");
263 ASSERT_EQ((*details).get().msg, "Error CCCCCC");
264 }
265}
Matt Spinler62011e22018-03-27 15:27:39 -0500266
267/**
268 * Test policy::find() that uses the data from a property
269 * map to find entries in the policy table.
270 */
271TEST_F(PolicyTableTest, TestFinder)
272{
273 using namespace std::literals::string_literals;
274
275 policy::Table policy{jsonFile};
276 ASSERT_EQ(policy.isLoaded(), true);
277
Matt Spinler259e7272018-03-29 10:57:17 -0500278 // A basic search with no modifier
Matt Spinler62011e22018-03-27 15:27:39 -0500279 {
Matt Spinler259e7272018-03-29 10:57:17 -0500280 DbusPropertyMap testProperties{
281 {"Message"s, Value{"xyz.openbmc_project.Error.Test1"s}}};
Matt Spinler62011e22018-03-27 15:27:39 -0500282
283 auto values = policy::find(policy, testProperties);
284 ASSERT_EQ(std::get<policy::EIDField>(values), "ABCD1234");
285 ASSERT_EQ(std::get<policy::MsgField>(values), "Error ABCD1234");
286 }
287
Matt Spinler259e7272018-03-29 10:57:17 -0500288 // Use CALLOUT_INVENTORY_PATH from the AdditionalData property
Matt Spinler62011e22018-03-27 15:27:39 -0500289 {
Matt Spinler259e7272018-03-29 10:57:17 -0500290 std::vector<std::string> ad{"FOO=BAR"s, "CALLOUT_INVENTORY_PATH=mod2"s};
291 DbusPropertyMap testProperties{
Matt Spinler62011e22018-03-27 15:27:39 -0500292 {"Message"s, Value{"xyz.openbmc_project.Error.Test3"s}},
Matt Spinler259e7272018-03-29 10:57:17 -0500293 {"AdditionalData"s, ad}};
Matt Spinler62011e22018-03-27 15:27:39 -0500294
295 auto values = policy::find(policy, testProperties);
296 ASSERT_EQ(std::get<policy::EIDField>(values), "BBBBBB");
297 ASSERT_EQ(std::get<policy::MsgField>(values), "Error BBBBBB");
298 }
299
Matt Spinler259e7272018-03-29 10:57:17 -0500300 // Use an I2C DEVICE_PATH from the AdditionalData property
Matt Spinler62011e22018-03-27 15:27:39 -0500301 {
Matt Spinler259e7272018-03-29 10:57:17 -0500302 std::vector<std::string> ad{"FOO=BAR"s,
303 "CALLOUT_DEVICE_PATH=/some/i2c/path"s};
304 DbusPropertyMap testProperties{
Matt Spinler62011e22018-03-27 15:27:39 -0500305 {"Message"s, Value{"xyz.openbmc_project.Error.Test4"s}},
Matt Spinler259e7272018-03-29 10:57:17 -0500306 {"AdditionalData"s, ad}};
Matt Spinler62011e22018-03-27 15:27:39 -0500307
308 auto values = policy::find(policy, testProperties);
309 ASSERT_EQ(std::get<policy::EIDField>(values), "DDDDDDDD");
310 ASSERT_EQ(std::get<policy::MsgField>(values), "Error DDDDDDDD");
311 }
312
Matt Spinler259e7272018-03-29 10:57:17 -0500313 // Use an FSI DEVICE_PATH from the AdditionalData property
Matt Spinler62011e22018-03-27 15:27:39 -0500314 {
Matt Spinler259e7272018-03-29 10:57:17 -0500315 std::vector<std::string> ad{"FOO=BAR"s,
316 "CALLOUT_DEVICE_PATH=/some/fsi/path"s};
317 DbusPropertyMap testProperties{
Matt Spinler62011e22018-03-27 15:27:39 -0500318 {"Message"s, Value{"xyz.openbmc_project.Error.Test4"s}},
Matt Spinler259e7272018-03-29 10:57:17 -0500319 {"AdditionalData"s, ad}};
Matt Spinler62011e22018-03-27 15:27:39 -0500320
321 auto values = policy::find(policy, testProperties);
322 ASSERT_EQ(std::get<policy::EIDField>(values), "EEEEEEEE");
323 ASSERT_EQ(std::get<policy::MsgField>(values), "Error EEEEEEEE");
324 }
325
Matt Spinler259e7272018-03-29 10:57:17 -0500326 // Use PROCEDURE from the AdditionalData property
Matt Spinler62011e22018-03-27 15:27:39 -0500327 {
Matt Spinler259e7272018-03-29 10:57:17 -0500328 std::vector<std::string> ad{"FOO=BAR"s, "PROCEDURE=109"s};
329 DbusPropertyMap testProperties{
Matt Spinler62011e22018-03-27 15:27:39 -0500330 {"Message"s, Value{"xyz.openbmc_project.Error.Test5"s}},
Matt Spinler259e7272018-03-29 10:57:17 -0500331 {"AdditionalData"s, ad}};
Matt Spinler62011e22018-03-27 15:27:39 -0500332
333 auto values = policy::find(policy, testProperties);
334 ASSERT_EQ(std::get<policy::EIDField>(values), "FFFFFFFF");
335 ASSERT_EQ(std::get<policy::MsgField>(values), "Error FFFFFFFF");
336 }
337
Matt Spinler259e7272018-03-29 10:57:17 -0500338 // Use RAIL_NAME from the AdditionalData property
Matt Spinler62011e22018-03-27 15:27:39 -0500339 {
Matt Spinler259e7272018-03-29 10:57:17 -0500340 std::vector<std::string> ad{"FOO=BAR"s, "RAIL_NAME=RAIL_5"s};
341 DbusPropertyMap testProperties{
Matt Spinler62011e22018-03-27 15:27:39 -0500342 {"Message"s, Value{"xyz.openbmc_project.Error.Test6"s}},
Matt Spinler259e7272018-03-29 10:57:17 -0500343 {"AdditionalData"s, ad}};
Matt Spinler62011e22018-03-27 15:27:39 -0500344
345 auto values = policy::find(policy, testProperties);
346 ASSERT_EQ(std::get<policy::EIDField>(values), "GGGGGGGG");
347 ASSERT_EQ(std::get<policy::MsgField>(values), "Error GGGGGGGG");
348 }
349
Matt Spinler259e7272018-03-29 10:57:17 -0500350 // Use INPUT_NAME from the AdditionalData property
Matt Spinler62011e22018-03-27 15:27:39 -0500351 {
Matt Spinler259e7272018-03-29 10:57:17 -0500352 std::vector<std::string> ad{"FOO=BAR"s, "INPUT_NAME=INPUT_42"s};
353 DbusPropertyMap testProperties{
Matt Spinler62011e22018-03-27 15:27:39 -0500354 {"Message"s, Value{"xyz.openbmc_project.Error.Test7"s}},
Matt Spinler259e7272018-03-29 10:57:17 -0500355 {"AdditionalData"s, ad}};
Matt Spinler62011e22018-03-27 15:27:39 -0500356
357 auto values = policy::find(policy, testProperties);
358 ASSERT_EQ(std::get<policy::EIDField>(values), "HHHHHHHH");
359 ASSERT_EQ(std::get<policy::MsgField>(values), "Error HHHHHHHH");
360 }
361
Matt Spinler259e7272018-03-29 10:57:17 -0500362 // Test not finding an entry.
Matt Spinler62011e22018-03-27 15:27:39 -0500363 {
Matt Spinler259e7272018-03-29 10:57:17 -0500364 DbusPropertyMap testProperties{{"Message"s, Value{"hello world"s}}};
Matt Spinler62011e22018-03-27 15:27:39 -0500365
366 auto values = policy::find(policy, testProperties);
367 ASSERT_EQ(std::get<policy::EIDField>(values), policy.defaultEID());
368 ASSERT_EQ(std::get<policy::MsgField>(values), policy.defaultMsg());
369 }
370
371 // Test that strange AdditionalData values don't break anything
372 {
Matt Spinler259e7272018-03-29 10:57:17 -0500373 std::vector<std::string> ad{"FOO"s, "INPUT_NAME="s};
374 DbusPropertyMap testProperties{
Matt Spinler62011e22018-03-27 15:27:39 -0500375 {"Message"s, Value{"xyz.openbmc_project.Error.Test7"s}},
Matt Spinler259e7272018-03-29 10:57:17 -0500376 {"AdditionalData"s, ad}};
Matt Spinler62011e22018-03-27 15:27:39 -0500377
378 auto values = policy::find(policy, testProperties);
379 ASSERT_EQ(std::get<policy::EIDField>(values), policy.defaultEID());
380 ASSERT_EQ(std::get<policy::MsgField>(values), policy.defaultMsg());
381 }
Matt Spinlerc57aa4b2018-09-28 10:32:24 -0500382
383 // Test a device path modifier match
384 {
385 std::vector<std::string> ad{"CALLOUT_DEVICE_PATH=/match/this/path"s};
386 DbusPropertyMap testProperties{
387 {"Message"s, Value{"xyz.openbmc_project.Error.Test8"s}},
388 {"AdditionalData"s, ad}};
389
390 auto values = policy::find(policy, testProperties);
391 ASSERT_EQ(std::get<policy::EIDField>(values), "IIIIIII");
392 ASSERT_EQ(std::get<policy::MsgField>(values), "Error IIIIIII");
393 }
394
395 // Test a predictive SEL matches on 'callout||Warning'
396 {
397 std::vector<std::string> ad{eSELBase + SEV_PREDICTIVE,
398 "CALLOUT_INVENTORY_PATH=/inventory/core0"s};
399 DbusPropertyMap testProperties{
400 {"Message"s, Value{"org.open_power.Host.Error.Event"s}},
401 {"AdditionalData"s, ad}};
402
403 auto values = policy::find(policy, testProperties);
404 ASSERT_EQ(std::get<policy::EIDField>(values), "JJJJJJJJ");
405 ASSERT_EQ(std::get<policy::MsgField>(values), "Error JJJJJJJJ");
406 }
407
408 // Test a recovered SEL matches on 'callout||Informational'
409 {
410 std::vector<std::string> ad{eSELBase + SEV_RECOVERED,
411 "CALLOUT_INVENTORY_PATH=/inventory/core1"s};
412 DbusPropertyMap testProperties{
413 {"Message"s, Value{"org.open_power.Host.Error.Event"s}},
414 {"AdditionalData"s, ad}};
415
416 auto values = policy::find(policy, testProperties);
417 ASSERT_EQ(std::get<policy::EIDField>(values), "KKKKKKKK");
418 ASSERT_EQ(std::get<policy::MsgField>(values), "Error KKKKKKKK");
419 }
420
421 // Test a critical severity matches on 'callout||Critical'
422 {
423 std::vector<std::string> ad{eSELBase + SEV_CRITICAL,
424 "CALLOUT_INVENTORY_PATH=/inventory/core2"s};
425 DbusPropertyMap testProperties{
426 {"Message"s, Value{"org.open_power.Host.Error.Event"s}},
427 {"AdditionalData"s, ad}};
428
429 auto values = policy::find(policy, testProperties);
430 ASSERT_EQ(std::get<policy::EIDField>(values), "LLLLLLLL");
431 ASSERT_EQ(std::get<policy::MsgField>(values), "Error LLLLLLLL");
432 }
433
434 // Test an unrecoverable SEL matches on 'callout||Critical'
435 {
436 std::vector<std::string> ad{eSELBase + SEV_UNRECOV,
437 "CALLOUT_INVENTORY_PATH=/inventory/core3"s};
438 DbusPropertyMap testProperties{
439 {"Message"s, Value{"org.open_power.Host.Error.Event"s}},
440 {"AdditionalData"s, ad}};
441
442 auto values = policy::find(policy, testProperties);
443 ASSERT_EQ(std::get<policy::EIDField>(values), "MMMMMMMM");
444 ASSERT_EQ(std::get<policy::MsgField>(values), "Error MMMMMMMM");
445 }
446
447 // Test a Diagnostic SEL matches on 'callout||Critical'
448 {
449 std::vector<std::string> ad{eSELBase + SEV_DIAG,
450 "CALLOUT_INVENTORY_PATH=/inventory/core4"s};
451 DbusPropertyMap testProperties{
452 {"Message"s, Value{"org.open_power.Host.Error.Event"s}},
453 {"AdditionalData"s, ad}};
454
455 auto values = policy::find(policy, testProperties);
456 ASSERT_EQ(std::get<policy::EIDField>(values), "NNNNNNNN");
457 ASSERT_EQ(std::get<policy::MsgField>(values), "Error NNNNNNNN");
458 }
459
460 // Test a short eSEL still matches the normal callout
461 {
462 std::vector<std::string> ad{eSELBase,
463 "CALLOUT_INVENTORY_PATH=/inventory/core5"s};
464 DbusPropertyMap testProperties{
465 {"Message"s, Value{"org.open_power.Host.Error.Event"s}},
466 {"AdditionalData"s, ad}};
467
468 auto values = policy::find(policy, testProperties);
469 ASSERT_EQ(std::get<policy::EIDField>(values), "OOOOOOOO");
470 ASSERT_EQ(std::get<policy::MsgField>(values), "Error OOOOOOOO");
471 }
472
473 // Test an eSEL with no UH section still matches a normal callout
474 {
475 std::vector<std::string> ad{noUHeSEL,
476 "CALLOUT_INVENTORY_PATH=/inventory/core5"s};
477 DbusPropertyMap testProperties{
478 {"Message"s, Value{"org.open_power.Host.Error.Event"s}},
479 {"AdditionalData"s, ad}};
480
481 auto values = policy::find(policy, testProperties);
482 ASSERT_EQ(std::get<policy::EIDField>(values), "OOOOOOOO");
483 ASSERT_EQ(std::get<policy::MsgField>(values), "Error OOOOOOOO");
484 }
485
486 // Test a bad severity is still considered critical (by design)
487 {
488 std::vector<std::string> ad{eSELBase + "ZZ",
489 "CALLOUT_INVENTORY_PATH=/inventory/core5"s};
490 DbusPropertyMap testProperties{
491 {"Message"s, Value{"org.open_power.Host.Error.Event"s}},
492 {"AdditionalData"s, ad}};
493
494 auto values = policy::find(policy, testProperties);
495 ASSERT_EQ(std::get<policy::EIDField>(values), "PPPPPPPP");
496 ASSERT_EQ(std::get<policy::MsgField>(values), "Error PPPPPPPP");
497 }
Matt Spinler62011e22018-03-27 15:27:39 -0500498}