blob: e163cc5bc47163b9ae3fa7aba0b070701c54fed4 [file] [log] [blame]
// Copyright 2020 The Chromium 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 "chrome/browser/permissions/permission_actions_history.h"
#include <vector>
#include "base/containers/adapters.h"
#include "base/optional.h"
#include "base/util/values/values_util.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/permissions/permission_request_enums.h"
#include "components/permissions/request_type.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "components/prefs/testing_pref_service.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
struct TestEntry {
permissions::PermissionAction action;
permissions::RequestType type;
bool advance_clock;
} kTestEntries[]{
{permissions::PermissionAction::DISMISSED,
permissions::RequestType::kNotifications, true},
{permissions::PermissionAction::GRANTED,
permissions::RequestType::kNotifications, false},
{permissions::PermissionAction::DISMISSED,
permissions::RequestType::kVrSession, true},
{permissions::PermissionAction::IGNORED,
permissions::RequestType::kCameraStream, false},
{permissions::PermissionAction::DISMISSED,
permissions::RequestType::kGeolocation, false},
{permissions::PermissionAction::DENIED,
permissions::RequestType::kNotifications, true},
{permissions::PermissionAction::GRANTED,
permissions::RequestType::kNotifications, false},
};
} // namespace
class PermissionActionHistoryTest : public testing::Test {
public:
PermissionActionHistoryTest()
: testing_profile_(std::make_unique<TestingProfile>()) {}
~PermissionActionHistoryTest() override = default;
void SetUp() override {
testing::Test::SetUp();
RecordSetUpActions();
}
PermissionActionHistoryTest(const PermissionActionHistoryTest&) =
delete;
PermissionActionHistoryTest& operator=(
const PermissionActionHistoryTest&) = delete;
PermissionActionsHistory* GetPermissionActionsHistory() {
return PermissionActionsHistory::GetForProfile(profile());
}
std::vector<PermissionActionsHistory::Entry> GetHistory(
base::Optional<permissions::RequestType> type) {
if (type.has_value())
return GetPermissionActionsHistory()->GetHistory(base::Time(),
type.value());
else
return GetPermissionActionsHistory()->GetHistory(base::Time());
}
void RecordSetUpActions() {
// Record the actions needed to support test cases. This is the structure
// 3-days ago: {notification, dismissed}
// 2-days ago: {notification, granted}, {vr, dismissed}
// 1-days ago: {geolocation, ignored}, {camera, dismissed}, {notification,
// denied}
// 0-days ago: {notification, granted}
for (const auto& entry : kTestEntries) {
GetPermissionActionsHistory()->RecordAction(entry.action,
entry.type);
if (entry.advance_clock)
task_environment_.AdvanceClock(base::TimeDelta::FromDays(1));
}
}
TestingProfile* profile() { return testing_profile_.get(); }
private:
content::BrowserTaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
std::unique_ptr<TestingProfile> testing_profile_;
};
TEST_F(PermissionActionHistoryTest, GetHistorySortedOrder) {
auto all_entries = GetHistory(base::nullopt);
EXPECT_EQ(7u, all_entries.size());
size_t index = 0;
for (const auto& entry : kTestEntries)
EXPECT_EQ(entry.action, all_entries[index++].action);
for (const auto& request_type : {permissions::RequestType::kVrSession,
permissions::RequestType::kCameraStream,
permissions::RequestType::kGeolocation,
permissions::RequestType::kNotifications}) {
auto permission_entries = GetHistory(request_type);
index = 0;
for (const auto& entry : kTestEntries) {
if (entry.type != request_type) {
continue;
}
EXPECT_EQ(entry.action, permission_entries[index++].action);
}
}
auto entries_1_day = GetPermissionActionsHistory()->GetHistory(
base::Time::Now() - base::TimeDelta::FromDays(1));
EXPECT_TRUE(std::equal(entries_1_day.begin(), entries_1_day.end(),
std::vector<PermissionActionsHistory::Entry>(
all_entries.begin() + 3, all_entries.end())
.begin()));
}
TEST_F(PermissionActionHistoryTest, NotificationRecordAction) {
size_t general_count = GetHistory(base::nullopt).size();
size_t notification_count =
GetHistory(permissions::RequestType::kNotifications).size();
GetPermissionActionsHistory()->RecordAction(
permissions::PermissionAction::GRANTED,
permissions::RequestType::kNotifications);
EXPECT_EQ(general_count + 1, GetHistory(base::nullopt).size());
EXPECT_EQ(notification_count + 1,
GetHistory(permissions::RequestType::kNotifications).size());
GetPermissionActionsHistory()->RecordAction(
permissions::PermissionAction::GRANTED,
permissions::RequestType::kGeolocation);
EXPECT_EQ(general_count + 2, GetHistory(base::nullopt).size());
EXPECT_EQ(notification_count + 1,
GetHistory(permissions::RequestType::kNotifications).size());
}
TEST_F(PermissionActionHistoryTest, ClearHistory) {
struct {
base::Time begin;
base::Time end;
size_t generic_count;
size_t notifications_count;
} kTests[] = {
// Misc and baseline tests cases.
{base::Time(), base::Time::Max(), 0, 0},
{base::Time(), base::Time::Now(), 1, 1},
{base::Time(), base::Time::Now() + base::TimeDelta::FromMicroseconds(1),
0, 0},
// Test cases specifying only the upper bound.
{base::Time(), base::Time::Now() - base::TimeDelta::FromDays(1), 4, 2},
{base::Time(), base::Time::Now() - base::TimeDelta::FromDays(2), 6, 3},
{base::Time(), base::Time::Now() - base::TimeDelta::FromDays(3), 7, 4},
// Test cases specifying only the lower bound.
{base::Time::Now() - base::TimeDelta::FromDays(3), base::Time::Max(), 0,
0},
{base::Time::Now() - base::TimeDelta::FromDays(2), base::Time::Max(), 1,
1},
{base::Time::Now() - base::TimeDelta::FromDays(1), base::Time::Max(), 3,
2},
{base::Time::Now(), base::Time::Max(), 6, 3},
// Test cases with both bounds.
{base::Time::Now() - base::TimeDelta::FromDays(3),
base::Time::Now() + base::TimeDelta::FromMicroseconds(1), 0, 0},
{base::Time::Now() - base::TimeDelta::FromDays(3), base::Time::Now(), 1,
1},
{base::Time::Now() - base::TimeDelta::FromDays(3),
base::Time::Now() - base::TimeDelta::FromDays(1), 4, 2},
{base::Time::Now() - base::TimeDelta::FromDays(3),
base::Time::Now() - base::TimeDelta::FromDays(2), 6, 3},
{base::Time::Now() - base::TimeDelta::FromDays(3),
base::Time::Now() - base::TimeDelta::FromDays(3), 7, 4},
{base::Time::Now() - base::TimeDelta::FromDays(2),
base::Time::Now() + base::TimeDelta::FromMicroseconds(1), 1, 1},
{base::Time::Now() - base::TimeDelta::FromDays(2), base::Time::Now(), 2,
2},
{base::Time::Now() - base::TimeDelta::FromDays(2),
base::Time::Now() - base::TimeDelta::FromDays(1), 5, 3},
{base::Time::Now() - base::TimeDelta::FromDays(2),
base::Time::Now() - base::TimeDelta::FromDays(2), 7, 4},
{base::Time::Now() - base::TimeDelta::FromDays(1),
base::Time::Now() + base::TimeDelta::FromMicroseconds(1), 3, 2},
{base::Time::Now() - base::TimeDelta::FromDays(1), base::Time::Now(), 4,
3},
{base::Time::Now() - base::TimeDelta::FromDays(1),
base::Time::Now() - base::TimeDelta::FromDays(1), 7, 4},
{base::Time::Now(),
base::Time::Now() + base::TimeDelta::FromMicroseconds(1), 6, 3},
{base::Time::Now(), base::Time::Now(), 7, 4},
};
// We need to account for much we have already advanced the time for each test
// case and so we keep track of how much we need to offset the initial test
// values.
base::TimeDelta current_offset;
for (auto& test : kTests) {
test.begin += current_offset;
test.end += current_offset;
GetPermissionActionsHistory()->ClearHistory(test.begin, test.end);
EXPECT_EQ(test.generic_count, GetHistory(base::nullopt).size());
EXPECT_EQ(test.notifications_count,
GetHistory(permissions::RequestType::kNotifications).size());
// Clean up for next test and update offset.
base::Time last_now = base::Time::Now();
GetPermissionActionsHistory()->ClearHistory(base::Time(),
base::Time::Max());
RecordSetUpActions();
current_offset += base::Time::Now() - last_now;
}
}