1 /** 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 */ 16 #include <fstream> 17 #include <gtest/gtest.h> 18 #include <experimental/filesystem> 19 #include "policy_table.hpp" 20 #include "policy_find.hpp" 21 22 using namespace ibm::logging; 23 namespace fs = std::experimental::filesystem; 24 25 static constexpr auto json = R"( 26 [ 27 { 28 "dtls":[ 29 { 30 "CEID":"ABCD1234", 31 "mod":"", 32 "msg":"Error ABCD1234" 33 } 34 ], 35 "err":"xyz.openbmc_project.Error.Test1" 36 }, 37 38 { 39 "dtls":[ 40 { 41 "CEID":"XYZ222", 42 "mod":"", 43 "msg":"Error XYZ222" 44 } 45 ], 46 "err":"xyz.openbmc_project.Error.Test2" 47 }, 48 49 { 50 "dtls":[ 51 { 52 "CEID":"AAAAAA", 53 "mod":"mod1", 54 "msg":"Error AAAAAA" 55 }, 56 { 57 "CEID":"BBBBBB", 58 "mod":"mod2", 59 "msg":"Error BBBBBB" 60 }, 61 { 62 "CEID":"CCCCCC", 63 "mod":"mod3", 64 "msg":"Error CCCCCC" 65 } 66 ], 67 "err":"xyz.openbmc_project.Error.Test3" 68 }, 69 70 { 71 "dtls":[ 72 { 73 "CEID":"DDDDDDDD", 74 "mod":"I2C", 75 "msg":"Error DDDDDDDD" 76 }, 77 { 78 "CEID":"EEEEEEEE", 79 "mod":"FSI", 80 "msg":"Error EEEEEEEE" 81 } 82 ], 83 "err":"xyz.openbmc_project.Error.Test4" 84 }, 85 86 { 87 "dtls":[ 88 { 89 "CEID":"FFFFFFFF", 90 "mod":"6D", 91 "msg":"Error FFFFFFFF" 92 } 93 ], 94 95 "err":"xyz.openbmc_project.Error.Test5" 96 }, 97 { 98 "dtls":[ 99 { 100 "CEID":"GGGGGGGG", 101 "mod":"RAIL_5", 102 "msg":"Error GGGGGGGG" 103 } 104 ], 105 106 "err":"xyz.openbmc_project.Error.Test6" 107 }, 108 { 109 "dtls":[ 110 { 111 "CEID":"HHHHHHHH", 112 "mod":"INPUT_42", 113 "msg":"Error HHHHHHHH" 114 } 115 ], 116 "err":"xyz.openbmc_project.Error.Test7" 117 } 118 ])"; 119 120 /** 121 * Helper class to write the above json to a file and then 122 * remove it when the tests are over. 123 */ 124 class PolicyTableTest : public ::testing::Test 125 { 126 protected: 127 virtual void SetUp() 128 { 129 char dir[] = {"./jsonTestXXXXXX"}; 130 131 jsonDir = mkdtemp(dir); 132 jsonFile = jsonDir / "policy.json"; 133 134 std::ofstream f{jsonFile}; 135 f << json; 136 } 137 138 virtual void TearDown() 139 { 140 fs::remove_all(jsonDir); 141 } 142 143 fs::path jsonDir; 144 fs::path jsonFile; 145 }; 146 147 /** 148 * Test finding entries in the policy table 149 */ 150 TEST_F(PolicyTableTest, TestTable) 151 { 152 policy::Table policy{jsonFile}; 153 ASSERT_EQ(policy.isLoaded(), true); 154 155 //////////////////////////////////// 156 // Basic search, no modifier 157 std::string err{"xyz.openbmc_project.Error.Test2"}; 158 std::string mod; 159 160 auto details = policy.find(err, mod); 161 ASSERT_EQ(static_cast<bool>(details), true); 162 if (details) 163 { 164 ASSERT_EQ((*details).get().ceid, "XYZ222"); 165 ASSERT_EQ((*details).get().msg, "Error XYZ222"); 166 } 167 168 ///////////////////////////////////// 169 // Not found 170 err = "foo"; 171 details = policy.find(err, mod); 172 ASSERT_EQ(static_cast<bool>(details), false); 173 174 ///////////////////////////////////// 175 // Test with a modifier 176 err = "xyz.openbmc_project.Error.Test3"; 177 mod = "mod3"; 178 179 details = policy.find(err, mod); 180 ASSERT_EQ(static_cast<bool>(details), true); 181 if (details) 182 { 183 ASSERT_EQ((*details).get().ceid, "CCCCCC"); 184 ASSERT_EQ((*details).get().msg, "Error CCCCCC"); 185 } 186 } 187 188 /** 189 * Test policy::find() that uses the data from a property 190 * map to find entries in the policy table. 191 */ 192 TEST_F(PolicyTableTest, TestFinder) 193 { 194 using namespace std::literals::string_literals; 195 196 policy::Table policy{jsonFile}; 197 ASSERT_EQ(policy.isLoaded(), true); 198 199 // A basic search with no modifier 200 { 201 DbusPropertyMap testProperties{ 202 {"Message"s, Value{"xyz.openbmc_project.Error.Test1"s}}}; 203 204 auto values = policy::find(policy, testProperties); 205 ASSERT_EQ(std::get<policy::EIDField>(values), "ABCD1234"); 206 ASSERT_EQ(std::get<policy::MsgField>(values), "Error ABCD1234"); 207 } 208 209 // Use CALLOUT_INVENTORY_PATH from the AdditionalData property 210 { 211 std::vector<std::string> ad{"FOO=BAR"s, "CALLOUT_INVENTORY_PATH=mod2"s}; 212 DbusPropertyMap testProperties{ 213 {"Message"s, Value{"xyz.openbmc_project.Error.Test3"s}}, 214 {"AdditionalData"s, ad}}; 215 216 auto values = policy::find(policy, testProperties); 217 ASSERT_EQ(std::get<policy::EIDField>(values), "BBBBBB"); 218 ASSERT_EQ(std::get<policy::MsgField>(values), "Error BBBBBB"); 219 } 220 221 // Use an I2C DEVICE_PATH from the AdditionalData property 222 { 223 std::vector<std::string> ad{"FOO=BAR"s, 224 "CALLOUT_DEVICE_PATH=/some/i2c/path"s}; 225 DbusPropertyMap testProperties{ 226 {"Message"s, Value{"xyz.openbmc_project.Error.Test4"s}}, 227 {"AdditionalData"s, ad}}; 228 229 auto values = policy::find(policy, testProperties); 230 ASSERT_EQ(std::get<policy::EIDField>(values), "DDDDDDDD"); 231 ASSERT_EQ(std::get<policy::MsgField>(values), "Error DDDDDDDD"); 232 } 233 234 // Use an FSI DEVICE_PATH from the AdditionalData property 235 { 236 std::vector<std::string> ad{"FOO=BAR"s, 237 "CALLOUT_DEVICE_PATH=/some/fsi/path"s}; 238 DbusPropertyMap testProperties{ 239 {"Message"s, Value{"xyz.openbmc_project.Error.Test4"s}}, 240 {"AdditionalData"s, ad}}; 241 242 auto values = policy::find(policy, testProperties); 243 ASSERT_EQ(std::get<policy::EIDField>(values), "EEEEEEEE"); 244 ASSERT_EQ(std::get<policy::MsgField>(values), "Error EEEEEEEE"); 245 } 246 247 // Use PROCEDURE from the AdditionalData property 248 { 249 std::vector<std::string> ad{"FOO=BAR"s, "PROCEDURE=109"s}; 250 DbusPropertyMap testProperties{ 251 {"Message"s, Value{"xyz.openbmc_project.Error.Test5"s}}, 252 {"AdditionalData"s, ad}}; 253 254 auto values = policy::find(policy, testProperties); 255 ASSERT_EQ(std::get<policy::EIDField>(values), "FFFFFFFF"); 256 ASSERT_EQ(std::get<policy::MsgField>(values), "Error FFFFFFFF"); 257 } 258 259 // Use RAIL_NAME from the AdditionalData property 260 { 261 std::vector<std::string> ad{"FOO=BAR"s, "RAIL_NAME=RAIL_5"s}; 262 DbusPropertyMap testProperties{ 263 {"Message"s, Value{"xyz.openbmc_project.Error.Test6"s}}, 264 {"AdditionalData"s, ad}}; 265 266 auto values = policy::find(policy, testProperties); 267 ASSERT_EQ(std::get<policy::EIDField>(values), "GGGGGGGG"); 268 ASSERT_EQ(std::get<policy::MsgField>(values), "Error GGGGGGGG"); 269 } 270 271 // Use INPUT_NAME from the AdditionalData property 272 { 273 std::vector<std::string> ad{"FOO=BAR"s, "INPUT_NAME=INPUT_42"s}; 274 DbusPropertyMap testProperties{ 275 {"Message"s, Value{"xyz.openbmc_project.Error.Test7"s}}, 276 {"AdditionalData"s, ad}}; 277 278 auto values = policy::find(policy, testProperties); 279 ASSERT_EQ(std::get<policy::EIDField>(values), "HHHHHHHH"); 280 ASSERT_EQ(std::get<policy::MsgField>(values), "Error HHHHHHHH"); 281 } 282 283 // Test not finding an entry. 284 { 285 DbusPropertyMap testProperties{{"Message"s, Value{"hello world"s}}}; 286 287 auto values = policy::find(policy, testProperties); 288 ASSERT_EQ(std::get<policy::EIDField>(values), policy.defaultEID()); 289 ASSERT_EQ(std::get<policy::MsgField>(values), policy.defaultMsg()); 290 } 291 292 // Test that strange AdditionalData values don't break anything 293 { 294 std::vector<std::string> ad{"FOO"s, "INPUT_NAME="s}; 295 DbusPropertyMap testProperties{ 296 {"Message"s, Value{"xyz.openbmc_project.Error.Test7"s}}, 297 {"AdditionalData"s, ad}}; 298 299 auto values = policy::find(policy, testProperties); 300 ASSERT_EQ(std::get<policy::EIDField>(values), policy.defaultEID()); 301 ASSERT_EQ(std::get<policy::MsgField>(values), policy.defaultMsg()); 302 } 303 } 304