blob: eb0dd21483733f5670b428803d0c34880a5320ab [file] [log] [blame]
// A basic unit test that runs on a BMC (qemu or hardware)
#include <getopt.h>
#include <systemd/sd-journal.h>
#include <cstring>
#include <iostream>
#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/elog.hpp>
#include <phosphor-logging/log.hpp>
#include <sdbusplus/exception.hpp>
#include <sstream>
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 <string> 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<level::DEBUG>("Basic phosphor logging test");
// TEST 2 - Log with metadata field
const char* file_name = "phosphor_logging_test.txt";
int number = 0xFEFE;
log<level::DEBUG>(
"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>(
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>(
TestErrorOne::ERRNUM(number), prev_entry<TestErrorOne::FILE_PATH>(),
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>(TestErrorOne::ERRNUM(1),
// TestErrorOne::FILE_PATH("test"));
// Simple test to prove we fail to compile due to invalid param
// elog<TestErrorOne>(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>(
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>(
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;
}