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