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