1 #include "config.h"
2 
3 #include "elog_entry.hpp"
4 #include "elog_serialize.hpp"
5 #include "extensions.hpp"
6 #include "log_manager.hpp"
7 #include "paths.hpp"
8 
9 #include <filesystem>
10 #include <thread>
11 
12 #include <gtest/gtest.h>
13 
14 namespace phosphor
15 {
16 namespace logging
17 {
18 namespace test
19 {
20 
21 using namespace std::chrono_literals;
22 namespace fs = std::filesystem;
23 
24 void deleteIsProhibitedMock(uint32_t /*id*/, bool& prohibited)
25 {
26     prohibited = true;
27 }
28 
29 void deleteIsNotProhibitedMock(uint32_t /*id*/, bool& prohibited)
30 {
31     prohibited = false;
32 }
33 
34 // Test that the update timestamp changes when the resolved property changes
35 TEST(TestUpdateTS, testChangeResolved)
36 {
37     // Setting resolved will serialize, so need this directory.
38     fs::create_directories(paths::error());
39 
40     if (!fs::exists(paths::error()))
41     {
42         ADD_FAILURE() << "Could not create " << paths::error() << "\n";
43         exit(1);
44     }
45 
46     auto bus = sdbusplus::bus::new_default();
47     phosphor::logging::internal::Manager manager(bus, OBJ_INTERNAL);
48 
49     // Use a random number for the ID to avoid other CI
50     // testcases running in parallel.
51     std::srand(std::time(nullptr));
52     uint32_t id = std::rand();
53 
54     if (fs::exists(fs::path{paths::error()} / std::to_string(id)))
55     {
56         std::cerr << "Another testcase is using ID " << id << "\n";
57         id = std::rand();
58     }
59 
60     uint64_t timestamp{100};
61     std::string message{"test error"};
62     std::string fwLevel{"level42"};
63     std::string path{"/tmp/99"};
64     std::vector<std::string> testData{"additional", "data"};
65     phosphor::logging::AssociationList associations{};
66 
67     Entry elog{bus,
68                std::string(OBJ_ENTRY) + '/' + std::to_string(id),
69                id,
70                timestamp,
71                Entry::Level::Informational,
72                std::move(message),
73                std::move(testData),
74                std::move(associations),
75                fwLevel,
76                path,
77                manager};
78 
79     EXPECT_EQ(elog.timestamp(), elog.updateTimestamp());
80 
81     std::this_thread::sleep_for(1ms);
82 
83     elog.resolved(true);
84     auto updateTS = elog.updateTimestamp();
85     EXPECT_NE(updateTS, elog.timestamp());
86 
87     std::this_thread::sleep_for(1ms);
88 
89     elog.resolved(false);
90     EXPECT_NE(updateTS, elog.updateTimestamp());
91     updateTS = elog.updateTimestamp();
92 
93     std::this_thread::sleep_for(1ms);
94 
95     // No change
96     elog.resolved(false);
97     EXPECT_EQ(updateTS, elog.updateTimestamp());
98 
99     // Leave the directory in case other CI instances are running
100     fs::remove(fs::path{paths::error()} / std::to_string(id));
101 }
102 
103 TEST(TestResolveProhibited, testResolveFlagChange)
104 {
105     // Setting resolved will serialize, so need this directory.
106     fs::create_directory(ERRLOG_PERSIST_PATH);
107 
108     if (!fs::exists(ERRLOG_PERSIST_PATH))
109     {
110         ADD_FAILURE() << "Could not create " << ERRLOG_PERSIST_PATH << "\n";
111         exit(1);
112     }
113 
114     auto bus = sdbusplus::bus::new_default();
115     phosphor::logging::internal::Manager manager(bus, OBJ_INTERNAL);
116 
117     // Use a random number for the ID to avoid other CI
118     // testcases running in parallel.
119     std::srand(std::time(nullptr));
120     uint32_t id = std::rand();
121 
122     if (fs::exists(fs::path{ERRLOG_PERSIST_PATH} / std::to_string(id)))
123     {
124         std::cerr << "Another testcase is using ID " << id << "\n";
125         id = std::rand();
126     }
127 
128     uint64_t timestamp{100};
129     std::string message{"test error"};
130     std::string fwLevel{"level42"};
131     std::string path{"/tmp/99"};
132     std::vector<std::string> testData{"additional", "data"};
133     phosphor::logging::AssociationList associations{};
134 
135     Entry elog{bus,
136                std::string(OBJ_ENTRY) + '/' + std::to_string(id),
137                id,
138                timestamp,
139                Entry::Level::Informational,
140                std::move(message),
141                std::move(testData),
142                std::move(associations),
143                fwLevel,
144                path,
145                manager};
146 
147     Extensions ext{deleteIsProhibitedMock};
148 
149     EXPECT_THROW(elog.resolved(true),
150                  sdbusplus::xyz::openbmc_project::Common::Error::Unavailable);
151 
152     Extensions::getDeleteProhibitedFunctions().clear();
153 
154     Extensions e{deleteIsNotProhibitedMock};
155 
156     EXPECT_NO_THROW(elog.resolved(true));
157     EXPECT_EQ(elog.resolved(), true);
158 
159     // Leave the directory in case other CI instances are running
160     fs::remove(fs::path{ERRLOG_PERSIST_PATH} / std::to_string(id));
161 }
162 } // namespace test
163 } // namespace logging
164 } // namespace phosphor
165