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