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