blob: 431a34b509a013cef7db40ed2f345af28af8ba57 [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>
22
23#include <gtest/gtest.h>
24
25TEST(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
33TEST(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
45TEST(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
54TEST(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
62TEST(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
70TEST(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
82TEST(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
106TEST(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
119TEST(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
132TEST(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
146TEST(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
156TEST(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
178TEST(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
186TEST(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
194TEST(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
206TEST(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
214TEST(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
228TEST(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
249TEST(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
262TEST(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
290TEST(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}
William A. Kennington III51694c22019-04-24 01:44:44 -0700313
314std::vector<std::string> logs;
315
316extern "C" {
317int sd_journal_send(const char* format, ...)
318{
319 logs.push_back(format);
320 return 0;
321}
322
323int 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
331class PayloadLogging : public testing::Test
332{
333 public:
334 void SetUp()
335 {
336 logs.clear();
337 }
338};
339
340TEST_F(PayloadLogging, TrailingOk)
341{
342 {
343 ipmi::message::Payload p({1, 2});
344 }
345 EXPECT_EQ(logs.size(), 0);
346}
347
348TEST_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
357TEST_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
368TEST_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
379TEST_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
389TEST_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
401TEST_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
415TEST_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}