1 #include "common/bios_utils.hpp" 2 #include "common/test/mocked_utils.hpp" 3 #include "libpldmresponder/bios_config.hpp" 4 #include "libpldmresponder/bios_string_attribute.hpp" 5 #include "mocked_bios.hpp" 6 7 #include <nlohmann/json.hpp> 8 9 #include <fstream> 10 #include <memory> 11 12 #include <gmock/gmock.h> 13 #include <gtest/gtest.h> 14 15 using namespace pldm::bios::utils; 16 using namespace pldm::responder::bios; 17 using namespace pldm::utils; 18 19 using ::testing::_; 20 using ::testing::ElementsAreArray; 21 using ::testing::Throw; 22 23 class TestBIOSConfig : public ::testing::Test 24 { 25 public: 26 static void SetUpTestCase() // will execute once at the begining of all 27 // TestBIOSConfig objects 28 { 29 char tmpdir[] = "/tmp/BIOSTables.XXXXXX"; 30 tableDir = fs::path(mkdtemp(tmpdir)); 31 32 std::vector<fs::path> paths = { 33 "./bios_jsons/string_attrs.json", 34 "./bios_jsons/integer_attrs.json", 35 "./bios_jsons/enum_attrs.json", 36 }; 37 38 for (auto& path : paths) 39 { 40 std::ifstream file; 41 file.open(path); 42 auto j = Json::parse(file); 43 jsons.emplace_back(j); 44 } 45 } 46 47 std::optional<Json> findJsonEntry(const std::string& name) 48 { 49 for (auto& json : jsons) 50 { 51 auto entries = json.at("entries"); 52 for (auto& entry : entries) 53 { 54 auto n = entry.at("attribute_name").get<std::string>(); 55 if (n == name) 56 { 57 return entry; 58 } 59 } 60 } 61 return std::nullopt; 62 } 63 64 static void TearDownTestCase() // will be executed once at th end of all 65 // TestBIOSConfig objects 66 { 67 fs::remove_all(tableDir); 68 } 69 70 static fs::path tableDir; 71 static std::vector<Json> jsons; 72 }; 73 74 fs::path TestBIOSConfig::tableDir; 75 std::vector<Json> TestBIOSConfig::jsons; 76 77 TEST_F(TestBIOSConfig, buildTablesTest) 78 { 79 MockdBusHandler dbusHandler; 80 81 ON_CALL(dbusHandler, getDbusPropertyVariant(_, _, _)) 82 .WillByDefault(Throw(std::exception())); 83 84 BIOSConfig biosConfig("./bios_jsons", tableDir.c_str(), &dbusHandler, 0, 0, 85 nullptr, nullptr); 86 biosConfig.buildTables(); 87 88 auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE); 89 auto attrTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_TABLE); 90 auto attrValueTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 91 92 EXPECT_TRUE(stringTable); 93 EXPECT_TRUE(attrTable); 94 EXPECT_TRUE(attrValueTable); 95 96 std::set<std::string> expectedStrings = {"HMCManagedState", 97 "On", 98 "Off", 99 "FWBootSide", 100 "Perm", 101 "Temp", 102 "InbandCodeUpdate", 103 "Allowed", 104 "NotAllowed", 105 "CodeUpdatePolicy", 106 "Concurrent", 107 "Disruptive", 108 "VDD_AVSBUS_RAIL", 109 "SBE_IMAGE_MINIMUM_VALID_ECS", 110 "INTEGER_INVALID_CASE", 111 "str_example1", 112 "str_example2", 113 "str_example3"}; 114 std::set<std::string> strings; 115 for (auto entry : BIOSTableIter<PLDM_BIOS_STRING_TABLE>( 116 stringTable->data(), stringTable->size())) 117 { 118 auto str = table::string::decodeString(entry); 119 strings.emplace(str); 120 } 121 122 EXPECT_EQ(strings, expectedStrings); 123 124 BIOSStringTable biosStringTable(*stringTable); 125 126 for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(attrTable->data(), 127 attrTable->size())) 128 { 129 auto header = table::attribute::decodeHeader(entry); 130 auto attrName = biosStringTable.findString(header.stringHandle); 131 auto jsonEntry = findJsonEntry(attrName); 132 EXPECT_TRUE(jsonEntry); 133 switch (header.attrType) 134 { 135 case PLDM_BIOS_STRING: 136 case PLDM_BIOS_STRING_READ_ONLY: 137 { 138 auto stringField = table::attribute::decodeStringEntry(entry); 139 auto stringType = BIOSStringAttribute::strTypeMap.at( 140 jsonEntry->at("string_type").get<std::string>()); 141 EXPECT_EQ(stringField.stringType, 142 static_cast<uint8_t>(stringType)); 143 144 EXPECT_EQ( 145 stringField.minLength, 146 jsonEntry->at("minimum_string_length").get<uint16_t>()); 147 EXPECT_EQ( 148 stringField.maxLength, 149 jsonEntry->at("maximum_string_length").get<uint16_t>()); 150 EXPECT_EQ( 151 stringField.defLength, 152 jsonEntry->at("default_string_length").get<uint16_t>()); 153 EXPECT_EQ(stringField.defString, 154 jsonEntry->at("default_string").get<std::string>()); 155 break; 156 } 157 case PLDM_BIOS_INTEGER: 158 case PLDM_BIOS_INTEGER_READ_ONLY: 159 { 160 auto integerField = table::attribute::decodeIntegerEntry(entry); 161 EXPECT_EQ(integerField.lowerBound, 162 jsonEntry->at("lower_bound").get<uint64_t>()); 163 EXPECT_EQ(integerField.upperBound, 164 jsonEntry->at("upper_bound").get<uint64_t>()); 165 EXPECT_EQ(integerField.scalarIncrement, 166 jsonEntry->at("scalar_increment").get<uint32_t>()); 167 EXPECT_EQ(integerField.defaultValue, 168 jsonEntry->at("default_value").get<uint64_t>()); 169 break; 170 } 171 case PLDM_BIOS_ENUMERATION: 172 case PLDM_BIOS_ENUMERATION_READ_ONLY: 173 { 174 auto [pvHdls, 175 defInds] = table::attribute::decodeEnumEntry(entry); 176 auto possibleValues = jsonEntry->at("possible_values") 177 .get<std::vector<std::string>>(); 178 std::vector<std::string> strings; 179 for (auto pv : pvHdls) 180 { 181 auto s = biosStringTable.findString(pv); 182 strings.emplace_back(s); 183 } 184 EXPECT_EQ(strings, possibleValues); 185 EXPECT_EQ(defInds.size(), 1); 186 187 auto defValue = biosStringTable.findString(pvHdls[defInds[0]]); 188 auto defaultValues = jsonEntry->at("default_values") 189 .get<std::vector<std::string>>(); 190 EXPECT_EQ(defValue, defaultValues[0]); 191 192 break; 193 } 194 default: 195 EXPECT_TRUE(false); 196 break; 197 } 198 } 199 200 for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>( 201 attrValueTable->data(), attrValueTable->size())) 202 { 203 auto header = table::attribute_value::decodeHeader(entry); 204 auto attrEntry = table::attribute::findByHandle(*attrTable, 205 header.attrHandle); 206 auto attrHeader = table::attribute::decodeHeader(attrEntry); 207 auto attrName = biosStringTable.findString(attrHeader.stringHandle); 208 auto jsonEntry = findJsonEntry(attrName); 209 EXPECT_TRUE(jsonEntry); 210 switch (header.attrType) 211 { 212 case PLDM_BIOS_STRING: 213 case PLDM_BIOS_STRING_READ_ONLY: 214 { 215 auto value = table::attribute_value::decodeStringEntry(entry); 216 auto defValue = 217 jsonEntry->at("default_string").get<std::string>(); 218 EXPECT_EQ(value, defValue); 219 break; 220 } 221 case PLDM_BIOS_INTEGER: 222 case PLDM_BIOS_INTEGER_READ_ONLY: 223 { 224 auto value = table::attribute_value::decodeIntegerEntry(entry); 225 auto defValue = jsonEntry->at("default_value").get<uint64_t>(); 226 EXPECT_EQ(value, defValue); 227 break; 228 } 229 case PLDM_BIOS_ENUMERATION: 230 case PLDM_BIOS_ENUMERATION_READ_ONLY: 231 { 232 auto indices = table::attribute_value::decodeEnumEntry(entry); 233 EXPECT_EQ(indices.size(), 1); 234 auto possibleValues = jsonEntry->at("possible_values") 235 .get<std::vector<std::string>>(); 236 237 auto defValues = jsonEntry->at("default_values") 238 .get<std::vector<std::string>>(); 239 EXPECT_EQ(possibleValues[indices[0]], defValues[0]); 240 break; 241 } 242 default: 243 EXPECT_TRUE(false); 244 break; 245 } 246 } 247 } 248 249 TEST_F(TestBIOSConfig, setAttrValue) 250 { 251 MockdBusHandler dbusHandler; 252 253 BIOSConfig biosConfig("./bios_jsons", tableDir.c_str(), &dbusHandler, 0, 0, 254 nullptr, nullptr); 255 biosConfig.removeTables(); 256 biosConfig.buildTables(); 257 258 auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE); 259 auto attrTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_TABLE); 260 261 BIOSStringTable biosStringTable(*stringTable); 262 BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter(attrTable->data(), 263 attrTable->size()); 264 auto stringHandle = biosStringTable.findHandle("str_example1"); 265 uint16_t attrHandle{}; 266 267 for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(attrTable->data(), 268 attrTable->size())) 269 { 270 auto header = table::attribute::decodeHeader(entry); 271 if (header.stringHandle == stringHandle) 272 { 273 attrHandle = header.attrHandle; 274 break; 275 } 276 } 277 278 EXPECT_NE(attrHandle, 0); 279 280 std::vector<uint8_t> attrValueEntry{ 281 0, 0, /* attr handle */ 282 1, /* attr type string read-write */ 283 4, 0, /* current string length */ 284 'a', 'b', 'c', 'd', /* defaut value string handle index */ 285 }; 286 287 attrValueEntry[0] = attrHandle & 0xff; 288 attrValueEntry[1] = (attrHandle >> 8) & 0xff; 289 290 DBusMapping dbusMapping{"/xyz/abc/def", 291 "xyz.openbmc_project.str_example1.value", 292 "Str_example1", "string"}; 293 PropertyValue value = std::string("abcd"); 294 EXPECT_CALL(dbusHandler, setDbusProperty(dbusMapping, value)).Times(1); 295 296 auto rc = biosConfig.setAttrValue(attrValueEntry.data(), 297 attrValueEntry.size(), false); 298 EXPECT_EQ(rc, PLDM_SUCCESS); 299 300 auto attrValueTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE); 301 auto findEntry = 302 [&attrValueTable]( 303 uint16_t handle) -> const pldm_bios_attr_val_table_entry* { 304 for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>( 305 attrValueTable->data(), attrValueTable->size())) 306 { 307 auto [attrHandle, _] = table::attribute_value::decodeHeader(entry); 308 if (attrHandle == handle) 309 return entry; 310 } 311 return nullptr; 312 }; 313 314 auto entry = findEntry(attrHandle); 315 EXPECT_NE(entry, nullptr); 316 317 auto p = reinterpret_cast<const uint8_t*>(entry); 318 EXPECT_THAT(std::vector<uint8_t>(p, p + attrValueEntry.size()), 319 ElementsAreArray(attrValueEntry)); 320 } 321