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*/, 327 const char* /*line*/, 328 const char* /*func*/, const char* format, 329 ...) 330 { 331 logs.push_back(format); 332 return 0; 333 } 334 } 335 336 class PayloadLogging : public testing::Test 337 { 338 public: 339 void SetUp() 340 { 341 logs.clear(); 342 } 343 }; 344 345 TEST_F(PayloadLogging, TrailingOk) 346 { 347 { 348 ipmi::message::Payload p({1, 2}); 349 } 350 EXPECT_EQ(logs.size(), 0); 351 } 352 353 TEST_F(PayloadLogging, EnforcingUnchecked) 354 { 355 { 356 ipmi::message::Payload p({1, 2}); 357 p.trailingOk = false; 358 } 359 EXPECT_EQ(logs.size(), 1); 360 } 361 362 TEST_F(PayloadLogging, EnforcingUncheckedUnpacked) 363 { 364 { 365 ipmi::message::Payload p({1, 2}); 366 p.trailingOk = false; 367 uint8_t out; 368 p.unpack(out, out); 369 } 370 EXPECT_EQ(logs.size(), 1); 371 } 372 373 TEST_F(PayloadLogging, EnforcingUncheckedError) 374 { 375 { 376 ipmi::message::Payload p({1, 2}); 377 p.trailingOk = false; 378 uint32_t out; 379 p.unpack(out); 380 } 381 EXPECT_EQ(logs.size(), 0); 382 } 383 384 TEST_F(PayloadLogging, EnforcingChecked) 385 { 386 { 387 ipmi::message::Payload p({1, 2}); 388 p.trailingOk = false; 389 EXPECT_FALSE(p.fullyUnpacked()); 390 } 391 EXPECT_EQ(logs.size(), 0); 392 } 393 394 TEST_F(PayloadLogging, EnforcingCheckedUnpacked) 395 { 396 { 397 ipmi::message::Payload p({1, 2}); 398 p.trailingOk = false; 399 uint8_t out; 400 p.unpack(out, out); 401 EXPECT_TRUE(p.fullyUnpacked()); 402 } 403 EXPECT_EQ(logs.size(), 0); 404 } 405 406 TEST_F(PayloadLogging, EnforcingUnpackPayload) 407 { 408 { 409 ipmi::message::Payload p; 410 { 411 ipmi::message::Payload q({1, 2}); 412 q.trailingOk = false; 413 q.unpack(p); 414 } 415 EXPECT_EQ(logs.size(), 0); 416 } 417 EXPECT_EQ(logs.size(), 1); 418 } 419 420 TEST_F(PayloadLogging, EnforcingMove) 421 { 422 { 423 ipmi::message::Payload p; 424 { 425 ipmi::message::Payload q({1, 2}); 426 q.trailingOk = false; 427 p = std::move(q); 428 } 429 EXPECT_EQ(logs.size(), 0); 430 } 431 EXPECT_EQ(logs.size(), 1); 432 } 433 434 TEST_F(PayloadLogging, EnforcingException) 435 { 436 try 437 { 438 ipmi::message::Payload p({1, 2}); 439 p.trailingOk = false; 440 throw std::runtime_error("test"); 441 } 442 catch (...) 443 {} 444 EXPECT_EQ(logs.size(), 0); 445 } 446