blob: 28802f40f2d1785f69bfa439cf370e6304313d30 [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 Spinlerf682b402019-12-18 13:48:08 -060070void eventLoggerStub(const std::string&, phosphor::logging::Entry::Level,
71 const EventLogger::ADMap&)
72{
73}
74
Matt Spinler89fa0822019-07-17 13:54:30 -050075// Test that using the RAWPEL=<file> with the Manager::create() call gets
76// a PEL saved in the repository.
77TEST_F(ManagerTest, TestCreateWithPEL)
78{
Matt Spinlerc8705e22019-09-11 12:36:07 -050079 std::unique_ptr<DataInterfaceBase> dataIface =
80 std::make_unique<DataInterface>(bus);
Matt Spinler89fa0822019-07-17 13:54:30 -050081
Matt Spinlerf682b402019-12-18 13:48:08 -060082 openpower::pels::Manager manager{logManager, std::move(dataIface),
83 eventLoggerStub};
Matt Spinler89fa0822019-07-17 13:54:30 -050084
85 // Create a PEL, write it to a file, and pass that filename into
86 // the create function.
Matt Spinler42828bd2019-10-11 10:39:30 -050087 auto data = pelDataFactory(TestPELType::pelSimple);
Matt Spinler89fa0822019-07-17 13:54:30 -050088
89 fs::path pelFilename = makeTempDir() / "rawpel";
90 std::ofstream pelFile{pelFilename};
Matt Spinler42828bd2019-10-11 10:39:30 -050091 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
Matt Spinler89fa0822019-07-17 13:54:30 -050092 pelFile.close();
93
94 std::string adItem = "RAWPEL=" + pelFilename.string();
95 std::vector<std::string> additionalData{adItem};
96 std::vector<std::string> associations;
97
Matt Spinler367144c2019-09-19 15:33:52 -050098 manager.create("error message", 42, 0,
99 phosphor::logging::Entry::Level::Error, additionalData,
Matt Spinler89fa0822019-07-17 13:54:30 -0500100 associations);
101
Matt Spinler67456c22019-10-21 12:22:49 -0500102 // Find the file in the PEL repository directory
103 auto pelPathInRepo = findAnyPELInRepo();
Matt Spinler89fa0822019-07-17 13:54:30 -0500104
Matt Spinler67456c22019-10-21 12:22:49 -0500105 EXPECT_TRUE(pelPathInRepo);
Matt Spinler89fa0822019-07-17 13:54:30 -0500106
Matt Spinler475e5742019-07-18 16:09:49 -0500107 // Now remove it based on its OpenBMC event log ID
108 manager.erase(42);
109
Matt Spinler67456c22019-10-21 12:22:49 -0500110 pelPathInRepo = findAnyPELInRepo();
Matt Spinler475e5742019-07-18 16:09:49 -0500111
Matt Spinler67456c22019-10-21 12:22:49 -0500112 EXPECT_FALSE(pelPathInRepo);
Matt Spinler475e5742019-07-18 16:09:49 -0500113
Matt Spinler89fa0822019-07-17 13:54:30 -0500114 fs::remove_all(pelFilename.parent_path());
115}
Matt Spinler67456c22019-10-21 12:22:49 -0500116
117// Test that the message registry can be used to build a PEL.
118TEST_F(ManagerTest, TestCreateWithMessageRegistry)
119{
120 const auto registry = R"(
121{
122 "PELs":
123 [
124 {
125 "Name": "xyz.openbmc_project.Error.Test",
126 "Subsystem": "power_supply",
127 "ActionFlags": ["service_action", "report"],
128 "SRC":
129 {
130 "ReasonCode": "0x2030"
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800131 },
132 "Documentation":
133 {
134 "Description": "A PGOOD Fault",
135 "Message": "PS had a PGOOD Fault"
Matt Spinler67456c22019-10-21 12:22:49 -0500136 }
137 }
138 ]
139}
140)";
141
Matt Spinlerd4ffb652019-11-12 14:16:14 -0600142 auto path = getMessageRegistryPath();
143 fs::create_directories(path);
144 path /= "message_registry.json";
145
Matt Spinler67456c22019-10-21 12:22:49 -0500146 std::ofstream registryFile{path};
147 registryFile << registry;
148 registryFile.close();
149
Matt Spinler67456c22019-10-21 12:22:49 -0500150 std::unique_ptr<DataInterfaceBase> dataIface =
151 std::make_unique<DataInterface>(logManager.getBus());
152
Matt Spinlerf682b402019-12-18 13:48:08 -0600153 openpower::pels::Manager manager{logManager, std::move(dataIface),
154 eventLoggerStub};
Matt Spinler67456c22019-10-21 12:22:49 -0500155
156 std::vector<std::string> additionalData;
157 std::vector<std::string> associations;
158
159 // Create the event log to create the PEL from.
160 manager.create("xyz.openbmc_project.Error.Test", 33, 0,
161 phosphor::logging::Entry::Level::Error, additionalData,
162 associations);
163
164 // Ensure a PEL was created in the repository
165 auto pelFile = findAnyPELInRepo();
166 ASSERT_TRUE(pelFile);
167
168 auto data = readPELFile(*pelFile);
169 PEL pel(*data);
170
171 // Spot check it. Other testcases cover the details.
172 EXPECT_TRUE(pel.valid());
173 EXPECT_EQ(pel.obmcLogID(), 33);
174 EXPECT_EQ(pel.primarySRC().value()->asciiString(),
175 "BD612030 ");
176
177 // Remove it
178 manager.erase(33);
179 pelFile = findAnyPELInRepo();
180 EXPECT_FALSE(pelFile);
181
182 // Create an event log that can't be found in the registry.
183 manager.create("xyz.openbmc_project.Error.Foo", 33, 0,
184 phosphor::logging::Entry::Level::Error, additionalData,
185 associations);
186
187 // Currently, no PEL should be created. Eventually, a 'missing registry
188 // entry' PEL will be there.
189 pelFile = findAnyPELInRepo();
190 EXPECT_FALSE(pelFile);
191}
Matt Spinlera34ab722019-12-16 10:39:32 -0600192
193TEST_F(ManagerTest, TestDBusMethods)
194{
Matt Spinlera34ab722019-12-16 10:39:32 -0600195 std::unique_ptr<DataInterfaceBase> dataIface =
196 std::make_unique<DataInterface>(bus);
197
Matt Spinlerf682b402019-12-18 13:48:08 -0600198 Manager manager{logManager, std::move(dataIface), eventLoggerStub};
Matt Spinlera34ab722019-12-16 10:39:32 -0600199
200 // Create a PEL, write it to a file, and pass that filename into
201 // the create function so there's one in the repo.
202 auto data = pelDataFactory(TestPELType::pelSimple);
203
204 fs::path pelFilename = makeTempDir() / "rawpel";
205 std::ofstream pelFile{pelFilename};
206 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
207 pelFile.close();
208
209 std::string adItem = "RAWPEL=" + pelFilename.string();
210 std::vector<std::string> additionalData{adItem};
211 std::vector<std::string> associations;
212
213 manager.create("error message", 42, 0,
214 phosphor::logging::Entry::Level::Error, additionalData,
215 associations);
216
217 // getPELFromOBMCID
218 auto newData = manager.getPELFromOBMCID(42);
219 EXPECT_EQ(newData.size(), data.size());
220
221 // Read the PEL to get the ID for later
222 PEL pel{newData};
223 auto id = pel.id();
224
225 EXPECT_THROW(
226 manager.getPELFromOBMCID(id + 1),
227 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
228
229 // getPEL
230 auto unixfd = manager.getPEL(id);
231
232 // Get the size
233 struct stat s;
234 int r = fstat(unixfd, &s);
235 ASSERT_EQ(r, 0);
236 auto size = s.st_size;
237
238 // Open the FD and check the contents
239 FILE* fp = fdopen(unixfd, "r");
240 ASSERT_NE(fp, nullptr);
241
242 std::vector<uint8_t> fdData;
243 fdData.resize(size);
244 r = fread(fdData.data(), 1, size, fp);
245 EXPECT_EQ(r, size);
246
247 EXPECT_EQ(newData, fdData);
248
249 fclose(fp);
250
251 EXPECT_THROW(
252 manager.getPEL(id + 1),
253 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
254
255 // hostAck
256 manager.hostAck(id);
257
258 EXPECT_THROW(
259 manager.hostAck(id + 1),
260 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
261
262 // hostReject
263 manager.hostReject(id, Manager::RejectionReason::BadPEL);
264 manager.hostReject(id, Manager::RejectionReason::HostFull);
265
266 EXPECT_THROW(
267 manager.hostReject(id + 1, Manager::RejectionReason::BadPEL),
268 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
269
270 fs::remove_all(pelFilename.parent_path());
271}