1 /** 2 * Copyright © 2018 Intel 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 #define SD_JOURNAL_SUPPRESS_LOCATION 17 18 #include <systemd/sd-journal.h> 19 20 #include <ipmid/api.hpp> 21 #include <ipmid/message.hpp> 22 23 #include <stdexcept> 24 25 #include <gtest/gtest.h> 26 27 TEST(Payload, InputSize) 28 { 29 ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02}; 30 size_t input_size = i.size(); 31 ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i)); 32 ASSERT_EQ(input_size, p.size()); 33 } 34 35 TEST(Payload, OutputSize) 36 { 37 ipmi::message::Payload p; 38 ASSERT_EQ(0, p.size()); 39 ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02}; 40 p.pack(i); 41 ASSERT_EQ(i.size(), p.size()); 42 p.pack(i); 43 p.pack(i); 44 ASSERT_EQ(3 * i.size(), p.size()); 45 } 46 47 TEST(Payload, Resize) 48 { 49 ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02}; 50 ipmi::message::Payload p; 51 p.pack(i); 52 p.resize(16); 53 ASSERT_EQ(p.size(), 16); 54 } 55 56 TEST(Payload, Data) 57 { 58 ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02}; 59 ipmi::message::Payload p; 60 p.pack(i); 61 ASSERT_NE(nullptr, p.data()); 62 } 63 64 TEST(PayloadResponse, Append) 65 { 66 std::string s("0123456789abcdef"); 67 ipmi::message::Payload p; 68 p.append(s.data(), s.data() + s.size()); 69 ASSERT_EQ(s.size(), p.size()); 70 } 71 72 TEST(PayloadResponse, AppendDrain) 73 { 74 std::string s("0123456789abcdef"); 75 ipmi::message::Payload p; 76 bool b = true; 77 // first pack a lone bit 78 p.pack(b); 79 p.append(s.data(), s.data() + s.size()); 80 // append will 'drain' first, padding the lone bit into a full byte 81 ASSERT_EQ(s.size() + 1, p.size()); 82 } 83 84 TEST(PayloadResponse, AppendBits) 85 { 86 ipmi::message::Payload p; 87 p.appendBits(3, 0b101); 88 ASSERT_EQ(p.bitStream, 0b101); 89 p.appendBits(4, 0b1100); 90 ASSERT_EQ(p.bitStream, 0b1100101); 91 p.appendBits(1, 0b1); 92 ASSERT_EQ(p.bitStream, 0); 93 ASSERT_EQ(p.bitCount, 0); 94 // appended 8 bits, should be one byte 95 ASSERT_EQ(p.size(), 1); 96 ipmi::SecureBuffer k1 = {0b11100101}; 97 ASSERT_EQ(p.raw, k1); 98 p.appendBits(7, 0b1110111); 99 // appended 7 more bits, should still be one byte 100 ASSERT_EQ(p.size(), 1); 101 p.drain(); 102 // drain forces padding; should be two bytes now 103 ASSERT_EQ(p.size(), 2); 104 ipmi::SecureBuffer k2 = {0b11100101, 0b01110111}; 105 ASSERT_EQ(p.raw, k2); 106 } 107 108 TEST(PayloadResponse, Drain16Bits) 109 { 110 ipmi::message::Payload p; 111 p.bitStream = 0b1011010011001111; 112 p.bitCount = 16; 113 p.drain(); 114 ASSERT_EQ(p.size(), 2); 115 ASSERT_EQ(p.bitCount, 0); 116 ASSERT_EQ(p.bitStream, 0); 117 ipmi::SecureBuffer k1 = {0b11001111, 0b10110100}; 118 ASSERT_EQ(p.raw, k1); 119 } 120 121 TEST(PayloadResponse, Drain15Bits) 122 { 123 ipmi::message::Payload p; 124 p.bitStream = 0b101101001100111; 125 p.bitCount = 15; 126 p.drain(); 127 ASSERT_EQ(p.size(), 2); 128 ASSERT_EQ(p.bitCount, 0); 129 ASSERT_EQ(p.bitStream, 0); 130 ipmi::SecureBuffer k1 = {0b1100111, 0b1011010}; 131 ASSERT_EQ(p.raw, k1); 132 } 133 134 TEST(PayloadResponse, Drain15BitsWholeBytesOnly) 135 { 136 ipmi::message::Payload p; 137 p.bitStream = 0b101101001100111; 138 p.bitCount = 15; 139 p.drain(true); 140 // only the first whole byte should have been 'drained' into p.raw 141 ASSERT_EQ(p.size(), 1); 142 ASSERT_EQ(p.bitCount, 7); 143 ASSERT_EQ(p.bitStream, 0b1011010); 144 ipmi::SecureBuffer k1 = {0b1100111}; 145 ASSERT_EQ(p.raw, k1); 146 } 147 148 TEST(PayloadRequest, Pop) 149 { 150 ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02}; 151 ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i)); 152 const auto& [vb, ve] = p.pop<uint8_t>(4); 153 std::vector<uint8_t> v(vb, ve); 154 std::vector<uint8_t> k = {0xbf, 0x04, 0x86, 0x00}; 155 ASSERT_EQ(v, k); 156 } 157 158 TEST(PayloadRequest, FillBits) 159 { 160 ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02}; 161 ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i)); 162 p.fillBits(5); 163 ASSERT_FALSE(p.unpackError); 164 ASSERT_EQ(p.bitStream, 0xbf); 165 ASSERT_EQ(p.bitCount, 8); 166 // should still have 5 bits available, no change 167 p.fillBits(5); 168 ASSERT_FALSE(p.unpackError); 169 ASSERT_EQ(p.bitStream, 0xbf); 170 ASSERT_EQ(p.bitCount, 8); 171 // discard 5 bits (low order) 172 p.popBits(5); 173 // should add another byte into the stream (high order) 174 p.fillBits(5); 175 ASSERT_FALSE(p.unpackError); 176 ASSERT_EQ(p.bitStream, 0x25); 177 ASSERT_EQ(p.bitCount, 11); 178 } 179 180 TEST(PayloadRequest, FillBitsTooManyBits) 181 { 182 ipmi::SecureBuffer i = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 183 ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i)); 184 p.fillBits(72); 185 ASSERT_TRUE(p.unpackError); 186 } 187 188 TEST(PayloadRequest, FillBitsNotEnoughBytes) 189 { 190 ipmi::SecureBuffer i = {1, 2, 3, 4}; 191 ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i)); 192 p.fillBits(48); 193 ASSERT_TRUE(p.unpackError); 194 } 195 196 TEST(PayloadRequest, PopBits) 197 { 198 ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02}; 199 ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i)); 200 p.fillBits(4); 201 uint8_t v = p.popBits(4); 202 ASSERT_FALSE(p.unpackError); 203 ASSERT_EQ(p.bitStream, 0x0b); 204 ASSERT_EQ(p.bitCount, 4); 205 ASSERT_EQ(v, 0x0f); 206 } 207 208 TEST(PayloadRequest, PopBitsNoFillBits) 209 { 210 ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02}; 211 ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i)); 212 p.popBits(4); 213 ASSERT_TRUE(p.unpackError); 214 } 215 216 TEST(PayloadRequest, DiscardBits) 217 { 218 ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02}; 219 ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i)); 220 p.fillBits(5); 221 ASSERT_FALSE(p.unpackError); 222 ASSERT_EQ(p.bitStream, 0xbf); 223 ASSERT_EQ(p.bitCount, 8); 224 p.discardBits(); 225 ASSERT_FALSE(p.unpackError); 226 ASSERT_EQ(p.bitStream, 0); 227 ASSERT_EQ(p.bitCount, 0); 228 } 229 230 TEST(PayloadRequest, FullyUnpacked) 231 { 232 ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02}; 233 ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i)); 234 uint32_t v1; 235 p.unpack(v1); 236 // still one remaining byte 237 ASSERT_FALSE(p.fullyUnpacked()); 238 p.fillBits(3); 239 p.popBits(3); 240 // still five remaining bits 241 ASSERT_FALSE(p.fullyUnpacked()); 242 p.fillBits(5); 243 p.popBits(5); 244 // fully unpacked, should be no errors 245 ASSERT_TRUE(p.fullyUnpacked()); 246 p.fillBits(4); 247 // fullyUnpacked fails because an attempt to unpack too many bytes 248 ASSERT_FALSE(p.fullyUnpacked()); 249 } 250 251 TEST(PayloadRequest, ResetInternal) 252 { 253 ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02}; 254 ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i)); 255 p.fillBits(4); 256 p.unpackError = true; 257 p.reset(); 258 ASSERT_EQ(p.rawIndex, 0); 259 ASSERT_EQ(p.bitStream, 0); 260 ASSERT_EQ(p.bitCount, 0); 261 ASSERT_FALSE(p.unpackError); 262 } 263 264 TEST(PayloadRequest, ResetUsage) 265 { 266 // Payload.reset is used to rewind the unpacking to the initial 267 // state. This is needed so that OEM commands can unpack the group 268 // number or the IANA to determine which handler needs to be called 269 ipmi::SecureBuffer i = {0x04, 0x86}; 270 ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i)); 271 uint8_t v1; 272 // check that the number of bytes matches 273 ASSERT_EQ(p.unpack(v1), 0); 274 // check that the payload was not fully unpacked 275 ASSERT_FALSE(p.fullyUnpacked()); 276 uint8_t k1 = 0x04; 277 // check that the bytes were correctly unpacked (LSB first) 278 ASSERT_EQ(v1, k1); 279 // do a reset on the payload 280 p.reset(); 281 // unpack a uint16 282 uint16_t v2; 283 // check that the number of bytes matches 284 ASSERT_EQ(p.unpack(v2), 0); 285 // check that the payload was fully unpacked 286 ASSERT_TRUE(p.fullyUnpacked()); 287 uint16_t k2 = 0x8604; 288 // check that the bytes were correctly unpacked (LSB first) 289 ASSERT_EQ(v2, k2); 290 } 291 292 TEST(PayloadRequest, PartialPayload) 293 { 294 ipmi::SecureBuffer i = {0xbf, 0x04, 0x86, 0x00, 0x02}; 295 ipmi::message::Payload p(std::forward<ipmi::SecureBuffer>(i)); 296 uint8_t v1; 297 ipmi::message::Payload localPayload; 298 // check that the number of bytes matches 299 ASSERT_EQ(p.unpack(v1, localPayload), 0); 300 // check that the payload was partially unpacked and not in error 301 ASSERT_FALSE(p.fullyUnpacked()); 302 ASSERT_FALSE(p.unpackError); 303 // check that the 'extracted' payload is not fully unpacked 304 ASSERT_FALSE(localPayload.fullyUnpacked()); 305 uint8_t k1 = 0xbf; 306 // check that the bytes were correctly unpacked (LSB first) 307 ASSERT_EQ(v1, k1); 308 uint32_t v2; 309 // unpack using the 'extracted' payload 310 ASSERT_EQ(localPayload.unpack(v2), 0); 311 ASSERT_TRUE(localPayload.fullyUnpacked()); 312 uint32_t k2 = 0x02008604; 313 ASSERT_EQ(v2, k2); 314 } 315 316 std::vector<std::string> logs; 317 318 extern "C" 319 { 320 int sd_journal_send(const char* format, ...) 321 { 322 logs.push_back(format); 323 return 0; 324 } 325 326 int sd_journal_send_with_location(const char* /*file*/, const char* /*line*/, 327 const char* /*func*/, const char* format, ...) 328 { 329 logs.push_back(format); 330 return 0; 331 } 332 } 333 334 class PayloadLogging : public testing::Test 335 { 336 public: 337 void SetUp() 338 { 339 logs.clear(); 340 } 341 }; 342 343 TEST_F(PayloadLogging, TrailingOk) 344 { 345 { 346 ipmi::message::Payload p({1, 2}); 347 } 348 EXPECT_EQ(logs.size(), 0); 349 } 350 351 TEST_F(PayloadLogging, EnforcingUnchecked) 352 { 353 { 354 ipmi::message::Payload p({1, 2}); 355 p.trailingOk = false; 356 } 357 EXPECT_EQ(logs.size(), 1); 358 } 359 360 TEST_F(PayloadLogging, EnforcingUncheckedUnpacked) 361 { 362 { 363 ipmi::message::Payload p({1, 2}); 364 p.trailingOk = false; 365 uint8_t out; 366 p.unpack(out, out); 367 } 368 EXPECT_EQ(logs.size(), 1); 369 } 370 371 TEST_F(PayloadLogging, EnforcingUncheckedError) 372 { 373 { 374 ipmi::message::Payload p({1, 2}); 375 p.trailingOk = false; 376 uint32_t out; 377 p.unpack(out); 378 } 379 EXPECT_EQ(logs.size(), 0); 380 } 381 382 TEST_F(PayloadLogging, EnforcingChecked) 383 { 384 { 385 ipmi::message::Payload p({1, 2}); 386 p.trailingOk = false; 387 EXPECT_FALSE(p.fullyUnpacked()); 388 } 389 EXPECT_EQ(logs.size(), 0); 390 } 391 392 TEST_F(PayloadLogging, EnforcingCheckedUnpacked) 393 { 394 { 395 ipmi::message::Payload p({1, 2}); 396 p.trailingOk = false; 397 uint8_t out; 398 p.unpack(out, out); 399 EXPECT_TRUE(p.fullyUnpacked()); 400 } 401 EXPECT_EQ(logs.size(), 0); 402 } 403 404 TEST_F(PayloadLogging, EnforcingUnpackPayload) 405 { 406 { 407 ipmi::message::Payload p; 408 { 409 ipmi::message::Payload q({1, 2}); 410 q.trailingOk = false; 411 q.unpack(p); 412 } 413 EXPECT_EQ(logs.size(), 0); 414 } 415 EXPECT_EQ(logs.size(), 1); 416 } 417 418 TEST_F(PayloadLogging, EnforcingMove) 419 { 420 { 421 ipmi::message::Payload p; 422 { 423 ipmi::message::Payload q({1, 2}); 424 q.trailingOk = false; 425 p = std::move(q); 426 } 427 EXPECT_EQ(logs.size(), 0); 428 } 429 EXPECT_EQ(logs.size(), 1); 430 } 431 432 TEST_F(PayloadLogging, EnforcingException) 433 { 434 try 435 { 436 ipmi::message::Payload p({1, 2}); 437 p.trailingOk = false; 438 throw std::runtime_error("test"); 439 } 440 catch (...) 441 {} 442 EXPECT_EQ(logs.size(), 0); 443 } 444