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 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 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 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 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