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