// A basic unit test that runs on a BMC (qemu or hardware) #include #include #include #include #include #include #include #include #include using namespace phosphor; using namespace logging; const char* usage = "Usage: logging-test [OPTION] \n\n\ Options: \n\ [NONE] Default test case. \n\ -h, --help Display this usage text. \n\ -c, --commit Commit desired error. \n\n\ Valid errors to commit: \n\ AutoTestSimple, AutoTestCreateAndCommit\n"; // validate the journal metadata equals the input value int validate_journal(const char* i_entry, const char* i_value) { sd_journal* journal; const void* data; size_t l; int rc; bool validated = false; rc = sd_journal_open(&journal, SD_JOURNAL_LOCAL_ONLY); if (rc < 0) { std::cerr << "Failed to open journal: " << strerror(-rc) << "\n"; return 1; } rc = sd_journal_query_unique(journal, i_entry); if (rc < 0) { std::cerr << "Failed to query journal: " << strerror(-rc) << "\n"; return 1; } SD_JOURNAL_FOREACH_UNIQUE(journal, data, l) { std::string journ_entry((const char*)data); std::cout << journ_entry << "\n"; if (journ_entry.find(i_value) != std::string::npos) { std::cout << "We found it!\n"; validated = true; break; } } sd_journal_close(journal); rc = (validated) ? 0 : 1; if (rc) { std::cerr << "Failed to find " << i_entry << " with value " << i_value << " in journal!" << "\n"; } return rc; } int elog_test() { // TEST 1 - Basic log log("Basic phosphor logging test"); // TEST 2 - Log with metadata field const char* file_name = "phosphor_logging_test.txt"; int number = 0xFEFE; log( "phosphor logging test with attribute", entry("FILE_NAME_WITH_NUM_TEST=%s_%x", file_name, number)); // Now read back and verify our data made it into the journal int rc = validate_journal("FILE_NAME_WITH_NUM_TEST", "phosphor_logging_test.txt_fefe"); if (rc) return (rc); // TEST 3 - Create error log with 2 meta data fields (rvalue and lvalue) number = 0x1234; const char* test_string = "/tmp/test_string/"; try { elog( example::xyz::openbmc_project::example::elog::TestErrorOne::ERRNUM( number), example::xyz::openbmc_project::example::elog::TestErrorOne:: FILE_PATH(test_string), example::xyz::openbmc_project::example::elog::TestErrorOne:: FILE_NAME("elog_test_3.txt"), example::xyz::openbmc_project::example::elog::TestErrorTwo:: DEV_ADDR(0xDEADDEAD), example::xyz::openbmc_project::example::elog::TestErrorTwo::DEV_ID( 100), example::xyz::openbmc_project::example::elog::TestErrorTwo:: DEV_NAME("test case 3")); } catch (const example::xyz::openbmc_project::example::elog::TestErrorOne& e) { std::cout << "elog exception caught: " << e.what() << std::endl; } // Reduce our error namespaces using namespace example::xyz::openbmc_project::example::elog; // Now read back and verify our data made it into the journal std::stringstream stream; stream << std::hex << number; rc = validate_journal(TestErrorOne::ERRNUM::str_short, std::string(stream.str()).c_str()); if (rc) return (rc); rc = validate_journal(TestErrorOne::FILE_PATH::str_short, test_string); if (rc) return (rc); rc = validate_journal(TestErrorOne::FILE_NAME::str_short, "elog_test_3.txt"); if (rc) return (rc); rc = validate_journal(TestErrorTwo::DEV_ADDR::str_short, "0xDEADDEAD"); if (rc) return (rc); rc = validate_journal(TestErrorTwo::DEV_ID::str_short, "100"); if (rc) return (rc); rc = validate_journal(TestErrorTwo::DEV_NAME::str_short, "test case 3"); if (rc) return (rc); // TEST 4 - Create error log with previous entry use number = 0x9876; try { elog( TestErrorOne::ERRNUM(number), prev_entry(), TestErrorOne::FILE_NAME("elog_test_4.txt"), TestErrorTwo::DEV_ADDR(0xDEADDEAD), TestErrorTwo::DEV_ID(100), TestErrorTwo::DEV_NAME("test case 4")); } catch (const sdbusplus::exception_t& e) { std::cout << "elog exception caught: " << e.what() << std::endl; } // Now read back and verify our data made it into the journal stream.str(""); stream << std::hex << number; rc = validate_journal(TestErrorOne::ERRNUM::str_short, std::string(stream.str()).c_str()); if (rc) return (rc); // This should just be equal to what we put in test 3 rc = validate_journal(TestErrorOne::FILE_PATH::str_short, test_string); if (rc) return (rc); rc = validate_journal(TestErrorOne::FILE_NAME::str_short, "elog_test_4.txt"); if (rc) return (rc); rc = validate_journal(TestErrorTwo::DEV_ADDR::str_short, "0xDEADDEAD"); if (rc) return (rc); rc = validate_journal(TestErrorTwo::DEV_ID::str_short, "100"); if (rc) return (rc); rc = validate_journal(TestErrorTwo::DEV_NAME::str_short, "test case 4"); if (rc) return (rc); // Compile fail tests // Simple test to prove we fail to compile due to missing param // elog(TestErrorOne::ERRNUM(1), // TestErrorOne::FILE_PATH("test")); // Simple test to prove we fail to compile due to invalid param // elog(TestErrorOne::ERRNUM(1), // TestErrorOne::FILE_PATH("test"), // TestErrorOne::FILE_NAME(1)); return 0; } void commitError(const char* text) { if (std::strcmp(text, "AutoTestSimple") == 0) { try { elog( example::xyz::openbmc_project::example::elog::AutoTestSimple:: STRING("FOO")); } catch ( const example::xyz::openbmc_project::example::elog::AutoTestSimple& e) { std::cout << "elog exception caught: " << e.what() << std::endl; commit(e.name()); } } else if (std::strcmp(text, "AutoTestCreateAndCommit") == 0) { report( example::xyz::openbmc_project::example::elog::AutoTestSimple:: STRING("FOO")); } return; } int main(int argc, char* argv[]) { int arg; if (argc == 1) return elog_test(); static struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"commit", required_argument, 0, 'c'}, {0, 0, 0, 0}}; int option_index = 0; while ((arg = getopt_long(argc, argv, "hc:", long_options, &option_index)) != -1) { switch (arg) { case 'c': commitError(optarg); return 0; case 'h': case '?': std::cerr << usage; return 1; } } return 0; }