1 // A basic unit test that runs on a BMC (qemu or hardware)
2
3 #include <getopt.h>
4 #include <systemd/sd-journal.h>
5
6 #include <phosphor-logging/elog-errors.hpp>
7 #include <phosphor-logging/elog.hpp>
8 #include <phosphor-logging/log.hpp>
9 #include <sdbusplus/exception.hpp>
10
11 #include <cstring>
12 #include <iostream>
13 #include <sstream>
14
15 using namespace phosphor;
16 using namespace logging;
17
18 const char* usage = "Usage: logging-test [OPTION] \n\n\
19 Options: \n\
20 [NONE] Default test case. \n\
21 -h, --help Display this usage text. \n\
22 -c, --commit <string> Commit desired error. \n\n\
23 Valid errors to commit: \n\
24 AutoTestSimple, AutoTestCreateAndCommit\n";
25
26 // validate the journal metadata equals the input value
validate_journal(const char * i_entry,const char * i_value)27 int validate_journal(const char* i_entry, const char* i_value)
28 {
29 sd_journal* journal;
30 const void* data;
31 size_t l;
32 int rc;
33 bool validated = false;
34
35 rc = sd_journal_open(&journal, SD_JOURNAL_LOCAL_ONLY);
36 if (rc < 0)
37 {
38 std::cerr << "Failed to open journal: " << strerror(-rc) << "\n";
39 return 1;
40 }
41 rc = sd_journal_query_unique(journal, i_entry);
42 if (rc < 0)
43 {
44 std::cerr << "Failed to query journal: " << strerror(-rc) << "\n";
45 return 1;
46 }
47 SD_JOURNAL_FOREACH_UNIQUE(journal, data, l)
48 {
49 std::string journ_entry((const char*)data);
50 std::cout << journ_entry << "\n";
51 if (journ_entry.find(i_value) != std::string::npos)
52 {
53 std::cout << "We found it!\n";
54 validated = true;
55 break;
56 }
57 }
58
59 sd_journal_close(journal);
60
61 rc = (validated) ? 0 : 1;
62 if (rc)
63 {
64 std::cerr << "Failed to find " << i_entry << " with value " << i_value
65 << " in journal!"
66 << "\n";
67 }
68
69 return rc;
70 }
71
elog_test()72 int elog_test()
73 {
74 // TEST 1 - Basic log
75 log<level::DEBUG>("Basic phosphor logging test");
76
77 // TEST 2 - Log with metadata field
78 const char* file_name = "phosphor_logging_test.txt";
79 int number = 0xFEFE;
80 log<level::DEBUG>(
81 "phosphor logging test with attribute",
82 entry("FILE_NAME_WITH_NUM_TEST=%s_%x", file_name, number));
83
84 // Now read back and verify our data made it into the journal
85 int rc = validate_journal("FILE_NAME_WITH_NUM_TEST",
86 "phosphor_logging_test.txt_fefe");
87 if (rc)
88 return (rc);
89
90 // TEST 3 - Create error log with 2 meta data fields (rvalue and lvalue)
91 number = 0x1234;
92 const char* test_string = "/tmp/test_string/";
93 try
94 {
95 elog<example::xyz::openbmc_project::example::elog::TestErrorOne>(
96 example::xyz::openbmc_project::example::elog::TestErrorOne::ERRNUM(
97 number),
98 example::xyz::openbmc_project::example::elog::TestErrorOne::
99 FILE_PATH(test_string),
100 example::xyz::openbmc_project::example::elog::TestErrorOne::
101 FILE_NAME("elog_test_3.txt"),
102 example::xyz::openbmc_project::example::elog::TestErrorTwo::
103 DEV_ADDR(0xDEADDEAD),
104 example::xyz::openbmc_project::example::elog::TestErrorTwo::DEV_ID(
105 100),
106 example::xyz::openbmc_project::example::elog::TestErrorTwo::
107 DEV_NAME("test case 3"));
108 }
109 catch (const example::xyz::openbmc_project::example::elog::TestErrorOne& e)
110 {
111 std::cout << "elog exception caught: " << e.what() << std::endl;
112 }
113
114 // Reduce our error namespaces
115 using namespace example::xyz::openbmc_project::example::elog;
116
117 // Now read back and verify our data made it into the journal
118 std::stringstream stream;
119 stream << std::hex << number;
120 rc = validate_journal(TestErrorOne::ERRNUM::str_short,
121 std::string(stream.str()).c_str());
122 if (rc)
123 return (rc);
124
125 rc = validate_journal(TestErrorOne::FILE_PATH::str_short, test_string);
126 if (rc)
127 return (rc);
128
129 rc =
130 validate_journal(TestErrorOne::FILE_NAME::str_short, "elog_test_3.txt");
131 if (rc)
132 return (rc);
133
134 rc = validate_journal(TestErrorTwo::DEV_ADDR::str_short, "0xDEADDEAD");
135 if (rc)
136 return (rc);
137
138 rc = validate_journal(TestErrorTwo::DEV_ID::str_short, "100");
139 if (rc)
140 return (rc);
141
142 rc = validate_journal(TestErrorTwo::DEV_NAME::str_short, "test case 3");
143 if (rc)
144 return (rc);
145
146 // TEST 4 - Create error log with previous entry use
147 number = 0x9876;
148 try
149 {
150 elog<TestErrorOne>(
151 TestErrorOne::ERRNUM(number), prev_entry<TestErrorOne::FILE_PATH>(),
152 TestErrorOne::FILE_NAME("elog_test_4.txt"),
153 TestErrorTwo::DEV_ADDR(0xDEADDEAD), TestErrorTwo::DEV_ID(100),
154 TestErrorTwo::DEV_NAME("test case 4"));
155 }
156 catch (const sdbusplus::exception_t& e)
157 {
158 std::cout << "elog exception caught: " << e.what() << std::endl;
159 }
160
161 // Now read back and verify our data made it into the journal
162 stream.str("");
163 stream << std::hex << number;
164 rc = validate_journal(TestErrorOne::ERRNUM::str_short,
165 std::string(stream.str()).c_str());
166 if (rc)
167 return (rc);
168
169 // This should just be equal to what we put in test 3
170 rc = validate_journal(TestErrorOne::FILE_PATH::str_short, test_string);
171 if (rc)
172 return (rc);
173
174 rc =
175 validate_journal(TestErrorOne::FILE_NAME::str_short, "elog_test_4.txt");
176 if (rc)
177 return (rc);
178
179 rc = validate_journal(TestErrorTwo::DEV_ADDR::str_short, "0xDEADDEAD");
180 if (rc)
181 return (rc);
182
183 rc = validate_journal(TestErrorTwo::DEV_ID::str_short, "100");
184 if (rc)
185 return (rc);
186
187 rc = validate_journal(TestErrorTwo::DEV_NAME::str_short, "test case 4");
188 if (rc)
189 return (rc);
190
191 // Compile fail tests
192
193 // Simple test to prove we fail to compile due to missing param
194 // elog<TestErrorOne>(TestErrorOne::ERRNUM(1),
195 // TestErrorOne::FILE_PATH("test"));
196
197 // Simple test to prove we fail to compile due to invalid param
198 // elog<TestErrorOne>(TestErrorOne::ERRNUM(1),
199 // TestErrorOne::FILE_PATH("test"),
200 // TestErrorOne::FILE_NAME(1));
201
202 return 0;
203 }
204
commitError(const char * text)205 void commitError(const char* text)
206 {
207 if (std::strcmp(text, "AutoTestSimple") == 0)
208 {
209 try
210 {
211 elog<example::xyz::openbmc_project::example::elog::AutoTestSimple>(
212 example::xyz::openbmc_project::example::elog::AutoTestSimple::
213 STRING("FOO"));
214 }
215 catch (
216 const example::xyz::openbmc_project::example::elog::AutoTestSimple&
217 e)
218 {
219 std::cout << "elog exception caught: " << e.what() << std::endl;
220 commit(e.name());
221 }
222 }
223 else if (std::strcmp(text, "AutoTestCreateAndCommit") == 0)
224 {
225 report<example::xyz::openbmc_project::example::elog::AutoTestSimple>(
226 example::xyz::openbmc_project::example::elog::AutoTestSimple::
227 STRING("FOO"));
228 }
229
230 return;
231 }
232
main(int argc,char * argv[])233 int main(int argc, char* argv[])
234 {
235 int arg;
236
237 if (argc == 1)
238 return elog_test();
239
240 static struct option long_options[] = {
241 {"help", no_argument, 0, 'h'},
242 {"commit", required_argument, 0, 'c'},
243 {0, 0, 0, 0}};
244 int option_index = 0;
245
246 while ((arg = getopt_long(argc, argv, "hc:", long_options,
247 &option_index)) != -1)
248 {
249 switch (arg)
250 {
251 case 'c':
252 commitError(optarg);
253 return 0;
254 case 'h':
255 case '?':
256 std::cerr << usage;
257 return 1;
258 }
259 }
260
261 return 0;
262 }
263