blob: 8f3df2279902e9feca4fd24612f5ae53a79b355b [file] [log] [blame]
Matt Spinler97f7abc2019-11-06 09:40:23 -06001/**
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 */
Matt Spinler89fa0822019-07-17 13:54:30 -050016#include "extensions/openpower-pels/manager.hpp"
17#include "log_manager.hpp"
18#include "pel_utils.hpp"
19
20#include <fstream>
21#include <regex>
Matt Spinlera34ab722019-12-16 10:39:32 -060022#include <xyz/openbmc_project/Common/error.hpp>
Matt Spinler89fa0822019-07-17 13:54:30 -050023
24#include <gtest/gtest.h>
25
26using namespace openpower::pels;
27namespace fs = std::filesystem;
28
29class ManagerTest : public CleanPELFiles
30{
Matt Spinler6b1a5c82020-01-07 08:48:53 -060031 public:
32 ManagerTest() : logManager(bus, "logging_path")
33 {
34 sd_event_default(&sdEvent);
35 bus.attach_event(sdEvent, SD_EVENT_PRIORITY_NORMAL);
36 }
37
38 ~ManagerTest()
39 {
40 sd_event_unref(sdEvent);
41 }
42
43 sdbusplus::bus::bus bus = sdbusplus::bus::new_default();
44 phosphor::logging::internal::Manager logManager;
45 sd_event* sdEvent;
Matt Spinler89fa0822019-07-17 13:54:30 -050046};
47
48fs::path makeTempDir()
49{
50 char path[] = "/tmp/tempnameXXXXXX";
51 std::filesystem::path dir = mkdtemp(path);
52 return dir;
53}
54
Matt Spinler67456c22019-10-21 12:22:49 -050055std::optional<fs::path> findAnyPELInRepo()
56{
57 // PELs are named <timestamp>_<ID>
58 std::regex expr{"\\d+_\\d+"};
59
60 for (auto& f : fs::directory_iterator(getPELRepoPath() / "logs"))
61 {
62 if (std::regex_search(f.path().string(), expr))
63 {
64 return f.path();
65 }
66 }
67 return std::nullopt;
68}
69
Matt Spinler89fa0822019-07-17 13:54:30 -050070// Test that using the RAWPEL=<file> with the Manager::create() call gets
71// a PEL saved in the repository.
72TEST_F(ManagerTest, TestCreateWithPEL)
73{
Matt Spinlerc8705e22019-09-11 12:36:07 -050074 std::unique_ptr<DataInterfaceBase> dataIface =
75 std::make_unique<DataInterface>(bus);
Matt Spinler89fa0822019-07-17 13:54:30 -050076
Matt Spinlerc8705e22019-09-11 12:36:07 -050077 openpower::pels::Manager manager{logManager, std::move(dataIface)};
Matt Spinler89fa0822019-07-17 13:54:30 -050078
79 // Create a PEL, write it to a file, and pass that filename into
80 // the create function.
Matt Spinler42828bd2019-10-11 10:39:30 -050081 auto data = pelDataFactory(TestPELType::pelSimple);
Matt Spinler89fa0822019-07-17 13:54:30 -050082
83 fs::path pelFilename = makeTempDir() / "rawpel";
84 std::ofstream pelFile{pelFilename};
Matt Spinler42828bd2019-10-11 10:39:30 -050085 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
Matt Spinler89fa0822019-07-17 13:54:30 -050086 pelFile.close();
87
88 std::string adItem = "RAWPEL=" + pelFilename.string();
89 std::vector<std::string> additionalData{adItem};
90 std::vector<std::string> associations;
91
Matt Spinler367144c2019-09-19 15:33:52 -050092 manager.create("error message", 42, 0,
93 phosphor::logging::Entry::Level::Error, additionalData,
Matt Spinler89fa0822019-07-17 13:54:30 -050094 associations);
95
Matt Spinler67456c22019-10-21 12:22:49 -050096 // Find the file in the PEL repository directory
97 auto pelPathInRepo = findAnyPELInRepo();
Matt Spinler89fa0822019-07-17 13:54:30 -050098
Matt Spinler67456c22019-10-21 12:22:49 -050099 EXPECT_TRUE(pelPathInRepo);
Matt Spinler89fa0822019-07-17 13:54:30 -0500100
Matt Spinler475e5742019-07-18 16:09:49 -0500101 // Now remove it based on its OpenBMC event log ID
102 manager.erase(42);
103
Matt Spinler67456c22019-10-21 12:22:49 -0500104 pelPathInRepo = findAnyPELInRepo();
Matt Spinler475e5742019-07-18 16:09:49 -0500105
Matt Spinler67456c22019-10-21 12:22:49 -0500106 EXPECT_FALSE(pelPathInRepo);
Matt Spinler475e5742019-07-18 16:09:49 -0500107
Matt Spinler89fa0822019-07-17 13:54:30 -0500108 fs::remove_all(pelFilename.parent_path());
109}
Matt Spinler67456c22019-10-21 12:22:49 -0500110
111// Test that the message registry can be used to build a PEL.
112TEST_F(ManagerTest, TestCreateWithMessageRegistry)
113{
114 const auto registry = R"(
115{
116 "PELs":
117 [
118 {
119 "Name": "xyz.openbmc_project.Error.Test",
120 "Subsystem": "power_supply",
121 "ActionFlags": ["service_action", "report"],
122 "SRC":
123 {
124 "ReasonCode": "0x2030"
125 }
126 }
127 ]
128}
129)";
130
Matt Spinlerd4ffb652019-11-12 14:16:14 -0600131 auto path = getMessageRegistryPath();
132 fs::create_directories(path);
133 path /= "message_registry.json";
134
Matt Spinler67456c22019-10-21 12:22:49 -0500135 std::ofstream registryFile{path};
136 registryFile << registry;
137 registryFile.close();
138
139 auto bus = sdbusplus::bus::new_default();
140 phosphor::logging::internal::Manager logManager(bus, "logging_path");
141
142 std::unique_ptr<DataInterfaceBase> dataIface =
143 std::make_unique<DataInterface>(logManager.getBus());
144
145 openpower::pels::Manager manager{logManager, std::move(dataIface)};
146
147 std::vector<std::string> additionalData;
148 std::vector<std::string> associations;
149
150 // Create the event log to create the PEL from.
151 manager.create("xyz.openbmc_project.Error.Test", 33, 0,
152 phosphor::logging::Entry::Level::Error, additionalData,
153 associations);
154
155 // Ensure a PEL was created in the repository
156 auto pelFile = findAnyPELInRepo();
157 ASSERT_TRUE(pelFile);
158
159 auto data = readPELFile(*pelFile);
160 PEL pel(*data);
161
162 // Spot check it. Other testcases cover the details.
163 EXPECT_TRUE(pel.valid());
164 EXPECT_EQ(pel.obmcLogID(), 33);
165 EXPECT_EQ(pel.primarySRC().value()->asciiString(),
166 "BD612030 ");
167
168 // Remove it
169 manager.erase(33);
170 pelFile = findAnyPELInRepo();
171 EXPECT_FALSE(pelFile);
172
173 // Create an event log that can't be found in the registry.
174 manager.create("xyz.openbmc_project.Error.Foo", 33, 0,
175 phosphor::logging::Entry::Level::Error, additionalData,
176 associations);
177
178 // Currently, no PEL should be created. Eventually, a 'missing registry
179 // entry' PEL will be there.
180 pelFile = findAnyPELInRepo();
181 EXPECT_FALSE(pelFile);
182}
Matt Spinlera34ab722019-12-16 10:39:32 -0600183
184TEST_F(ManagerTest, TestDBusMethods)
185{
Matt Spinlera34ab722019-12-16 10:39:32 -0600186 std::unique_ptr<DataInterfaceBase> dataIface =
187 std::make_unique<DataInterface>(bus);
188
189 Manager manager{logManager, std::move(dataIface)};
190
191 // Create a PEL, write it to a file, and pass that filename into
192 // the create function so there's one in the repo.
193 auto data = pelDataFactory(TestPELType::pelSimple);
194
195 fs::path pelFilename = makeTempDir() / "rawpel";
196 std::ofstream pelFile{pelFilename};
197 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
198 pelFile.close();
199
200 std::string adItem = "RAWPEL=" + pelFilename.string();
201 std::vector<std::string> additionalData{adItem};
202 std::vector<std::string> associations;
203
204 manager.create("error message", 42, 0,
205 phosphor::logging::Entry::Level::Error, additionalData,
206 associations);
207
208 // getPELFromOBMCID
209 auto newData = manager.getPELFromOBMCID(42);
210 EXPECT_EQ(newData.size(), data.size());
211
212 // Read the PEL to get the ID for later
213 PEL pel{newData};
214 auto id = pel.id();
215
216 EXPECT_THROW(
217 manager.getPELFromOBMCID(id + 1),
218 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
219
220 // getPEL
221 auto unixfd = manager.getPEL(id);
222
223 // Get the size
224 struct stat s;
225 int r = fstat(unixfd, &s);
226 ASSERT_EQ(r, 0);
227 auto size = s.st_size;
228
229 // Open the FD and check the contents
230 FILE* fp = fdopen(unixfd, "r");
231 ASSERT_NE(fp, nullptr);
232
233 std::vector<uint8_t> fdData;
234 fdData.resize(size);
235 r = fread(fdData.data(), 1, size, fp);
236 EXPECT_EQ(r, size);
237
238 EXPECT_EQ(newData, fdData);
239
240 fclose(fp);
241
242 EXPECT_THROW(
243 manager.getPEL(id + 1),
244 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
245
246 // hostAck
247 manager.hostAck(id);
248
249 EXPECT_THROW(
250 manager.hostAck(id + 1),
251 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
252
253 // hostReject
254 manager.hostReject(id, Manager::RejectionReason::BadPEL);
255 manager.hostReject(id, Manager::RejectionReason::HostFull);
256
257 EXPECT_THROW(
258 manager.hostReject(id + 1, Manager::RejectionReason::BadPEL),
259 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
260
261 fs::remove_all(pelFilename.parent_path());
262}