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