blob: 08124ff687077f23b845d53d5c6bc049867b79bf [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"
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800125 },
126 "Documentation":
127 {
128 "Description": "A PGOOD Fault",
129 "Message": "PS had a PGOOD Fault"
Matt Spinler67456c22019-10-21 12:22:49 -0500130 }
131 }
132 ]
133}
134)";
135
Matt Spinlerd4ffb652019-11-12 14:16:14 -0600136 auto path = getMessageRegistryPath();
137 fs::create_directories(path);
138 path /= "message_registry.json";
139
Matt Spinler67456c22019-10-21 12:22:49 -0500140 std::ofstream registryFile{path};
141 registryFile << registry;
142 registryFile.close();
143
144 auto bus = sdbusplus::bus::new_default();
145 phosphor::logging::internal::Manager logManager(bus, "logging_path");
146
147 std::unique_ptr<DataInterfaceBase> dataIface =
148 std::make_unique<DataInterface>(logManager.getBus());
149
150 openpower::pels::Manager manager{logManager, std::move(dataIface)};
151
152 std::vector<std::string> additionalData;
153 std::vector<std::string> associations;
154
155 // Create the event log to create the PEL from.
156 manager.create("xyz.openbmc_project.Error.Test", 33, 0,
157 phosphor::logging::Entry::Level::Error, additionalData,
158 associations);
159
160 // Ensure a PEL was created in the repository
161 auto pelFile = findAnyPELInRepo();
162 ASSERT_TRUE(pelFile);
163
164 auto data = readPELFile(*pelFile);
165 PEL pel(*data);
166
167 // Spot check it. Other testcases cover the details.
168 EXPECT_TRUE(pel.valid());
169 EXPECT_EQ(pel.obmcLogID(), 33);
170 EXPECT_EQ(pel.primarySRC().value()->asciiString(),
171 "BD612030 ");
172
173 // Remove it
174 manager.erase(33);
175 pelFile = findAnyPELInRepo();
176 EXPECT_FALSE(pelFile);
177
178 // Create an event log that can't be found in the registry.
179 manager.create("xyz.openbmc_project.Error.Foo", 33, 0,
180 phosphor::logging::Entry::Level::Error, additionalData,
181 associations);
182
183 // Currently, no PEL should be created. Eventually, a 'missing registry
184 // entry' PEL will be there.
185 pelFile = findAnyPELInRepo();
186 EXPECT_FALSE(pelFile);
187}
Matt Spinlera34ab722019-12-16 10:39:32 -0600188
189TEST_F(ManagerTest, TestDBusMethods)
190{
Matt Spinlera34ab722019-12-16 10:39:32 -0600191 std::unique_ptr<DataInterfaceBase> dataIface =
192 std::make_unique<DataInterface>(bus);
193
194 Manager manager{logManager, std::move(dataIface)};
195
196 // Create a PEL, write it to a file, and pass that filename into
197 // the create function so there's one in the repo.
198 auto data = pelDataFactory(TestPELType::pelSimple);
199
200 fs::path pelFilename = makeTempDir() / "rawpel";
201 std::ofstream pelFile{pelFilename};
202 pelFile.write(reinterpret_cast<const char*>(data.data()), data.size());
203 pelFile.close();
204
205 std::string adItem = "RAWPEL=" + pelFilename.string();
206 std::vector<std::string> additionalData{adItem};
207 std::vector<std::string> associations;
208
209 manager.create("error message", 42, 0,
210 phosphor::logging::Entry::Level::Error, additionalData,
211 associations);
212
213 // getPELFromOBMCID
214 auto newData = manager.getPELFromOBMCID(42);
215 EXPECT_EQ(newData.size(), data.size());
216
217 // Read the PEL to get the ID for later
218 PEL pel{newData};
219 auto id = pel.id();
220
221 EXPECT_THROW(
222 manager.getPELFromOBMCID(id + 1),
223 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
224
225 // getPEL
226 auto unixfd = manager.getPEL(id);
227
228 // Get the size
229 struct stat s;
230 int r = fstat(unixfd, &s);
231 ASSERT_EQ(r, 0);
232 auto size = s.st_size;
233
234 // Open the FD and check the contents
235 FILE* fp = fdopen(unixfd, "r");
236 ASSERT_NE(fp, nullptr);
237
238 std::vector<uint8_t> fdData;
239 fdData.resize(size);
240 r = fread(fdData.data(), 1, size, fp);
241 EXPECT_EQ(r, size);
242
243 EXPECT_EQ(newData, fdData);
244
245 fclose(fp);
246
247 EXPECT_THROW(
248 manager.getPEL(id + 1),
249 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
250
251 // hostAck
252 manager.hostAck(id);
253
254 EXPECT_THROW(
255 manager.hostAck(id + 1),
256 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
257
258 // hostReject
259 manager.hostReject(id, Manager::RejectionReason::BadPEL);
260 manager.hostReject(id, Manager::RejectionReason::HostFull);
261
262 EXPECT_THROW(
263 manager.hostReject(id + 1, Manager::RejectionReason::BadPEL),
264 sdbusplus::xyz::openbmc_project::Common::Error::InvalidArgument);
265
266 fs::remove_all(pelFilename.parent_path());
267}