1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright 2019 IBM Corporation
3 
4 #include "extensions/openpower-pels/callouts.hpp"
5 #include "pel_utils.hpp"
6 
7 #include <format>
8 
9 #include <gtest/gtest.h>
10 
11 using namespace openpower::pels;
12 using namespace openpower::pels::src;
13 
TEST(CalloutsTest,UnflattenFlattenTest)14 TEST(CalloutsTest, UnflattenFlattenTest)
15 {
16     std::vector<uint8_t> data{0xC0, 0x00, 0x00,
17                               0x00}; // ID, flags, length in words
18 
19     // Add 2 callouts
20     auto callout = srcDataFactory(TestSRCType::calloutStructureA);
21     data.insert(data.end(), callout.begin(), callout.end());
22 
23     callout = srcDataFactory(TestSRCType::calloutStructureB);
24     data.insert(data.end(), callout.begin(), callout.end());
25 
26     Stream stream{data};
27 
28     // Set the actual word length value at offset 2
29     uint16_t wordLength = data.size() / 4;
30     stream.offset(2);
31     stream << wordLength;
32     stream.offset(0);
33 
34     Callouts callouts{stream};
35 
36     EXPECT_EQ(callouts.flattenedSize(), data.size());
37     EXPECT_EQ(callouts.callouts().size(), 2);
38 
39     // spot check that each callout has the right substructures
40     EXPECT_TRUE(callouts.callouts().front()->fruIdentity());
41     EXPECT_FALSE(callouts.callouts().front()->pceIdentity());
42     EXPECT_FALSE(callouts.callouts().front()->mru());
43 
44     EXPECT_TRUE(callouts.callouts().back()->fruIdentity());
45     EXPECT_TRUE(callouts.callouts().back()->pceIdentity());
46     EXPECT_TRUE(callouts.callouts().back()->mru());
47 
48     // Flatten
49     std::vector<uint8_t> newData;
50     Stream newStream{newData};
51 
52     callouts.flatten(newStream);
53     EXPECT_EQ(data, newData);
54 }
55 
TEST(CalloutsTest,BadDataTest)56 TEST(CalloutsTest, BadDataTest)
57 {
58     // Start out with a valid 2 callout object, then truncate it.
59     std::vector<uint8_t> data{0xC0, 0x00, 0x00,
60                               0x00}; // ID, flags, length in words
61 
62     // Add 2 callouts
63     auto callout = srcDataFactory(TestSRCType::calloutStructureA);
64     data.insert(data.end(), callout.begin(), callout.end());
65 
66     callout = srcDataFactory(TestSRCType::calloutStructureB);
67     data.insert(data.end(), callout.begin(), callout.end());
68 
69     Stream stream{data};
70 
71     // Set the actual word length value at offset 2
72     uint16_t wordLength = data.size() / 4;
73     stream.offset(2);
74     stream << wordLength;
75     stream.offset(0);
76 
77     // Shorten the data by an arbitrary amount so unflattening goes awry.
78     data.resize(data.size() - 37);
79 
80     EXPECT_THROW(Callouts callouts{stream}, std::out_of_range);
81 }
82 
TEST(CalloutsTest,TestAddCallouts)83 TEST(CalloutsTest, TestAddCallouts)
84 {
85     Callouts callouts;
86 
87     // Empty Callouts size
88     size_t lastSize = 4;
89 
90     for (size_t i = 0; i < maxNumberOfCallouts; i++)
91     {
92         auto loc = std::format("U1-P{}", i);
93         auto callout = std::make_unique<Callout>(
94             CalloutPriority::high, loc, "1234567", "ABCD", "123456789ABC");
95         auto calloutSize = callout->flattenedSize();
96 
97         callouts.addCallout(std::move(callout));
98 
99         EXPECT_EQ(callouts.flattenedSize(), lastSize + calloutSize);
100 
101         lastSize = callouts.flattenedSize();
102 
103         EXPECT_EQ(callouts.callouts().size(), i + 1);
104     }
105 
106     // Try to add an 11th callout.  Shouldn't work
107 
108     auto callout = std::make_unique<Callout>(CalloutPriority::high, "U1-P1",
109                                              "1234567", "ABCD", "123456789ABC");
110     callouts.addCallout(std::move(callout));
111 
112     EXPECT_EQ(callouts.callouts().size(), maxNumberOfCallouts);
113 }
114 
TEST(CalloutsTest,TestSortCallouts)115 TEST(CalloutsTest, TestSortCallouts)
116 {
117     Callouts callouts;
118 
119     // Add  callouts with different priorities to test sorting in descending
120     // order
121 
122     auto c0 = std::make_unique<Callout>(CalloutPriority::high, "U1-P1",
123                                         "1234567", "ABC", "123456789ABC");
124 
125     callouts.addCallout(std::move(c0));
126 
127     auto c1 = std::make_unique<Callout>(CalloutPriority::medium, "U1-P2",
128                                         "1234567", "ABCD", "123456789ABC");
129 
130     callouts.addCallout(std::move(c1));
131 
132     auto c2 = std::make_unique<Callout>(CalloutPriority::low, "U1-P3",
133                                         "1234567", "ABCDE", "123456789ABC");
134 
135     callouts.addCallout(std::move(c2));
136 
137     auto c3 = std::make_unique<Callout>(CalloutPriority::high, "U1-P4",
138                                         "1234567", "ABCDE1", "123456789ABC");
139 
140     callouts.addCallout(std::move(c3));
141 
142     auto c4 = std::make_unique<Callout>(CalloutPriority::high, "U1-P5",
143                                         "1234567", "ABCDE2", "123456789ABC");
144 
145     callouts.addCallout(std::move(c4));
146 
147     auto c5 = std::make_unique<Callout>(CalloutPriority::low, "U1-P6",
148                                         "1234567", "ABCDE2", "123456789ABC");
149 
150     callouts.addCallout(std::move(c5));
151 
152     auto c6 = std::make_unique<Callout>(CalloutPriority::medium, "U1-P7",
153                                         "1234567", "ABCD2", "123456789ABC");
154 
155     callouts.addCallout(std::move(c6));
156 
157     auto c7 = std::make_unique<Callout>(CalloutPriority::mediumGroupA, "U1-P8",
158                                         "1234567", "ABCDE3", "123456789ABC");
159 
160     callouts.addCallout(std::move(c7));
161 
162     auto c8 = std::make_unique<Callout>(CalloutPriority::mediumGroupC, "U1-P9",
163                                         "1234567", "ABCDE4", "123456789ABC");
164 
165     callouts.addCallout(std::move(c8));
166 
167     auto c9 = std::make_unique<Callout>(CalloutPriority::low, "U1-P10",
168                                         "1234567", "ABCDE3", "123456789ABC");
169 
170     callouts.addCallout(std::move(c9));
171 
172     const auto& calloutObjects = callouts.callouts();
173     EXPECT_EQ(calloutObjects[0]->locationCode(), "U1-P1");
174     EXPECT_EQ(calloutObjects[0]->priority(), 'H');
175     EXPECT_EQ(calloutObjects[1]->locationCode(), "U1-P4");
176     EXPECT_EQ(calloutObjects[1]->priority(), 'H');
177     EXPECT_EQ(calloutObjects[2]->locationCode(), "U1-P5");
178     EXPECT_EQ(calloutObjects[2]->priority(), 'H');
179     EXPECT_EQ(calloutObjects[3]->locationCode(), "U1-P2");
180     EXPECT_EQ(calloutObjects[3]->priority(), 'M');
181     EXPECT_EQ(calloutObjects[4]->locationCode(), "U1-P7");
182     EXPECT_EQ(calloutObjects[4]->priority(), 'M');
183     EXPECT_EQ(calloutObjects[5]->locationCode(), "U1-P8");
184     EXPECT_EQ(calloutObjects[5]->priority(), 'A');
185     EXPECT_EQ(calloutObjects[6]->locationCode(), "U1-P9");
186     EXPECT_EQ(calloutObjects[6]->priority(), 'C');
187     EXPECT_EQ(calloutObjects[7]->locationCode(), "U1-P3");
188     EXPECT_EQ(calloutObjects[7]->priority(), 'L');
189     EXPECT_EQ(calloutObjects[8]->locationCode(), "U1-P6");
190     EXPECT_EQ(calloutObjects[8]->priority(), 'L');
191     EXPECT_EQ(calloutObjects[9]->locationCode(), "U1-P10");
192     EXPECT_EQ(calloutObjects[9]->priority(), 'L');
193 }
194 
TEST(CalloutsTest,TestDupCallouts)195 TEST(CalloutsTest, TestDupCallouts)
196 {
197     {
198         // Duplicate callouts, keep the high priority one
199         Callouts callouts;
200         auto c0 = std::make_unique<Callout>(CalloutPriority::medium, "U1-P1",
201                                             "1234567", "ABC", "123456789ABC");
202         callouts.addCallout(std::move(c0));
203 
204         auto c1 = std::make_unique<Callout>(CalloutPriority::high, "U1-P1",
205                                             "1234567", "ABCD", "123456789ABC");
206         callouts.addCallout(std::move(c1));
207 
208         EXPECT_EQ(callouts.callouts().size(), 1);
209         const auto& calloutObjects = callouts.callouts();
210         EXPECT_EQ(calloutObjects[0]->priority(), 'H');
211     }
212 
213     {
214         // Different callouts, keep them both
215         Callouts callouts;
216         auto c0 = std::make_unique<Callout>(CalloutPriority::high, "U1-P1",
217                                             "1234567", "ABC", "123456789ABC");
218         callouts.addCallout(std::move(c0));
219 
220         auto c1 = std::make_unique<Callout>(CalloutPriority::medium, "U1-P2",
221                                             "1234567", "ABCD", "123456789ABC");
222         callouts.addCallout(std::move(c1));
223 
224         EXPECT_EQ(callouts.callouts().size(), 2);
225     }
226 
227     {
228         // Two duplicates and two unique.  Needs sorting.
229         Callouts callouts;
230         auto c0 = std::make_unique<Callout>(CalloutPriority::low, "U1-P9",
231                                             "1234567", "ABCD", "123456789ABC");
232         callouts.addCallout(std::move(c0));
233 
234         auto c1 = std::make_unique<Callout>(CalloutPriority::low, "U1-P1",
235                                             "1234567", "ABC", "123456789ABC");
236         callouts.addCallout(std::move(c1));
237 
238         auto c2 = std::make_unique<Callout>(CalloutPriority::high, "U1-P1",
239                                             "1234567", "ABC", "123456789ABC");
240         callouts.addCallout(std::move(c2));
241 
242         auto c3 = std::make_unique<Callout>(CalloutPriority::medium, "U1-P5",
243                                             "1234567", "ABCD", "123456789ABC");
244         callouts.addCallout(std::move(c3));
245 
246         const auto& calloutObjects = callouts.callouts();
247         EXPECT_EQ(callouts.callouts().size(), 3);
248         EXPECT_EQ(calloutObjects[0]->priority(), 'H');
249         EXPECT_EQ(calloutObjects[0]->locationCode(), "U1-P1");
250         EXPECT_EQ(calloutObjects[1]->priority(), 'M');
251         EXPECT_EQ(calloutObjects[1]->locationCode(), "U1-P5");
252         EXPECT_EQ(calloutObjects[2]->priority(), 'L');
253         EXPECT_EQ(calloutObjects[2]->locationCode(), "U1-P9");
254     }
255 }
256