1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/permissions/permission_auditing_database.h"
9 #include "base/check.h"
10 #include "base/files/file_util.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/functional/bind.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/time/time.h"
15 #include "sql/test/scoped_error_expecter.h"
16 #include "testing/gmock/include/gmock/gmock-matchers.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
21 namespace permissions {
23 using ::testing::ElementsAre;
24 using ::testing::IsEmpty;
28 base::Time TimeFromTimestamp(const int64_t& time) {
29 return base::Time::FromDeltaSinceWindowsEpoch(base::Microseconds(time));
32 constexpr ContentSettingsType kTestTypes[] = {
33 ContentSettingsType::GEOLOCATION, ContentSettingsType::NOTIFICATIONS};
35 constexpr char kTestUrl1[] = "http://www.example1.com";
36 constexpr char kTestUrl2[] = "http://www.example2.com";
38 std::string GetUniqueUrl(int id) {
39 return base::StringPrintf("http://www.example%d.com", id);
42 url::Origin GetOrigin(const char* url) {
43 return url::Origin::Create(GURL(url));
46 PermissionUsageSession SessionLike(ContentSettingsType type,
48 const PermissionUsageSession& session) {
49 return {.origin = GetOrigin(url),
51 .usage_start = session.usage_start,
52 .usage_end = session.usage_end,
53 .had_user_activation = session.had_user_activation,
54 .was_foreground = session.was_foreground,
55 .had_focus = session.had_focus};
60 class PermissionAuditingDatabaseTest : public testing::Test {
62 PermissionAuditingDatabaseTest()
63 : test_sessions_(GeneratePermissionSessions()) {}
65 PermissionAuditingDatabaseTest(const PermissionAuditingDatabaseTest&) =
67 PermissionAuditingDatabaseTest& operator=(
68 const PermissionAuditingDatabaseTest&) = delete;
71 void SetUp() override {
72 ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
73 path_ = temp_directory_.GetPath().Append(
74 FILE_PATH_LITERAL("test_permission_auditing_database"));
75 ASSERT_TRUE(db_.Init(path_));
78 std::vector<PermissionUsageSession> GetPermissionUsageHistory(
79 ContentSettingsType type,
81 base::Time starting_from = base::Time()) {
82 return db_.GetPermissionUsageHistory(type, GetOrigin(url), starting_from);
85 absl::optional<base::Time> GetLastUsageTime(ContentSettingsType type,
87 return db_.GetLastPermissionUsageTime(type, GetOrigin(url));
90 bool UpdateEndTime(ContentSettingsType type,
92 base::Time ordering_time,
93 base::Time new_end_time) {
94 return db_.UpdateEndTime(type, GetOrigin(url), ordering_time, new_end_time);
97 void StoreSessionForEachTime() {
98 for (const auto& time : test_times_) {
99 ASSERT_TRUE(db().StorePermissionUsage({.origin = GetOrigin(kTestUrl1),
100 .type = kTestTypes[0],
103 .had_user_activation = false,
104 .was_foreground = false,
105 .had_focus = false}));
109 PermissionAuditingDatabase& db() { return db_; }
111 const base::Time test_times_[3] = {TimeFromTimestamp(12864787200000000),
112 TimeFromTimestamp(12864787200000001),
113 TimeFromTimestamp(12864787200000002)};
115 const std::vector<PermissionUsageSession> test_sessions_;
118 std::vector<PermissionUsageSession> GeneratePermissionSessions() {
119 std::vector<PermissionUsageSession> sessions;
120 for (size_t i = 0; i < std::size(test_times_); ++i) {
121 for (size_t j = i + 1; j <= std::size(test_times_); ++j) {
122 for (bool had_user_activation : {false, true}) {
123 for (bool was_foreground : {false, true}) {
124 for (bool had_focus : {false, true}) {
125 base::Time start = test_times_[i];
126 base::Time end = (j == std::size(test_times_)) ? test_times_[i]
128 sessions.push_back({.usage_start = start,
130 .had_user_activation = had_user_activation,
131 .was_foreground = was_foreground,
132 .had_focus = had_focus});
141 PermissionAuditingDatabase db_;
143 base::ScopedTempDir temp_directory_;
144 base::FilePath path_;
147 TEST_F(PermissionAuditingDatabaseTest, IsUsageHistorySizeCorrect) {
148 auto session = SessionLike(kTestTypes[0], kTestUrl1, test_sessions_[0]);
149 EXPECT_THAT(GetPermissionUsageHistory(kTestTypes[0], kTestUrl1), IsEmpty());
150 size_t current_size = 0;
151 for (const auto& time : test_times_) {
152 session.usage_start = time;
153 session.usage_end = time;
154 ASSERT_TRUE(db().StorePermissionUsage(
155 SessionLike(kTestTypes[0], kTestUrl1, session)));
156 ASSERT_EQ(GetPermissionUsageHistory(kTestTypes[0], kTestUrl1).size(),
161 TEST_F(PermissionAuditingDatabaseTest,
162 IsUsageHistoryDifferentForDifferentPermissionsAndOrigins) {
163 const auto& session1 =
164 SessionLike(kTestTypes[0], kTestUrl1, test_sessions_[0]);
165 const auto& session2 =
166 SessionLike(kTestTypes[1], kTestUrl2, test_sessions_[1]);
167 ASSERT_TRUE(db().StorePermissionUsage(session1));
168 ASSERT_TRUE(db().StorePermissionUsage(session2));
170 EXPECT_THAT(GetPermissionUsageHistory(kTestTypes[0], kTestUrl1),
171 ElementsAre(session1));
172 EXPECT_THAT(GetPermissionUsageHistory(kTestTypes[1], kTestUrl2),
173 ElementsAre(session2));
174 EXPECT_THAT(GetPermissionUsageHistory(kTestTypes[0], kTestUrl2), IsEmpty());
175 EXPECT_THAT(GetPermissionUsageHistory(kTestTypes[1], kTestUrl1), IsEmpty());
178 TEST_F(PermissionAuditingDatabaseTest, AreFieldsStoredCorrectlyInUsageHistory) {
180 for (const auto& session : test_sessions_) {
181 const std::string url = GetUniqueUrl(++counter);
182 auto updated_session = SessionLike(kTestTypes[0], url.c_str(), session);
183 ASSERT_TRUE(db().StorePermissionUsage(updated_session));
184 EXPECT_THAT(GetPermissionUsageHistory(kTestTypes[0], url.c_str()),
185 ElementsAre(updated_session));
189 TEST_F(PermissionAuditingDatabaseTest, UsageHistoryContainsOnlyLastSessions) {
190 for (const auto time : test_times_) {
192 db().StorePermissionUsage({.origin = GetOrigin(kTestUrl1),
193 .type = kTestTypes[0],
195 .usage_end = time + base::Microseconds(1),
196 .had_user_activation = false,
197 .was_foreground = false,
198 .had_focus = false}));
200 EXPECT_EQ(GetPermissionUsageHistory(kTestTypes[0], kTestUrl1).size(),
201 std::size(test_times_));
202 for (size_t i = 0; i < std::size(test_times_); ++i) {
203 EXPECT_EQ(GetPermissionUsageHistory(kTestTypes[0], kTestUrl1,
204 test_times_[i] + base::Microseconds(2))
206 std::size(test_times_) - i - 1);
210 TEST_F(PermissionAuditingDatabaseTest, GetLastPermissionUsageTime) {
211 EXPECT_FALSE(GetLastUsageTime(kTestTypes[0], kTestUrl1));
212 for (const auto& time : test_times_) {
213 ASSERT_TRUE(db().StorePermissionUsage({.origin = GetOrigin(kTestUrl1),
214 .type = kTestTypes[0],
217 .had_user_activation = false,
218 .was_foreground = false,
219 .had_focus = false}));
220 EXPECT_EQ(GetLastUsageTime(kTestTypes[0], kTestUrl1), time);
224 TEST_F(PermissionAuditingDatabaseTest, UpdateEndTime) {
226 for (const auto& session : test_sessions_) {
227 const std::string url = GetUniqueUrl(++counter);
228 ASSERT_TRUE(db().StorePermissionUsage(
229 SessionLike(kTestTypes[0], url.c_str(), session)));
230 const auto& end_time = session.usage_end;
231 auto tomorrow = end_time + base::Days(1);
232 ASSERT_TRUE(GetLastUsageTime(kTestTypes[0], url.c_str()) == end_time);
233 ASSERT_TRUE(UpdateEndTime(kTestTypes[0], url.c_str(), session.usage_start,
235 EXPECT_EQ(GetLastUsageTime(kTestTypes[0], url.c_str()), tomorrow);
236 auto history = GetPermissionUsageHistory(kTestTypes[0], url.c_str());
237 ASSERT_EQ(history.size(), 1u);
238 EXPECT_EQ(history[0].usage_end, tomorrow);
242 TEST_F(PermissionAuditingDatabaseTest, DeleteSessionsBetween) {
243 size_t current_size = std::size(test_times_);
244 StoreSessionForEachTime();
245 for (const auto& time : test_times_) {
246 ASSERT_TRUE(db().DeleteSessionsBetween(time, time));
247 ASSERT_EQ(GetPermissionUsageHistory(kTestTypes[0], kTestUrl1).size(),
252 TEST_F(PermissionAuditingDatabaseTest,
253 DeleteSessionsBetweenWithUnspecifiedEndTime) {
254 StoreSessionForEachTime();
255 ASSERT_TRUE(db().DeleteSessionsBetween(test_times_[1], base::Time()));
256 ASSERT_EQ(GetPermissionUsageHistory(kTestTypes[0], kTestUrl1).size(), 1u);
257 ASSERT_TRUE(db().DeleteSessionsBetween(test_times_[0], base::Time()));
258 EXPECT_THAT(GetPermissionUsageHistory(kTestTypes[0], kTestUrl1), IsEmpty());
261 TEST_F(PermissionAuditingDatabaseTest,
262 DeleteSessionsBetweenWithUnspecifiedStartTime) {
263 StoreSessionForEachTime();
264 ASSERT_TRUE(db().DeleteSessionsBetween(
265 base::Time(), test_times_[std::size(test_times_) - 2]));
266 ASSERT_EQ(GetPermissionUsageHistory(kTestTypes[0], kTestUrl1).size(), 1u);
267 ASSERT_TRUE(db().DeleteSessionsBetween(
268 base::Time(), test_times_[std::size(test_times_) - 1]));
269 EXPECT_THAT(GetPermissionUsageHistory(kTestTypes[0], kTestUrl1), IsEmpty());
272 TEST_F(PermissionAuditingDatabaseTest,
273 DeleteSessionsBetweenWithUnspecifiedStartAndEndTime) {
274 StoreSessionForEachTime();
275 ASSERT_EQ(GetPermissionUsageHistory(kTestTypes[0], kTestUrl1).size(),
276 std::size(test_times_));
277 ASSERT_TRUE(db().DeleteSessionsBetween(base::Time(), base::Time()));
278 EXPECT_THAT(GetPermissionUsageHistory(kTestTypes[0], kTestUrl1), IsEmpty());
281 TEST_F(PermissionAuditingDatabaseTest,
282 StorePermissionUsageChecksTimerangeConstraint) {
283 auto session = SessionLike(kTestTypes[0], kTestUrl1, test_sessions_[0]);
284 session.usage_start = session.usage_end;
285 EXPECT_TRUE(db().StorePermissionUsage(session));
288 TEST_F(PermissionAuditingDatabaseTest,
289 StorePermissionUsageDoesntAccpetExistingRecord) {
290 auto session = SessionLike(kTestTypes[0], kTestUrl1, test_sessions_[0]);
291 EXPECT_TRUE(db().StorePermissionUsage(session));
293 sql::test::ScopedErrorExpecter expecter;
294 expecter.ExpectError(SQLITE_CONSTRAINT);
295 EXPECT_FALSE(db().StorePermissionUsage(session));
296 EXPECT_TRUE(expecter.SawExpectedErrors());
300 TEST_F(PermissionAuditingDatabaseTest, UpdateEndTimeChecksTimerangeConstraint) {
301 auto session = SessionLike(kTestTypes[0], kTestUrl1, test_sessions_[0]);
302 ASSERT_TRUE(db().StorePermissionUsage(session));
303 EXPECT_TRUE(UpdateEndTime(kTestTypes[0], kTestUrl1, session.usage_start,
304 session.usage_start));
307 } // namespace permissions