blob: 5568df1b414f68dfe8ccb7f17db41aa35ecb9186 [file] [log] [blame]
// Copyright 2022 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cobalt/watchdog/watchdog.h"
#include <set>
#include <vector>
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "starboard/common/file.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cobalt {
namespace watchdog {
namespace {
const char kWatchdogViolationsJson[] = "watchdog_test.json";
const int64_t kWatchdogMonitorFrequency = 100000;
const int64_t kWatchdogSleepDuration = kWatchdogMonitorFrequency * 4;
} // namespace
class WatchdogTest : public testing::Test {
protected:
WatchdogTest() {}
void SetUp() final {
watchdog_ = new watchdog::Watchdog();
watchdog_->InitializeCustom(nullptr, std::string(kWatchdogViolationsJson),
kWatchdogMonitorFrequency);
watchdog_->GetWatchdogViolations();
}
void TearDown() final {
watchdog_->Uninitialize();
delete watchdog_;
watchdog_ = nullptr;
}
base::Value CreateDummyViolationDict(std::string desc, int begin, int end) {
base::Value violation_dict(base::Value::Type::DICTIONARY);
violation_dict.SetKey("description", base::Value(desc));
base::Value list(base::Value::Type::LIST);
for (int i = begin; i < end; i++)
list.GetList().emplace_back(CreateDummyViolation(i));
violation_dict.SetKey("violations", list.Clone());
return violation_dict.Clone();
}
base::Value CreateDummyViolation(int timestamp_violation) {
base::Value violation(base::Value::Type::DICTIONARY);
base::Value ping_infos(base::Value::Type::LIST);
violation.SetKey("pingInfos", ping_infos.Clone());
violation.SetKey("monitorState",
base::Value(std::string(GetApplicationStateString(
base::kApplicationStateStarted))));
violation.SetKey("timeIntervalMilliseconds", base::Value("0"));
violation.SetKey("timeWaitMilliseconds", base::Value("0"));
violation.SetKey("timestampRegisteredMilliseconds", base::Value("0"));
violation.SetKey("timestampLastPingedMilliseconds", base::Value("0"));
violation.SetKey("timestampViolationMilliseconds",
base::Value(std::to_string(timestamp_violation)));
violation.SetKey("violationDurationMilliseconds", base::Value("0"));
base::Value registered_clients(base::Value::Type::LIST);
violation.SetKey("registeredClients", registered_clients.Clone());
return violation.Clone();
}
watchdog::Watchdog* watchdog_;
};
TEST_F(WatchdogTest, RedundantRegistersShouldFail) {
ASSERT_TRUE(watchdog_->Register("test-name", "test-desc",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
ASSERT_FALSE(watchdog_->Register("test-name", "test-desc",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
ASSERT_TRUE(watchdog_->Register("test-name", "test-desc",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency, 0, PING));
ASSERT_TRUE(watchdog_->Register("test-name", "test-desc",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency, 0, ALL));
ASSERT_TRUE(watchdog_->Unregister("test-name"));
}
TEST_F(WatchdogTest, RegisterOnlyAcceptsValidParameters) {
ASSERT_FALSE(watchdog_->Register("test-name-1", "test-desc-1",
base::kApplicationStateStarted, 1, 0));
ASSERT_FALSE(watchdog_->Unregister("test-name-1"));
ASSERT_FALSE(watchdog_->Register("test-name-2", "test-desc-2",
base::kApplicationStateStarted, 0, 0));
ASSERT_FALSE(watchdog_->Unregister("test-name-2"));
ASSERT_FALSE(watchdog_->Register("test-name-3", "test-desc-3",
base::kApplicationStateStarted, -1, 0));
ASSERT_FALSE(watchdog_->Unregister("test-name-3"));
ASSERT_TRUE(watchdog_->Register("test-name-4", "test-desc-4",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency, 1));
ASSERT_TRUE(watchdog_->Unregister("test-name-4"));
ASSERT_TRUE(watchdog_->Register("test-name-5", "test-desc-5",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency, 0));
ASSERT_TRUE(watchdog_->Unregister("test-name-5"));
ASSERT_FALSE(watchdog_->Register("test-name-6", "test-desc-6",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency, -1));
ASSERT_FALSE(watchdog_->Unregister("test-name-6"));
}
TEST_F(WatchdogTest, RegisterByClientOnlyAcceptsValidParameters) {
std::shared_ptr<Client> client = watchdog_->RegisterByClient(
"test-name", "test-desc", base::kApplicationStateStarted, 1, 0);
ASSERT_EQ(client, nullptr);
ASSERT_FALSE(watchdog_->UnregisterByClient(client));
client = watchdog_->RegisterByClient("test-name", "test-desc",
base::kApplicationStateStarted, 0, 0);
ASSERT_EQ(client, nullptr);
ASSERT_FALSE(watchdog_->UnregisterByClient(client));
client = watchdog_->RegisterByClient("test-name", "test-desc",
base::kApplicationStateStarted, -1, 0);
ASSERT_EQ(client, nullptr);
ASSERT_FALSE(watchdog_->UnregisterByClient(client));
client = watchdog_->RegisterByClient("test-name", "test-desc",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency, 1);
ASSERT_NE(client, nullptr);
ASSERT_TRUE(watchdog_->UnregisterByClient(client));
client = watchdog_->RegisterByClient("test-name", "test-desc",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency, 0);
ASSERT_NE(client, nullptr);
ASSERT_TRUE(watchdog_->UnregisterByClient(client));
client = watchdog_->RegisterByClient("test-name", "test-desc",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency, -1);
ASSERT_EQ(client, nullptr);
ASSERT_FALSE(watchdog_->UnregisterByClient(client));
}
TEST_F(WatchdogTest, UnmatchedUnregisterShouldFail) {
ASSERT_FALSE(watchdog_->Unregister("test-name"));
ASSERT_TRUE(watchdog_->Register("test-name", "test-desc",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
ASSERT_TRUE(watchdog_->Unregister("test-name"));
ASSERT_FALSE(watchdog_->Unregister("test-name"));
}
TEST_F(WatchdogTest, UnmatchedUnregisterByClientShouldFail) {
std::shared_ptr<Client> client_test(new Client);
ASSERT_FALSE(watchdog_->UnregisterByClient(client_test));
std::shared_ptr<Client> client = watchdog_->RegisterByClient(
"test-name", "test-desc", base::kApplicationStateStarted,
kWatchdogMonitorFrequency);
ASSERT_NE(client, nullptr);
ASSERT_TRUE(watchdog_->UnregisterByClient(client));
ASSERT_FALSE(watchdog_->UnregisterByClient(client));
}
TEST_F(WatchdogTest, UnmatchedPingShouldFail) {
ASSERT_FALSE(watchdog_->Ping("test-name"));
ASSERT_TRUE(watchdog_->Register("test-name", "test-desc",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
ASSERT_TRUE(watchdog_->Ping("test-name"));
ASSERT_TRUE(watchdog_->Unregister("test-name"));
ASSERT_FALSE(watchdog_->Ping("test-name"));
}
TEST_F(WatchdogTest, UnmatchedPingByClientShouldFail) {
std::shared_ptr<Client> client_test(new Client);
ASSERT_FALSE(watchdog_->PingByClient(client_test));
std::shared_ptr<Client> client = watchdog_->RegisterByClient(
"test-name", "test-desc", base::kApplicationStateStarted,
kWatchdogMonitorFrequency);
ASSERT_NE(client, nullptr);
ASSERT_TRUE(watchdog_->PingByClient(client));
ASSERT_TRUE(watchdog_->UnregisterByClient(client));
ASSERT_FALSE(watchdog_->PingByClient(client));
}
TEST_F(WatchdogTest, PingOnlyAcceptsValidParameters) {
ASSERT_TRUE(watchdog_->Register("test-name", "test-desc",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
ASSERT_TRUE(watchdog_->Ping("test-name", "42"));
ASSERT_FALSE(watchdog_->Ping("test-name", std::string(1025, 'x')));
ASSERT_TRUE(watchdog_->Unregister("test-name"));
}
TEST_F(WatchdogTest, PingByClientOnlyAcceptsValidParameters) {
std::shared_ptr<Client> client = watchdog_->RegisterByClient(
"test-name", "test-desc", base::kApplicationStateStarted,
kWatchdogMonitorFrequency);
ASSERT_NE(client, nullptr);
ASSERT_TRUE(watchdog_->PingByClient(client, "42"));
ASSERT_FALSE(watchdog_->PingByClient(client, std::string(1025, 'x')));
ASSERT_TRUE(watchdog_->UnregisterByClient(client));
}
TEST_F(WatchdogTest, ViolationsJsonShouldPersistAndBeValid) {
ASSERT_EQ(watchdog_->GetWatchdogViolations(), "");
ASSERT_TRUE(watchdog_->Register("test-name", "test-desc",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
ASSERT_TRUE(watchdog_->Ping("test-name", "test-ping"));
SbThreadSleep(kWatchdogSleepDuration);
ASSERT_TRUE(watchdog_->Unregister("test-name"));
TearDown();
watchdog_ = new watchdog::Watchdog();
watchdog_->InitializeCustom(nullptr, std::string(kWatchdogViolationsJson),
kWatchdogMonitorFrequency);
// Validates Violation json file.
std::string json = watchdog_->GetWatchdogViolations();
ASSERT_NE(json, "");
std::unique_ptr<base::Value> violations_map = base::JSONReader::Read(json);
ASSERT_NE(violations_map, nullptr);
base::Value* violation_dict = violations_map->FindKey("test-name");
ASSERT_NE(violation_dict, nullptr);
base::Value* description = violation_dict->FindKey("description");
ASSERT_NE(description, nullptr);
ASSERT_EQ(description->GetString(), "test-desc");
base::Value* violations = violation_dict->FindKey("violations");
ASSERT_NE(violations, nullptr);
ASSERT_EQ(violations->GetList().size(), 1);
base::Value* monitor_state = violations->GetList()[0].FindKey("monitorState");
ASSERT_NE(monitor_state, nullptr);
ASSERT_EQ(
monitor_state->GetString(),
std::string(GetApplicationStateString(base::kApplicationStateStarted)));
base::Value* ping_infos = violations->GetList()[0].FindKey("pingInfos");
ASSERT_NE(ping_infos, nullptr);
ASSERT_EQ(ping_infos->GetList().size(), 1);
base::Value* info = ping_infos->GetList()[0].FindKey("info");
ASSERT_NE(info, nullptr);
ASSERT_EQ(info->GetString(), "test-ping");
base::Value* timestamp_milliseconds =
ping_infos->GetList()[0].FindKey("timestampMilliseconds");
ASSERT_NE(timestamp_milliseconds, nullptr);
std::stoll(timestamp_milliseconds->GetString());
base::Value* registered_clients =
violations->GetList()[0].FindKey("registeredClients");
ASSERT_NE(registered_clients, nullptr);
ASSERT_EQ(registered_clients->GetList().size(), 1);
ASSERT_EQ(registered_clients->GetList()[0].GetString(), "test-name");
base::Value* time_interval_milliseconds =
violations->GetList()[0].FindKey("timeIntervalMilliseconds");
ASSERT_NE(time_interval_milliseconds, nullptr);
std::stoll(time_interval_milliseconds->GetString());
base::Value* time_wait_milliseconds =
violations->GetList()[0].FindKey("timeWaitMilliseconds");
ASSERT_NE(time_wait_milliseconds, nullptr);
std::stoll(time_wait_milliseconds->GetString());
base::Value* timestamp_last_pinged_milliseconds =
violations->GetList()[0].FindKey("timestampLastPingedMilliseconds");
ASSERT_NE(timestamp_last_pinged_milliseconds, nullptr);
std::stoll(timestamp_last_pinged_milliseconds->GetString());
base::Value* timestamp_registered_milliseconds =
violations->GetList()[0].FindKey("timestampRegisteredMilliseconds");
ASSERT_NE(timestamp_registered_milliseconds, nullptr);
std::stoll(timestamp_registered_milliseconds->GetString());
base::Value* timestamp_violation_milliseconds =
violations->GetList()[0].FindKey("timestampViolationMilliseconds");
ASSERT_NE(timestamp_violation_milliseconds, nullptr);
std::stoll(timestamp_violation_milliseconds->GetString());
base::Value* violation_duration_milliseconds =
violations->GetList()[0].FindKey("violationDurationMilliseconds");
ASSERT_NE(violation_duration_milliseconds, nullptr);
std::stoll(violation_duration_milliseconds->GetString());
}
TEST_F(WatchdogTest, RedundantViolationsShouldStack) {
ASSERT_TRUE(watchdog_->Register("test-name", "test-desc",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
SbThreadSleep(kWatchdogSleepDuration);
std::string json = watchdog_->GetWatchdogViolations({}, false);
ASSERT_NE(json, "");
std::unique_ptr<base::Value> uncleared_violations_map =
base::JSONReader::Read(json);
ASSERT_NE(uncleared_violations_map, nullptr);
base::Value* violation_dict = uncleared_violations_map->FindKey("test-name");
base::Value* violations = violation_dict->FindKey("violations");
ASSERT_EQ(violations->GetList().size(), 1);
std::string uncleared_timestamp =
violations->GetList()[0]
.FindKey("timestampLastPingedMilliseconds")
->GetString();
int64_t uncleared_duration =
std::stoll(violations->GetList()[0]
.FindKey("violationDurationMilliseconds")
->GetString());
SbThreadSleep(kWatchdogSleepDuration);
json = watchdog_->GetWatchdogViolations({}, false);
ASSERT_NE(json, "");
std::unique_ptr<base::Value> violations_map = base::JSONReader::Read(json);
ASSERT_NE(violations_map, nullptr);
violation_dict = violations_map->FindKey("test-name");
violations = violation_dict->FindKey("violations");
ASSERT_EQ(violations->GetList().size(), 1);
std::string timestamp = violations->GetList()[0]
.FindKey("timestampLastPingedMilliseconds")
->GetString();
int64_t duration = std::stoll(violations->GetList()[0]
.FindKey("violationDurationMilliseconds")
->GetString());
ASSERT_EQ(uncleared_timestamp, timestamp);
ASSERT_LT(uncleared_duration, duration);
ASSERT_TRUE(watchdog_->Unregister("test-name"));
}
TEST_F(WatchdogTest, ViolationsShouldResetAfterFetch) {
ASSERT_TRUE(watchdog_->Register("test-name-1", "test-desc-1",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
SbThreadSleep(kWatchdogSleepDuration);
ASSERT_TRUE(watchdog_->Unregister("test-name-1"));
std::string json = watchdog_->GetWatchdogViolations();
ASSERT_NE(json.find("test-name-1"), std::string::npos);
ASSERT_EQ(json.find("test-name-2"), std::string::npos);
std::shared_ptr<Client> client = watchdog_->RegisterByClient(
"test-name-2", "test-desc-2", base::kApplicationStateStarted,
kWatchdogMonitorFrequency);
ASSERT_NE(client, nullptr);
SbThreadSleep(kWatchdogSleepDuration);
ASSERT_TRUE(watchdog_->UnregisterByClient(client));
json = watchdog_->GetWatchdogViolations();
ASSERT_EQ(json.find("test-name-1"), std::string::npos);
ASSERT_NE(json.find("test-name-2"), std::string::npos);
ASSERT_EQ(watchdog_->GetWatchdogViolations(), "");
}
TEST_F(WatchdogTest, PingInfosAreEvictedAfterMax) {
ASSERT_TRUE(watchdog_->Register("test-name", "test_desc",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
for (int i = 0; i < 61; i++) {
ASSERT_TRUE(watchdog_->Ping("test-name", std::to_string(i)));
}
SbThreadSleep(kWatchdogSleepDuration);
std::string json = watchdog_->GetWatchdogViolations();
ASSERT_NE(json, "");
std::unique_ptr<base::Value> violations_map = base::JSONReader::Read(json);
ASSERT_NE(violations_map, nullptr);
base::Value* violation_dict = violations_map->FindKey("test-name");
base::Value* violations = violation_dict->FindKey("violations");
base::Value* pingInfos = violations->GetList()[0].FindKey("pingInfos");
ASSERT_EQ(pingInfos->GetList().size(), 60);
ASSERT_EQ(pingInfos->GetList()[0].FindKey("info")->GetString(), "1");
ASSERT_TRUE(watchdog_->Unregister("test-name"));
}
TEST_F(WatchdogTest, ViolationsAreEvictedAfterMax) {
// Creates maxed Violation json file.
std::unique_ptr<base::Value> dummy_map =
std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
dummy_map->SetKey("test-name-1",
CreateDummyViolationDict("test-desc-1", 0, 99));
dummy_map->SetKey("test-name-2",
CreateDummyViolationDict("test-desc-2", 1, 102));
std::string json;
base::JSONWriter::Write(*dummy_map, &json);
starboard::ScopedFile file(watchdog_->GetWatchdogFilePath().c_str(),
kSbFileCreateAlways | kSbFileWrite);
file.WriteAll(json.c_str(), static_cast<int>(json.size()));
TearDown();
watchdog_ = new watchdog::Watchdog();
watchdog_->InitializeCustom(nullptr, std::string(kWatchdogViolationsJson),
kWatchdogMonitorFrequency);
ASSERT_TRUE(watchdog_->Register("test-name-3", "test-desc-3",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
ASSERT_TRUE(watchdog_->Register("test-name-4", "test-desc-4",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
SbThreadSleep(kWatchdogSleepDuration);
json = watchdog_->GetWatchdogViolations({}, false);
ASSERT_NE(json, "");
std::unique_ptr<base::Value> uncleared_violations_map =
base::JSONReader::Read(json);
ASSERT_NE(uncleared_violations_map, nullptr);
base::Value* violation_dict =
uncleared_violations_map->FindKey("test-name-1");
base::Value* violations = violation_dict->FindKey("violations");
ASSERT_EQ(violations->GetList().size(), 99);
violation_dict = uncleared_violations_map->FindKey("test-name-2");
violations = violation_dict->FindKey("violations");
ASSERT_EQ(violations->GetList().size(), 99);
ASSERT_EQ(violations->GetList()[0]
.FindKey("timestampViolationMilliseconds")
->GetString(),
"3");
violation_dict = uncleared_violations_map->FindKey("test-name-3");
violations = violation_dict->FindKey("violations");
ASSERT_EQ(violations->GetList().size(), 1);
violation_dict = uncleared_violations_map->FindKey("test-name-4");
violations = violation_dict->FindKey("violations");
ASSERT_EQ(violations->GetList().size(), 1);
ASSERT_TRUE(watchdog_->Ping("test-name-3"));
SbThreadSleep(kWatchdogSleepDuration);
json = watchdog_->GetWatchdogViolations();
ASSERT_NE(json, "");
std::unique_ptr<base::Value> violations_map = base::JSONReader::Read(json);
ASSERT_NE(violations_map, nullptr);
violation_dict = violations_map->FindKey("test-name-1");
violations = violation_dict->FindKey("violations");
ASSERT_EQ(violations->GetList().size(), 98);
ASSERT_EQ(violations->GetList()[0]
.FindKey("timestampViolationMilliseconds")
->GetString(),
"1");
violation_dict = violations_map->FindKey("test-name-2");
violations = violation_dict->FindKey("violations");
ASSERT_EQ(violations->GetList().size(), 99);
violation_dict = violations_map->FindKey("test-name-3");
violations = violation_dict->FindKey("violations");
ASSERT_EQ(violations->GetList().size(), 2);
violation_dict = violations_map->FindKey("test-name-4");
violations = violation_dict->FindKey("violations");
ASSERT_EQ(violations->GetList().size(), 1);
ASSERT_TRUE(watchdog_->Unregister("test-name-3"));
ASSERT_TRUE(watchdog_->Unregister("test-name-4"));
}
TEST_F(WatchdogTest, UpdateStateShouldPreventViolations) {
ASSERT_TRUE(watchdog_->Register("test-name", "test-desc",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
watchdog_->UpdateState(base::kApplicationStateBlurred);
SbThreadSleep(kWatchdogSleepDuration);
ASSERT_EQ(watchdog_->GetWatchdogViolations(), "");
ASSERT_TRUE(watchdog_->Unregister("test-name"));
}
TEST_F(WatchdogTest, TimeWaitShouldPreventViolations) {
ASSERT_TRUE(watchdog_->Register(
"test-name", "test-desc", base::kApplicationStateStarted,
kWatchdogMonitorFrequency,
kWatchdogSleepDuration + kWatchdogMonitorFrequency));
SbThreadSleep(kWatchdogSleepDuration);
ASSERT_EQ(watchdog_->GetWatchdogViolations(), "");
ASSERT_TRUE(watchdog_->Unregister("test-name"));
}
TEST_F(WatchdogTest, PingShouldPreventViolations) {
ASSERT_TRUE(watchdog_->Register("test-name", "test-desc",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
SbThreadSleep(kWatchdogMonitorFrequency / 2);
ASSERT_TRUE(watchdog_->Ping("test-name"));
SbThreadSleep(kWatchdogMonitorFrequency / 2);
ASSERT_TRUE(watchdog_->Ping("test-name"));
ASSERT_EQ(watchdog_->GetWatchdogViolations(), "");
SbThreadSleep(kWatchdogMonitorFrequency / 2);
ASSERT_TRUE(watchdog_->Register("test-name", "test-desc",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency, 0, PING));
SbThreadSleep(kWatchdogMonitorFrequency / 2);
ASSERT_TRUE(watchdog_->Register("test-name", "test-desc",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency, 0, PING));
ASSERT_EQ(watchdog_->GetWatchdogViolations(), "");
SbThreadSleep(kWatchdogMonitorFrequency / 2);
ASSERT_TRUE(watchdog_->Register("test-name", "test-desc",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency, 0, ALL));
SbThreadSleep(kWatchdogMonitorFrequency / 2);
ASSERT_TRUE(watchdog_->Register("test-name", "test-desc",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency, 0, ALL));
ASSERT_EQ(watchdog_->GetWatchdogViolations(), "");
ASSERT_TRUE(watchdog_->Unregister("test-name"));
}
TEST_F(WatchdogTest, PingByClientShouldPreventViolations) {
std::shared_ptr<Client> client = watchdog_->RegisterByClient(
"test-name", "test-desc", base::kApplicationStateStarted,
kWatchdogMonitorFrequency);
SbThreadSleep(kWatchdogMonitorFrequency / 2);
ASSERT_TRUE(watchdog_->PingByClient(client));
SbThreadSleep(kWatchdogMonitorFrequency / 2);
ASSERT_TRUE(watchdog_->PingByClient(client));
ASSERT_EQ(watchdog_->GetWatchdogViolations(), "");
SbThreadSleep(kWatchdogSleepDuration);
ASSERT_NE(watchdog_->GetWatchdogViolations(), "");
ASSERT_TRUE(watchdog_->UnregisterByClient(client));
}
TEST_F(WatchdogTest, UnregisterShouldPreventViolations) {
ASSERT_TRUE(watchdog_->Register("test-name", "test-desc",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
ASSERT_TRUE(watchdog_->Unregister("test-name"));
SbThreadSleep(kWatchdogSleepDuration);
ASSERT_EQ(watchdog_->GetWatchdogViolations(), "");
}
TEST_F(WatchdogTest, UnregisterByClientShouldPreventViolations) {
std::shared_ptr<Client> client = watchdog_->RegisterByClient(
"test-name", "test-desc", base::kApplicationStateStarted,
kWatchdogMonitorFrequency);
ASSERT_TRUE(watchdog_->UnregisterByClient(client));
SbThreadSleep(kWatchdogSleepDuration);
ASSERT_EQ(watchdog_->GetWatchdogViolations(), "");
}
TEST_F(WatchdogTest, KillSwitchShouldPreventViolations) {
TearDown();
watchdog_ = new watchdog::Watchdog();
watchdog_->InitializeStub();
ASSERT_TRUE(watchdog_->Register("test-name", "test-desc",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
SbThreadSleep(kWatchdogSleepDuration);
ASSERT_EQ(watchdog_->GetWatchdogViolations(), "");
ASSERT_TRUE(watchdog_->Unregister("test-name"));
}
TEST_F(WatchdogTest, FrequentConsecutiveViolationsShouldNotWrite) {
ASSERT_TRUE(watchdog_->Register("test-name", "test-desc",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
SbThreadSleep(kWatchdogSleepDuration);
std::string write_json = "";
starboard::ScopedFile read_file(watchdog_->GetWatchdogFilePath().c_str(),
kSbFileOpenOnly | kSbFileRead);
if (read_file.IsValid()) {
int64_t kFileSize = read_file.GetSize();
std::vector<char> buffer(kFileSize + 1, 0);
read_file.ReadAll(buffer.data(), kFileSize);
write_json = std::string(buffer.data());
}
ASSERT_NE(write_json, "");
ASSERT_TRUE(watchdog_->Ping("test-name"));
SbThreadSleep(kWatchdogSleepDuration);
ASSERT_TRUE(watchdog_->Unregister("test-name"));
std::string no_write_json = "";
starboard::ScopedFile read_file_again(
watchdog_->GetWatchdogFilePath().c_str(), kSbFileOpenOnly | kSbFileRead);
if (read_file_again.IsValid()) {
int64_t kFileSize = read_file_again.GetSize();
std::vector<char> buffer(kFileSize + 1, 0);
read_file_again.ReadAll(buffer.data(), kFileSize);
no_write_json = std::string(buffer.data());
}
ASSERT_NE(no_write_json, "");
ASSERT_EQ(write_json, no_write_json);
std::string json = watchdog_->GetWatchdogViolations();
ASSERT_NE(write_json, json);
}
TEST_F(WatchdogTest, GetViolationClientNames) {
ASSERT_TRUE(watchdog_->Register("test-name-1", "test-desc-1",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
ASSERT_TRUE(watchdog_->Register("test-name-2", "test-desc-2",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
SbThreadSleep(kWatchdogSleepDuration);
ASSERT_TRUE(watchdog_->Unregister("test-name-1"));
ASSERT_TRUE(watchdog_->Unregister("test-name-2"));
std::vector<std::string> names = watchdog_->GetWatchdogViolationClientNames();
ASSERT_EQ(names.size(), 2);
ASSERT_TRUE(std::find(names.begin(), names.end(), "test-name-1") !=
names.end());
ASSERT_TRUE(std::find(names.begin(), names.end(), "test-name-2") !=
names.end());
watchdog_->GetWatchdogViolations();
names = watchdog_->GetWatchdogViolationClientNames();
ASSERT_EQ(names.size(), 0);
}
TEST_F(WatchdogTest, GetPartialViolationsByClients) {
ASSERT_TRUE(watchdog_->Register("test-name-1", "test-desc-1",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
ASSERT_TRUE(watchdog_->Register("test-name-2", "test-desc-2",
base::kApplicationStateStarted,
kWatchdogMonitorFrequency));
SbThreadSleep(kWatchdogSleepDuration);
ASSERT_TRUE(watchdog_->Unregister("test-name-1"));
ASSERT_TRUE(watchdog_->Unregister("test-name-2"));
const std::vector<std::string> clients = {"test-name-1"};
std::string json = watchdog_->GetWatchdogViolations(clients);
ASSERT_NE(json, "");
std::unique_ptr<base::Value> violations_map = base::JSONReader::Read(json);
ASSERT_NE(violations_map, nullptr);
base::Value* violation_dict = violations_map->FindKey("test-name-1");
ASSERT_NE(violation_dict, nullptr);
violation_dict = violations_map->FindKey("test-name-2");
ASSERT_EQ(violation_dict, nullptr);
json = watchdog_->GetWatchdogViolations(clients);
ASSERT_EQ(json, "");
}
TEST_F(WatchdogTest, EvictOldWatchdogViolations) {
// Creates old Violation json file.
std::unique_ptr<base::Value> dummy_map =
std::make_unique<base::Value>(base::Value::Type::DICTIONARY);
dummy_map->SetKey("test-name-old",
CreateDummyViolationDict("test-desc-old", 0, 1));
std::string json;
base::JSONWriter::Write(*dummy_map, &json);
starboard::ScopedFile file(watchdog_->GetWatchdogFilePath().c_str(),
kSbFileCreateAlways | kSbFileWrite);
TearDown();
file.WriteAll(json.c_str(), static_cast<int>(json.size()));
watchdog_ = new watchdog::Watchdog();
watchdog_->InitializeCustom(nullptr, std::string(kWatchdogViolationsJson),
kWatchdogMonitorFrequency);
ASSERT_NE(watchdog_->GetWatchdogViolations({}, false), "");
ASSERT_EQ(watchdog_->GetWatchdogViolations({"test-name-new"}), "");
ASSERT_EQ(watchdog_->GetWatchdogViolations({}, false), "");
}
TEST_F(WatchdogTest, CanGetLogTrace) {
watchdog_->LogEvent("1");
watchdog_->LogEvent("2");
std::vector<std::string> expected = {"1", "2"};
ASSERT_EQ(watchdog_->GetLogTrace(), expected);
}
TEST_F(WatchdogTest, CanClearLog) {
watchdog_->LogEvent("1");
watchdog_->LogEvent("2");
watchdog_->ClearLog();
ASSERT_EQ(watchdog_->GetLogTrace().size(), 0);
}
TEST_F(WatchdogTest, ViolationContainsLogTrace) {
watchdog_->Register("test-name", "test-desc", base::kApplicationStateStarted,
kWatchdogMonitorFrequency);
watchdog_->Ping("test-name", "test-ping");
watchdog_->LogEvent("1");
watchdog_->LogEvent("2");
watchdog_->LogEvent("3");
SbThreadSleep(kWatchdogSleepDuration);
std::string json = watchdog_->GetWatchdogViolations();
std::unique_ptr<base::Value> violations_map = base::JSONReader::Read(json);
base::Value* violations =
violations_map->FindKey("test-name")->FindKey("violations");
base::Value* logTrace = violations->GetList()[0].FindKey("logTrace");
ASSERT_EQ(logTrace->GetList().size(), 3);
}
TEST_F(WatchdogTest, ViolationContainsEmptyLogTrace) {
watchdog_->Register("test-name", "test-desc", base::kApplicationStateStarted,
kWatchdogMonitorFrequency);
watchdog_->Ping("test-name", "test-ping");
SbThreadSleep(kWatchdogSleepDuration);
std::string json = watchdog_->GetWatchdogViolations();
std::unique_ptr<base::Value> violations_map = base::JSONReader::Read(json);
base::Value* violations =
violations_map->FindKey("test-name")->FindKey("violations");
base::Value* logTrace = violations->GetList()[0].FindKey("logTrace");
ASSERT_EQ(logTrace->GetList().size(), 0);
}
} // namespace watchdog
} // namespace cobalt