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