blob: 5b7c1500a9cfda04ba4f0de2459892acc1c59ae7 [file] [log] [blame]
// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "crash-reporter/arc_util.h"
#include <algorithm>
#include <memory>
#include <base/test/simple_test_tick_clock.h>
#include <brillo/syslog_logging.h>
#include <gtest/gtest.h>
#include <session_manager/dbus-proxy-mocks.h>
using brillo::ClearLog;
using brillo::FindLog;
using brillo::GetLog;
namespace arc_util {
namespace {
constexpr char kUnknownValue[] = "unknown";
const char kCrashLog[] = R"(Process: com.arc.app
Flags: 0xcafebabe
Package: com.arc.app v1 (1.0)
Build: fingerprint
Line 1
Line 2
Line 3
)";
} // namespace
TEST(ArcUtilTest, ParseCrashLog) {
CrashLogHeaderMap map;
std::string exception_info, log;
// Crash log should not be empty.
EXPECT_FALSE(
ParseCrashLog("system_app_crash", "", &map, &exception_info, &log));
// Header key should be followed by a colon.
EXPECT_FALSE(
ParseCrashLog("system_app_crash", "Key", &map, &exception_info, &log));
EXPECT_TRUE(FindLog("Header has unexpected format"));
ClearLog();
// Header value should not be empty.
EXPECT_FALSE(ParseCrashLog("system_app_crash", "Key: ", &map,
&exception_info, &log));
EXPECT_TRUE(FindLog("Header has unexpected format"));
ClearLog();
// Parse a crash log with exception info.
EXPECT_TRUE(ParseCrashLog("system_app_crash", kCrashLog, &map,
&exception_info, &log));
EXPECT_TRUE(GetLog().empty());
EXPECT_EQ("com.arc.app", GetCrashLogHeader(map, "Process"));
EXPECT_EQ("fingerprint", GetCrashLogHeader(map, "Build"));
EXPECT_EQ("unknown", GetCrashLogHeader(map, "Activity"));
EXPECT_EQ("Line 1\nLine 2\nLine 3\n", exception_info);
// Parse a crash log without exception info.
map.clear();
exception_info.clear();
EXPECT_TRUE(
ParseCrashLog("system_app_anr", kCrashLog, &map, &exception_info, &log));
EXPECT_TRUE(GetLog().empty());
EXPECT_EQ("0xcafebabe", GetCrashLogHeader(map, "Flags"));
EXPECT_EQ("com.arc.app v1 (1.0)", GetCrashLogHeader(map, "Package"));
EXPECT_TRUE(exception_info.empty());
}
TEST(ArcUtilTest, GetAndroidVersion) {
const std::pair<const char*, const char*> tests[] = {
// version / fingerprint
{"7.1.1",
"google/caroline/caroline_cheets:7.1.1/R65-10317.0.9999/"
"4548207:user/release-keys"},
{"7.1.1",
"google/banon/banon_cheets:7.1.1/R62-9901.77.0/"
"4446936:user/release-keys"},
{"6.0.1",
"google/cyan/cyan_cheets:6.0.1/R60-9592.85.0/"
"4284198:user/release-keys"},
{"6.0.1",
"google/minnie/minnie_cheets:6.0.1/R60-9592.96.0/"
"4328948:user/release-keys"},
{"7.1.1",
"google/cyan/cyan_cheets:7.1.1/R61-9765.85.0/"
"4391409:user/release-keys"},
{"7.1.1",
"google/banon/banon_cheets:7.1.1/R62-9901.66.0/"
"4421464:user/release-keys"},
{"7.1.1",
"google/edgar/edgar_cheets:7.1.1/R62-9901.77.0/"
"4446936:user/release-keys"},
{"7.1.1",
"google/celes/celes_cheets:7.1.1/R63-10032.75.0/"
"4505339:user/release-keys"},
{"7.1.1",
"google/edgar/edgar_cheets:7.1.1/R64-10134.0.0/"
"4453597:user/release-keys"},
{"7.1.1",
"google/fizz/fizz_cheets:7.1.1/R64-10176.13.1/"
"4496886:user/release-keys"},
{"7.1.1",
"google/kevin/kevin_cheets:7.1.1/R64-10176.22.0/"
"4510202:user/release-keys"},
{"7.1.1",
"google/celes/celes_cheets:7.1.1/R65-10278.0.0/"
"4524556:user/release-keys"},
// fake ones
{"70.10.10.10",
"google/celes/celes_cheets:70.10.10.10/R65-10278.0.0/"
"4524556:user/release-keys"},
{"7.1.1.1",
"google/celes/celes_cheets:7.1.1.1/R65-10278.0.0/"
"4524556:user/release-keys"},
{"7.1.1",
"google/celes/celes_cheets:7.1.1/R65-10278.0.0/"
"4524556:user/release-keys"},
{"7.1",
"google/celes/celes_cheets:7.1/R65-10278.0.0/"
"4524556:user/release-keys"},
{"7",
"google/celes/celes_cheets:7/R65-10278.0.0/"
"4524556:user/release-keys"},
// future-proofing tests
{"test.1",
"google/celes/celes_cheets:test.1/R65-10278.0.0/"
"4524556:user/release-keys"},
{"7.1.1a",
"google/celes/celes_cheets:7.1.1a/R65-10278.0.0/"
"4524556:user/release-keys"},
{"7a",
"google/celes/celes_cheets:7a/R65-10278.0.0/"
"4524556:user/release-keys"},
{"9", ":9/R"},
// failed ones
{kUnknownValue,
"google/celes/celes_cheets:1.1/"
"65-10278.0.0/4524556:user/release-keys"},
{kUnknownValue,
"google/celes/celes_cheets:1.1/"
"65-10278.0.0/4524556:user/7.1.1"},
{kUnknownValue,
"google/celes/celes_cheets:/"
"R65-10278.0.0/4524556:user/7.1.1"},
{kUnknownValue,
"google/celes/celes_cheets:/"
"65-10278.0.0/4524556:user/7.1.1"},
{kUnknownValue, ":/"},
{kUnknownValue, ":/R"},
{kUnknownValue, "/R:"},
{kUnknownValue, ""},
{kUnknownValue, ":"},
{kUnknownValue, "/R"},
};
for (const auto& item : tests) {
EXPECT_EQ(item.first,
GetVersionFromFingerprint(item.second).value_or(kUnknownValue));
}
}
TEST(ArcUtilTest, ListMetadataForBuildProperty) {
constexpr char kDevice[] = "rammus_cheets";
constexpr char kBoard[] = "shyvana";
constexpr char kCpuAbi[] = "x86_64";
constexpr char kFingerprint[] =
"google/rammus/rammus_cheets:11/R87-13443.0.0/6801612:user/release-keys";
constexpr char kAndroidVersionInFingerprint[] = "11";
const BuildProperty build_property = {.device = kDevice,
.board = kBoard,
.cpu_abi = kCpuAbi,
.fingerprint = kFingerprint};
std::vector<std::pair<std::string, std::string>> expected_metadata{
// key / value
{kArcVersionField, kFingerprint},
{kAndroidVersionField, kAndroidVersionInFingerprint},
{kDeviceField, kDevice},
{kBoardField, kBoard},
{kCpuAbiField, kCpuAbi},
};
std::vector<std::pair<std::string, std::string>> metadata =
ListMetadataForBuildProperty(build_property);
std::sort(expected_metadata.begin(), expected_metadata.end());
std::sort(metadata.begin(), metadata.end());
EXPECT_EQ(metadata, expected_metadata);
}
TEST(ArcUtilTest, FormatDuration) {
EXPECT_EQ(FormatDuration(base::TimeDelta()), "0s");
EXPECT_EQ(FormatDuration(base::TimeDelta::FromMilliseconds(999)), "0s");
EXPECT_EQ(FormatDuration(base::TimeDelta::FromSeconds(1)), "1s");
EXPECT_EQ(FormatDuration(base::TimeDelta::FromMinutes(2)), "2min 0s");
EXPECT_EQ(FormatDuration(base::TimeDelta::FromHours(3)), "3h 0min 0s");
EXPECT_EQ(FormatDuration(base::TimeDelta::FromDays(4)), "4d 0h 0min 0s");
EXPECT_EQ(FormatDuration(base::TimeDelta::FromHours(1) +
base::TimeDelta::FromMinutes(2) +
base::TimeDelta::FromSeconds(3)),
"1h 2min 3s");
EXPECT_EQ(FormatDuration(base::TimeDelta::FromMilliseconds(123456789)),
"1d 10h 17min 36s");
EXPECT_EQ(FormatDuration(base::TimeDelta::FromDays(365)), "365d 0h 0min 0s");
}
TEST(ArcUtilTest, GetArcContainerUptime) {
base::TimeDelta expected = base::TimeDelta::FromMilliseconds(1234567);
int64_t start_time = 1234567890;
base::SimpleTestTickClock test_clock;
test_clock.SetNowTicks(base::TimeTicks::FromInternalValue(start_time) +
expected);
auto mock =
std::make_unique<org::chromium::SessionManagerInterfaceProxyMock>();
EXPECT_CALL(*mock, GetArcStartTimeTicks)
.WillOnce(
testing::Invoke([start_time](int64_t* start_time_ptr,
brillo::ErrorPtr* error, int value) {
*start_time_ptr = start_time;
return true;
}));
base::TimeDelta actual;
EXPECT_TRUE(GetArcContainerUptime(mock.get(), &actual, &test_clock));
EXPECT_EQ(actual, expected);
}
} // namespace arc_util