#define CATCH_CONFIG_MAIN #include "catch2/catch.hpp" #include "selfdrive/common/util.h" #include "selfdrive/proclogd/proclog.h" const std::string allowed_states = "RSDTZtWXxKWPI"; TEST_CASE("Parser::procStat") { SECTION("from string") { const std::string stat_str = "33012 (code )) S 32978 6620 6620 0 -1 4194368 2042377 0 144 0 24510 11627 0 " "0 20 0 39 0 53077 830029824 62214 18446744073709551615 94257242783744 94257366235808 " "140735738643248 0 0 0 0 4098 1073808632 0 0 0 17 2 0 0 2 0 0 94257370858656 94257371248232 " "94257404952576 140735738648768 140735738648823 140735738648823 140735738650595 0"; auto stat = Parser::procStat(stat_str); REQUIRE(stat); REQUIRE(stat->pid == 33012); REQUIRE(stat->name == "code )"); REQUIRE(stat->state == 'S'); REQUIRE(stat->ppid == 32978); REQUIRE(stat->utime == 24510); REQUIRE(stat->stime == 11627); REQUIRE(stat->cutime == 0); REQUIRE(stat->cstime == 0); REQUIRE(stat->priority == 20); REQUIRE(stat->nice == 0); REQUIRE(stat->num_threads == 39); REQUIRE(stat->starttime == 53077); REQUIRE(stat->vms == 830029824); REQUIRE(stat->rss == 62214); REQUIRE(stat->processor == 2); } SECTION("all processes") { std::vector pids = Parser::pids(); REQUIRE(pids.size() > 1); int parsed_cnt = 0; for (int pid : pids) { if (auto stat = Parser::procStat(util::read_file("/proc/" + std::to_string(pid) + "/stat"))) { REQUIRE(stat->pid == pid); REQUIRE(allowed_states.find(stat->state) != std::string::npos); ++parsed_cnt; } } REQUIRE(parsed_cnt == pids.size()); } } TEST_CASE("Parser::cpuTimes") { SECTION("from string") { std::string stat = "cpu 0 0 0 0 0 0 0 0 0 0\n" "cpu0 1 2 3 4 5 6 7 8 9 10\n" "cpu1 1 2 3 4 5 6 7 8 9 10\n"; std::istringstream stream(stat); auto stats = Parser::cpuTimes(stream); REQUIRE(stats.size() == 2); for (int i = 0; i < stats.size(); ++i) { REQUIRE(stats[i].id == i); REQUIRE(stats[i].utime == 1); REQUIRE(stats[i].ntime ==2); REQUIRE(stats[i].stime == 3); REQUIRE(stats[i].itime == 4); REQUIRE(stats[i].iowtime == 5); REQUIRE(stats[i].irqtime == 6); REQUIRE(stats[i].sirqtime == 7); } } SECTION("all cpus") { std::istringstream stream(util::read_file("/proc/stat")); auto stats = Parser::cpuTimes(stream); REQUIRE(stats.size() == sysconf(_SC_NPROCESSORS_ONLN)); for (int i = 0; i < stats.size(); ++i) { REQUIRE(stats[i].id == i); } } } TEST_CASE("Parser::memInfo") { SECTION("from string") { std::istringstream stream("MemTotal: 1024 kb\nMemFree: 2048 kb\n"); auto meminfo = Parser::memInfo(stream); REQUIRE(meminfo["MemTotal:"] == 1024 * 1024); REQUIRE(meminfo["MemFree:"] == 2048 * 1024); } SECTION("from /proc/meminfo") { std::string require_keys[] = {"MemTotal:", "MemFree:", "MemAvailable:", "Buffers:", "Cached:", "Active:", "Inactive:", "Shmem:"}; std::istringstream stream(util::read_file("/proc/meminfo")); auto meminfo = Parser::memInfo(stream); for (auto &key : require_keys) { REQUIRE(meminfo.find(key) != meminfo.end()); REQUIRE(meminfo[key] > 0); } } } void test_cmdline(std::string cmdline, const std::vector requires) { std::stringstream ss; ss.write(&cmdline[0], cmdline.size()); auto cmds = Parser::cmdline(ss); REQUIRE(cmds.size() == requires.size()); for (int i = 0; i < requires.size(); ++i) { REQUIRE(cmds[i] == requires[i]); } } TEST_CASE("Parser::cmdline") { test_cmdline(std::string("a\0b\0c\0", 7), {"a", "b", "c"}); test_cmdline(std::string("a\0\0c\0", 6), {"a", "c"}); test_cmdline(std::string("a\0b\0c\0\0\0", 9), {"a", "b", "c"}); } TEST_CASE("buildProcLogerMessage") { std::vector current_pids = Parser::pids(); MessageBuilder msg; buildProcLogMessage(msg); kj::Array buf = capnp::messageToFlatArray(msg); capnp::FlatArrayMessageReader reader(buf); auto log = reader.getRoot().getProcLog(); REQUIRE(log.totalSize().wordCount > 0); // test cereal::ProcLog::CPUTimes auto cpu_times = log.getCpuTimes(); REQUIRE(cpu_times.size() == sysconf(_SC_NPROCESSORS_ONLN)); REQUIRE(cpu_times[cpu_times.size() - 1].getCpuNum() == cpu_times.size() - 1); // test cereal::ProcLog::Mem auto mem = log.getMem(); REQUIRE(mem.getTotal() > 0); REQUIRE(mem.getShared() > 0); // test cereal::ProcLog::Process auto procs = log.getProcs(); REQUIRE(procs.size() == current_pids.size()); for (auto p : procs) { REQUIRE_THAT(current_pids, Catch::Matchers::VectorContains(p.getPid())); REQUIRE(allowed_states.find(p.getState()) != std::string::npos); if (p.getPid() == ::getpid()) { REQUIRE(p.getName() == "test_proclog"); REQUIRE(p.getState() == 'R'); REQUIRE_THAT(p.getExe().cStr(), Catch::Matchers::Contains("test_proclog")); } } }