Commit a100f65b authored by Igor Tukh's avatar Igor Tukh Committed by Commit Bot

[Permissions Auditing] Add PermissionAuditingService and PermissionAuditingServiceFactory.

PermissionAuditingService is a service which allows to store and audit the basic information about the permissions usage.

Bug: 1152769
Change-Id: If22ed0ad189eca8dbdd8502d3a1151d7561aeffc
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2517443
Commit-Queue: Balazs Engedy <engedy@chromium.org>
Reviewed-by: default avatarVasilii Sukhanov <vasilii@chromium.org>
Reviewed-by: default avatarBalazs Engedy <engedy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#831018}
parent 5aea6042
......@@ -1151,6 +1151,8 @@ static_library("browser") {
"permissions/last_tab_standing_tracker_observer.h",
"permissions/last_tab_standing_tracker_tab_helper.cc",
"permissions/last_tab_standing_tracker_tab_helper.h",
"permissions/permission_auditing_service_factory.cc",
"permissions/permission_auditing_service_factory.h",
"permissions/permission_decision_auto_blocker_factory.cc",
"permissions/permission_decision_auto_blocker_factory.h",
"permissions/permission_manager_factory.cc",
......
// 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_auditing_service_factory.h"
#include "base/feature_list.h"
#include "base/memory/singleton.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "chrome/browser/after_startup_task_utils.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_features.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/permissions/permission_auditing_service.h"
PermissionAuditingServiceFactory::PermissionAuditingServiceFactory()
: BrowserContextKeyedServiceFactory(
"PermissionAuditingService",
BrowserContextDependencyManager::GetInstance()) {}
PermissionAuditingServiceFactory::~PermissionAuditingServiceFactory() = default;
// static
PermissionAuditingServiceFactory*
PermissionAuditingServiceFactory::GetInstance() {
return base::Singleton<PermissionAuditingServiceFactory>::get();
}
// static
permissions::PermissionAuditingService*
PermissionAuditingServiceFactory::GetForProfile(Profile* profile) {
return static_cast<permissions::PermissionAuditingService*>(
GetInstance()->GetServiceForBrowserContext(profile, /*create=*/true));
}
bool PermissionAuditingServiceFactory::ServiceIsCreatedWithBrowserContext()
const {
return true;
}
KeyedService* PermissionAuditingServiceFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const {
if (!base::FeatureList::IsEnabled(features::kPermissionAuditing)) {
return nullptr;
}
auto backend_task_runner = base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE,
base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
auto* instance =
new permissions::PermissionAuditingService(backend_task_runner);
base::FilePath database_path =
context->GetPath().Append(FILE_PATH_LITERAL("Permission Auditing Logs"));
instance->Init(database_path);
AfterStartupTaskUtils::PostTask(
FROM_HERE, backend_task_runner,
base::BindOnce(&permissions::PermissionAuditingService::
StartPeriodicCullingOfExpiredSessions,
instance->AsWeakPtr()));
return instance;
}
// 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.
#ifndef CHROME_BROWSER_PERMISSIONS_PERMISSION_AUDITING_SERVICE_FACTORY_H_
#define CHROME_BROWSER_PERMISSIONS_PERMISSION_AUDITING_SERVICE_FACTORY_H_
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
class Profile;
namespace base {
template <typename T>
struct DefaultSingletonTraits;
}
namespace permissions {
class PermissionAuditingService;
}
class PermissionAuditingServiceFactory
: public BrowserContextKeyedServiceFactory {
public:
static PermissionAuditingServiceFactory* GetInstance();
// Creates a permission auditing service for the given `profile`. Will return
// nullptr in case if |profile| is off-the-record or if `kPermissionAuditing`
// feature is disabled.
static permissions::PermissionAuditingService* GetForProfile(
Profile* profile);
PermissionAuditingServiceFactory(const PermissionAuditingServiceFactory&) =
delete;
PermissionAuditingServiceFactory& operator=(
const PermissionAuditingServiceFactory&) = delete;
PermissionAuditingServiceFactory(PermissionAuditingServiceFactory&&) = delete;
PermissionAuditingServiceFactory& operator=(
PermissionAuditingServiceFactory&&) = delete;
private:
friend struct base::DefaultSingletonTraits<PermissionAuditingServiceFactory>;
PermissionAuditingServiceFactory();
~PermissionAuditingServiceFactory() override;
// BrowserContextKeyedServiceFactory:
bool ServiceIsCreatedWithBrowserContext() const override;
KeyedService* BuildServiceInstanceFor(
content::BrowserContext* context) const override;
};
#endif // CHROME_BROWSER_PERMISSIONS_PERMISSION_AUDITING_SERVICE_FACTORY_H_
......@@ -53,6 +53,7 @@
#include "chrome/browser/password_manager/password_store_factory.h"
#include "chrome/browser/permissions/adaptive_quiet_notification_permission_ui_enabler.h"
#include "chrome/browser/permissions/last_tab_standing_tracker_factory.h"
#include "chrome/browser/permissions/permission_auditing_service_factory.h"
#include "chrome/browser/persisted_state_db/persisted_state_db_factory.h"
#include "chrome/browser/plugins/plugin_prefs_factory.h"
#include "chrome/browser/policy/cloud/user_cloud_policy_invalidator_factory.h"
......@@ -96,6 +97,7 @@
#include "chrome/browser/unified_consent/unified_consent_service_factory.h"
#include "chrome/browser/web_data_service_factory.h"
#include "chrome/common/buildflags.h"
#include "chrome/common/chrome_features.h"
#include "components/captive_portal/core/buildflags.h"
#include "components/permissions/features.h"
#include "components/reading_list/features/reading_list_switches.h"
......@@ -334,6 +336,7 @@ void ChromeBrowserMainExtraPartsProfiles::
NTPResourceCacheFactory::GetInstance();
#endif
PasswordStoreFactory::GetInstance();
PermissionAuditingServiceFactory::GetInstance();
PersistedStateDBFactory::GetInstance();
#if !defined(OS_ANDROID)
PinnedTabServiceFactory::GetInstance();
......
......@@ -656,6 +656,11 @@ const base::Feature kPerAppTimeLimits{"PerAppTimeLimits",
base::FEATURE_ENABLED_BY_DEFAULT};
#endif
// Keep a client-side log of when websites access permission-gated capabilities
// to allow the user to audit usage.
const base::Feature kPermissionAuditing{"PermissionAuditing",
base::FEATURE_DISABLED_BY_DEFAULT};
// Enables using the prediction service for permission prompts.
const base::Feature kPermissionPredictions{"PermissionPredictions",
base::FEATURE_DISABLED_BY_DEFAULT};
......
......@@ -436,6 +436,9 @@ COMPONENT_EXPORT(CHROME_FEATURES)
extern const base::Feature kPerAppTimeLimits;
#endif
COMPONENT_EXPORT(CHROME_FEATURES)
extern const base::Feature kPermissionAuditing;
COMPONENT_EXPORT(CHROME_FEATURES)
extern const base::Feature kPermissionPredictions;
......
......@@ -27,6 +27,8 @@ source_set("permissions") {
"notification_permission_ui_selector.h",
"permission_auditing_database.cc",
"permission_auditing_database.h",
"permission_auditing_service.cc",
"permission_auditing_service.h",
"permission_context_base.cc",
"permission_context_base.h",
"permission_decision_auto_blocker.cc",
......@@ -145,6 +147,7 @@ source_set("unit_tests") {
"chooser_context_base_unittest.cc",
"contexts/geolocation_permission_context_unittest.cc",
"permission_auditing_database_unittest.cc",
"permission_auditing_service_unittest.cc",
"permission_context_base_unittest.cc",
"permission_decision_auto_blocker_unittest.cc",
"permission_manager_unittest.cc",
......
......@@ -53,6 +53,7 @@ PermissionAuditingDatabase::PermissionAuditingDatabase() = default;
PermissionAuditingDatabase::~PermissionAuditingDatabase() = default;
bool PermissionAuditingDatabase::Init(const base::FilePath& path) {
db_.set_histogram_tag("Permission Auditing Logs");
if (!db_.Open(path)) {
return false;
}
......
......@@ -47,7 +47,7 @@ class PermissionAuditingDatabase {
// Appends a new permission usage `session` of the given permission `type` on
// a given `origin`. The `session` must be valid according to IsValid().
// Operation will fail in case if a session with the same primary key, that
// Operation will fail if a session with the same primary key, that
// is, origin, type, and usage start time, already exists in the database.
// Returns if the operation was successful.
bool StorePermissionUsage(const PermissionUsageSession& session);
......
// 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 "components/permissions/permission_auditing_service.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/files/file_util.h"
#include "components/permissions/permission_auditing_database.h"
namespace {
// Specifies the permissions usage session lifetime. Each session older
// than this value is to be deleted.
constexpr base::TimeDelta kUsageSessionMaxAge = base::TimeDelta::FromDays(90);
// Specifies the time period between the regular sessions deletions.
constexpr base::TimeDelta kUsageSessionCullingInterval =
base::TimeDelta::FromMinutes(30);
} // namespace
namespace permissions {
PermissionAuditingService::PermissionAuditingService(
scoped_refptr<base::SequencedTaskRunner> backend_task_runner)
: backend_task_runner_(backend_task_runner) {}
PermissionAuditingService::~PermissionAuditingService() {
if (db_) {
backend_task_runner_->DeleteSoon(FROM_HERE, db_);
db_ = nullptr;
}
}
void PermissionAuditingService::Init(const base::FilePath& database_path) {
DCHECK(!db_);
db_ = new PermissionAuditingDatabase();
backend_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(base::IgnoreResult(&PermissionAuditingDatabase::Init),
base::Unretained(db_), database_path));
}
void PermissionAuditingService::StartPeriodicCullingOfExpiredSessions() {
timer_.Start(
FROM_HERE, kUsageSessionCullingInterval,
base::BindRepeating(&PermissionAuditingService::ExpireOldSessions,
this->AsWeakPtr()));
}
void PermissionAuditingService::StorePermissionUsage(
const PermissionUsageSession& session) {
DCHECK(db_);
backend_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
base::IgnoreResult(&PermissionAuditingDatabase::StorePermissionUsage),
base::Unretained(db_), session));
}
void PermissionAuditingService::GetPermissionUsageHistory(
ContentSettingsType type,
const url::Origin& origin,
base::Time start_time,
PermissionUsageHistoryCallback result_callback) {
DCHECK(db_);
backend_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&PermissionAuditingDatabase::GetPermissionUsageHistory,
base::Unretained(db_), type, origin, start_time),
std::move(result_callback));
}
void PermissionAuditingService::GetLastPermissionUsageTime(
ContentSettingsType type,
const url::Origin& origin,
LastPermissionUsageTimeCallback result_callback) {
DCHECK(db_);
backend_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&PermissionAuditingDatabase::GetLastPermissionUsageTime,
base::Unretained(db_), type, origin),
std::move(result_callback));
}
void PermissionAuditingService::UpdateEndTime(ContentSettingsType type,
const url::Origin& origin,
base::Time start_time,
base::Time new_end_time) {
DCHECK(db_);
backend_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
base::IgnoreResult(&PermissionAuditingDatabase::UpdateEndTime),
base::Unretained(db_), type, origin, start_time, new_end_time));
}
void PermissionAuditingService::DeleteSessionsBetween(base::Time start,
base::Time end) {
DCHECK(db_);
backend_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(base::IgnoreResult(
&PermissionAuditingDatabase::DeleteSessionsBetween),
base::Unretained(db_), start, end));
}
void PermissionAuditingService::ExpireOldSessions() {
DCHECK(db_);
backend_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(base::IgnoreResult(
&PermissionAuditingDatabase::DeleteSessionsBetween),
base::Unretained(db_), base::Time(),
base::Time::Now() - kUsageSessionMaxAge));
}
// static
base::TimeDelta PermissionAuditingService::GetUsageSessionMaxAge() {
return kUsageSessionMaxAge;
}
// static
base::TimeDelta PermissionAuditingService::GetUsageSessionCullingInterval() {
return kUsageSessionCullingInterval;
}
} // namespace permissions
// 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.
#ifndef COMPONENTS_PERMISSIONS_PERMISSION_AUDITING_SERVICE_H_
#define COMPONENTS_PERMISSIONS_PERMISSION_AUDITING_SERVICE_H_
#include "base/callback_forward.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner.h"
#include "base/timer/timer.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/keyed_service/core/keyed_service.h"
#include "url/origin.h"
namespace base {
class FilePath;
class Time;
class TimeDelta;
} // namespace base
namespace permissions {
class PermissionAuditingDatabase;
struct PermissionUsageSession;
// Keeps a client-side log of when websites use permission-gated capabilities to
// allow the user to audit usage.
//
// For each combination of permission type and origin, the history is
// stored on disk as a series of PermissionUsageSessions. Sessions expire
// at the latest after 3 months, or when browsing data or history is cleared.
class PermissionAuditingService
: public KeyedService,
public base::SupportsWeakPtr<PermissionAuditingService> {
public:
typedef base::OnceCallback<void(std::vector<PermissionUsageSession>)>
PermissionUsageHistoryCallback;
typedef base::OnceCallback<void(base::Optional<base::Time>)>
LastPermissionUsageTimeCallback;
explicit PermissionAuditingService(
scoped_refptr<base::SequencedTaskRunner> backend_task_runner);
~PermissionAuditingService() override;
// Initializes Permission Auditing database in `database_path`.
void Init(const base::FilePath& database_path);
// Starts the periodic deletions of outdated sessions.
void StartPeriodicCullingOfExpiredSessions();
// Appends a new permission usage `session` of the given permission `type` on
// a given `origin`. `session` must be valid according to IsValid().
// Operation will fail if a session with the same primary key, that is,
// origin, type, and usage start time, already exists.
void StorePermissionUsage(const PermissionUsageSession& session);
// Returns the detailed history stored for the permission `type` on a given
// `origin` from the specified `start_time` inclusive. The `origin` must not
// be opaque. History is provided via `result_callback`. History isn't ordered
// in any way.
void GetPermissionUsageHistory(
ContentSettingsType type,
const url::Origin& origin,
base::Time start_time,
PermissionUsageHistoryCallback result_callback);
// Returns when the given permission `type` was last used on a given `origin`.
// The `origin` must not be opaque. Time is provided via `result_callback`.
void GetLastPermissionUsageTime(
ContentSettingsType type,
const url::Origin& origin,
LastPermissionUsageTimeCallback result_callback);
// Updates the usage end time for a specific usage session. The session is
// identified by the primary key {`type`, `origin`, `start_time`}, and must
// already exist. `start_time` and `new_end_time` must be not null, and
// `start_time` must be less than or equal to `new_end_time`.
void UpdateEndTime(ContentSettingsType type,
const url::Origin& origin,
base::Time start_time,
base::Time new_end_time);
// Deletes permission usage sessions, which started or ended in the given
// time range inclusive. A null `start_time` or `end_time` time is treated as
// -inf and +inf, respectively.
void DeleteSessionsBetween(base::Time start, base::Time end);
// Returns sessions maximum lifetime.
static base::TimeDelta GetUsageSessionMaxAge();
// Returns the time delta between two consequent expiration iterations.
static base::TimeDelta GetUsageSessionCullingInterval();
private:
void ExpireOldSessions();
scoped_refptr<base::SequencedTaskRunner> backend_task_runner_;
// Lives on the |backend_task_runner_|, and must only be accessed on that
// sequence. It is safe to assume the database is alive as long as |db_| is
// non-null.
PermissionAuditingDatabase* db_ = nullptr;
base::RepeatingTimer timer_;
};
} // namespace permissions
#endif // COMPONENTS_PERMISSIONS_PERMISSION_AUDITING_SERVICE_H_
// 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 "components/permissions/permission_auditing_service.h"
#include <memory>
#include <vector>
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/time/clock.h"
#include "components/permissions/permission_usage_session.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace permissions {
using ::testing::ElementsAre;
using ::testing::IsEmpty;
using ::testing::UnorderedElementsAre;
namespace {
constexpr base::Time kTestTimes[] = {
base::Time() + base::TimeDelta::FromDays(1),
base::Time() + base::TimeDelta::FromDays(2),
base::Time() + base::TimeDelta::FromDays(3)};
constexpr ContentSettingsType kTestTypes[] = {
ContentSettingsType::MEDIASTREAM_MIC,
ContentSettingsType::MEDIASTREAM_CAMERA};
constexpr const char* kTestOrigins[] = {
"https://foo1.com", "https://foo2.com", "https://foo3.com",
"https://foo4.com", "https://foo5.com",
};
PermissionUsageSession BuildUsageSession(base::Time usage_start_time,
base::Time usage_end_time) {
return {.origin = url::Origin::Create(GURL(kTestOrigins[0])),
.type = kTestTypes[0],
.usage_start = usage_start_time,
.usage_end = usage_end_time,
.had_user_activation = false,
.was_foreground = false,
.had_focus = false};
}
PermissionUsageSession BuildUsageSession(ContentSettingsType type,
const url::Origin& origin) {
return {.origin = origin,
.type = type,
.usage_start = kTestTimes[0],
.usage_end = kTestTimes[1],
.had_user_activation = false,
.was_foreground = false,
.had_focus = false};
}
} // namespace
class PermissionAuditingServiceTest : public testing::Test {
public:
PermissionAuditingServiceTest() = default;
protected:
PermissionAuditingService& service() { return *service_.get(); }
base::test::TaskEnvironment& task_environment() { return task_environment_; }
void SetUp() override {
backend_task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE});
service_ =
std::make_unique<PermissionAuditingService>(backend_task_runner_);
ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
base::FilePath database_path = temp_directory_.GetPath().Append(
FILE_PATH_LITERAL("test_permission_auditing_database"));
service_->Init(database_path);
service_->StartPeriodicCullingOfExpiredSessions();
}
void TearDown() override {
// Ensure the database is destroyed on the |backend_task_runner_|.
service_.reset();
task_environment_.RunUntilIdle();
}
std::vector<PermissionUsageSession> GetPermissionUsageHistory(
ContentSettingsType type,
const url::Origin& origin,
base::Time start_time) {
base::RunLoop run_loop;
std::vector<PermissionUsageSession> history;
service().GetPermissionUsageHistory(
type, origin, start_time,
base::BindLambdaForTesting(
[&](std::vector<PermissionUsageSession> sessions) {
history = std::move(sessions);
run_loop.QuitWhenIdle();
}));
run_loop.Run();
return history;
}
base::Time GetLastPermissionUsageTime(ContentSettingsType type,
const url::Origin& origin) {
base::RunLoop run_loop;
base::Time last_usage_time;
service().GetLastPermissionUsageTime(
type, origin,
base::BindLambdaForTesting([&](base::Optional<base::Time> time) {
last_usage_time = time.value_or(base::Time());
run_loop.QuitWhenIdle();
}));
run_loop.Run();
return last_usage_time;
}
private:
base::ScopedTempDir temp_directory_;
std::unique_ptr<PermissionAuditingService> service_;
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
scoped_refptr<base::SequencedTaskRunner> backend_task_runner_;
};
TEST_F(PermissionAuditingServiceTest, StorePermissionUsage) {
std::vector<url::Origin> origins(base::size(kTestOrigins));
std::vector<PermissionUsageSession> sessions(base::size(kTestOrigins));
for (size_t i = 0; i < base::size(kTestOrigins); ++i) {
origins[i] = url::Origin::Create(GURL(kTestOrigins[i]));
sessions[i] = BuildUsageSession(kTestTypes[i % 2], origins[i]);
service().StorePermissionUsage(sessions[i]);
}
for (size_t i = 0; i < base::size(kTestOrigins); ++i) {
EXPECT_THAT(
GetPermissionUsageHistory(kTestTypes[i % 2], origins[i], base::Time()),
ElementsAre(sessions[i]));
}
}
TEST_F(PermissionAuditingServiceTest, GetLastPermissionUsageTime) {
std::vector<url::Origin> origins(base::size(kTestOrigins));
for (size_t i = 0; i < base::size(kTestOrigins); ++i) {
origins[i] = url::Origin::Create(GURL(kTestOrigins[i]));
service().StorePermissionUsage(
BuildUsageSession(kTestTypes[0], origins[i]));
task_environment().FastForwardBy(base::TimeDelta());
EXPECT_EQ(GetLastPermissionUsageTime(kTestTypes[0], origins[i]),
kTestTimes[1]);
}
}
TEST_F(PermissionAuditingServiceTest, UpdateEndTime) {
std::vector<url::Origin> origins(base::size(kTestOrigins));
for (size_t i = 0; i < base::size(kTestOrigins); ++i) {
origins[i] = url::Origin::Create(GURL(kTestOrigins[i]));
service().StorePermissionUsage(
BuildUsageSession(kTestTypes[1], origins[i]));
}
for (const auto& origin : origins) {
service().UpdateEndTime(kTestTypes[1], origin, kTestTimes[0],
kTestTimes[2]);
EXPECT_EQ(GetLastPermissionUsageTime(kTestTypes[1], origin), kTestTimes[2]);
}
}
TEST_F(PermissionAuditingServiceTest, DeleteSessionsBetween) {
auto session1 = BuildUsageSession(kTestTimes[0], kTestTimes[1]);
auto session2 = BuildUsageSession(kTestTimes[1], kTestTimes[2]);
auto origin = url::Origin::Create(GURL(kTestOrigins[0]));
auto type = session1.type;
session1.origin = origin;
session2.origin = origin;
auto store_sessions = [&]() {
service().StorePermissionUsage(session1);
service().StorePermissionUsage(session2);
task_environment().FastForwardBy(base::TimeDelta());
};
auto history = [&]() -> std::vector<PermissionUsageSession> {
return GetPermissionUsageHistory(type, origin, base::Time());
};
store_sessions();
ASSERT_THAT(history(), UnorderedElementsAre(session1, session2));
service().DeleteSessionsBetween(kTestTimes[0], kTestTimes[1]);
ASSERT_THAT(history(), IsEmpty());
store_sessions();
ASSERT_THAT(history(), UnorderedElementsAre(session1, session2));
service().DeleteSessionsBetween(kTestTimes[1], kTestTimes[2]);
ASSERT_THAT(history(), IsEmpty());
store_sessions();
ASSERT_THAT(history(), UnorderedElementsAre(session1, session2));
service().DeleteSessionsBetween(kTestTimes[0], kTestTimes[2]);
ASSERT_THAT(history(), IsEmpty());
store_sessions();
ASSERT_THAT(history(), UnorderedElementsAre(session1, session2));
service().DeleteSessionsBetween(kTestTimes[0], kTestTimes[0]);
ASSERT_THAT(history(), ElementsAre(session2));
service().DeleteSessionsBetween(kTestTimes[1], kTestTimes[1]);
ASSERT_THAT(history(), IsEmpty());
store_sessions();
ASSERT_THAT(history(), UnorderedElementsAre(session1, session2));
service().DeleteSessionsBetween(kTestTimes[2], kTestTimes[2]);
ASSERT_THAT(history(), ElementsAre(session1));
service().DeleteSessionsBetween(kTestTimes[1], kTestTimes[1]);
ASSERT_THAT(history(), IsEmpty());
}
TEST_F(PermissionAuditingServiceTest, OldSessionsAreExpired) {
auto delay = service().GetUsageSessionCullingInterval();
auto time1 = base::Time::Now() - service().GetUsageSessionMaxAge() + delay;
auto time2 = time1 + 2 * delay;
auto time3 = time2 + 2 * delay;
auto session1 = BuildUsageSession(time1, time1);
auto session2 = BuildUsageSession(time2, time2);
auto session3 = BuildUsageSession(time3, time3);
service().StorePermissionUsage(session1);
service().StorePermissionUsage(session2);
service().StorePermissionUsage(session3);
auto history = [&]() -> std::vector<PermissionUsageSession> {
return GetPermissionUsageHistory(kTestTypes[0],
url::Origin::Create(GURL(kTestOrigins[0])),
base::Time());
};
ASSERT_THAT(history(), UnorderedElementsAre(session1, session2, session3));
task_environment().FastForwardBy(2 * delay);
ASSERT_THAT(history(), UnorderedElementsAre(session2, session3));
task_environment().FastForwardBy(2 * delay);
ASSERT_THAT(history(), ElementsAre(session3));
task_environment().FastForwardBy(2 * delay);
EXPECT_THAT(history(), IsEmpty());
}
} // namespace permissions
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment