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