1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/performance_manager/persistence/site_data/site_data_cache_facade.h"
6
7 #include <memory>
8 #include <set>
9 #include <string>
10 #include <utility>
11 #include <vector>
12
13 #include "base/auto_reset.h"
14 #include "base/callback.h"
15 #include "base/memory/ptr_util.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/run_loop.h"
18 #include "base/task/post_task.h"
19 #include "base/test/bind.h"
20 #include "chrome/browser/performance_manager/persistence/site_data/site_data_cache_facade_factory.h"
21 #include "chrome/browser/performance_manager/persistence/site_data/unittest_utils.h"
22 #include "chrome/test/base/testing_profile.h"
23 #include "components/performance_manager/performance_manager_impl.h"
24 #include "components/performance_manager/persistence/site_data/leveldb_site_data_store.h"
25 #include "components/performance_manager/persistence/site_data/site_data_cache_factory.h"
26 #include "components/performance_manager/persistence/site_data/site_data_cache_impl.h"
27 #include "content/public/test/test_utils.h"
28 #include "testing/gmock/include/gmock/gmock.h"
29 #include "testing/gtest/include/gtest/gtest.h"
30 #include "url/gurl.h"
31
32 namespace performance_manager {
33
34 namespace {
35
36 // TODO(https://crbug.com/1042727): Fix test GURL scoping and remove this getter
37 // function.
TestOrigin()38 url::Origin TestOrigin() {
39 return url::Origin::Create(GURL("http://www.a.com"));
40 }
TestOrigin2()41 url::Origin TestOrigin2() {
42 return url::Origin::Create(GURL("http://www.b.com"));
43 }
44
45 // Mock version of a SiteDataCacheImpl. In practice instances of this object
46 // live on the Performance Manager sequence and all the mocked methods will be
47 // called from there.
48 class LenienMockSiteDataCacheImpl : public SiteDataCacheImpl {
49 public:
LenienMockSiteDataCacheImpl(const std::string & browser_context_id)50 explicit LenienMockSiteDataCacheImpl(const std::string& browser_context_id)
51 : SiteDataCacheImpl(browser_context_id) {}
52 ~LenienMockSiteDataCacheImpl() override = default;
53
54 // The 2 following functions allow setting the expectations for the mocked
55 // functions. Any call to one of these functions should be followed by the
56 // call that will caused the mocked the function to be called and then by a
57 // call to |WaitForExpectations|. Only one expectation can be set at a time.
58
SetClearSiteDataForOriginsExpectations(const std::vector<url::Origin> & expected_origins)59 void SetClearSiteDataForOriginsExpectations(
60 const std::vector<url::Origin>& expected_origins) {
61 ASSERT_FALSE(run_loop_);
62 run_loop_ = std::make_unique<base::RunLoop>();
63 auto quit_closure = run_loop_->QuitClosure();
64 EXPECT_CALL(*this, ClearSiteDataForOrigins(::testing::Eq(expected_origins)))
65 .WillOnce(
66 ::testing::InvokeWithoutArgs([closure = std::move(quit_closure)]() {
67 std::move(closure).Run();
68 }));
69 }
70
SetClearAllSiteDataExpectations()71 void SetClearAllSiteDataExpectations() {
72 ASSERT_FALSE(run_loop_);
73 run_loop_ = std::make_unique<base::RunLoop>();
74 auto quit_closure = run_loop_->QuitClosure();
75 EXPECT_CALL(*this, ClearAllSiteData())
76 .WillOnce(
77 ::testing::InvokeWithoutArgs([closure = std::move(quit_closure)]() {
78 std::move(closure).Run();
79 }));
80 }
81
WaitForExpectations()82 void WaitForExpectations() {
83 ASSERT_TRUE(run_loop_);
84 run_loop_->Run();
85 run_loop_.reset();
86 ::testing::Mock::VerifyAndClear(this);
87 }
88
89 private:
90 MOCK_METHOD1(ClearSiteDataForOrigins, void(const std::vector<url::Origin>&));
91 MOCK_METHOD0(ClearAllSiteData, void());
92
93 std::unique_ptr<base::RunLoop> run_loop_;
94
95 DISALLOW_COPY_AND_ASSIGN(LenienMockSiteDataCacheImpl);
96 };
97 using MockSiteDataCache = ::testing::StrictMock<LenienMockSiteDataCacheImpl>;
98
99 } // namespace
100
101 class SiteDataCacheFacadeTest : public testing::TestWithPerformanceManager {
102 public:
103 SiteDataCacheFacadeTest() = default;
104 ~SiteDataCacheFacadeTest() override = default;
105
SetUp()106 void SetUp() override {
107 testing::TestWithPerformanceManager::SetUp();
108 profile_ = std::make_unique<TestingProfile>();
109 use_in_memory_db_for_testing_ =
110 LevelDBSiteDataStore::UseInMemoryDBForTesting();
111 }
112
TearDown()113 void TearDown() override {
114 use_in_memory_db_for_testing_.reset();
115 profile_.reset();
116 testing::TestWithPerformanceManager::TearDown();
117 }
118
profile()119 TestingProfile* profile() { return profile_.get(); }
120
121 // Replace the SiteDataCache associated with |profile_| with a mock one.
SetUpMockCache()122 MockSiteDataCache* SetUpMockCache() {
123 MockSiteDataCache* mock_cache_raw = nullptr;
124 base::RunLoop run_loop;
125 auto quit_closure = run_loop.QuitClosure();
126 auto browser_context_id = profile()->UniqueId();
127 PerformanceManagerImpl::CallOnGraphImpl(
128 FROM_HERE, base::BindLambdaForTesting([&]() {
129 auto mock_cache =
130 std::make_unique<MockSiteDataCache>(browser_context_id);
131 mock_cache_raw = mock_cache.get();
132
133 SiteDataCacheFactory::GetInstance()->SetCacheForTesting(
134 browser_context_id, std::move(mock_cache));
135 SiteDataCacheFactory::GetInstance()->SetCacheInspectorForTesting(
136 browser_context_id, mock_cache_raw);
137 std::move(quit_closure).Run();
138 }));
139 run_loop.Run();
140 return mock_cache_raw;
141 }
142
143 private:
144 std::unique_ptr<TestingProfile> profile_;
145 std::unique_ptr<base::AutoReset<bool>> use_in_memory_db_for_testing_;
146 };
147
TEST_F(SiteDataCacheFacadeTest,IsDataCacheRecordingForTesting)148 TEST_F(SiteDataCacheFacadeTest, IsDataCacheRecordingForTesting) {
149 bool cache_is_recording = false;
150
151 SiteDataCacheFacade data_cache_facade(profile());
152 data_cache_facade.WaitUntilCacheInitializedForTesting();
153 {
154 base::RunLoop run_loop;
155 auto quit_closure = run_loop.QuitClosure();
156 data_cache_facade.IsDataCacheRecordingForTesting(
157 base::BindLambdaForTesting([&](bool is_recording) {
158 cache_is_recording = is_recording;
159 std::move(quit_closure).Run();
160 }));
161 run_loop.Run();
162 }
163 EXPECT_TRUE(cache_is_recording);
164
165 SiteDataCacheFacade off_record_data_cache_facade(
166 profile()->GetPrimaryOTRProfile());
167 {
168 base::RunLoop run_loop;
169 auto quit_closure = run_loop.QuitClosure();
170 off_record_data_cache_facade.IsDataCacheRecordingForTesting(
171 base::BindLambdaForTesting([&](bool is_recording) {
172 cache_is_recording = is_recording;
173 quit_closure.Run();
174 }));
175 run_loop.Run();
176 }
177
178 EXPECT_FALSE(cache_is_recording);
179 }
180
181 // Verify that an origin is removed from the data cache (in memory and on disk)
182 // when there are no more references to it in the history, after the history is
183 // partially cleared.
TEST_F(SiteDataCacheFacadeTest,OnURLsDeleted_Partial_OriginNotReferenced)184 TEST_F(SiteDataCacheFacadeTest, OnURLsDeleted_Partial_OriginNotReferenced) {
185 history::URLRows urls_to_delete = {history::URLRow(TestOrigin().GetURL()),
186 history::URLRow(TestOrigin2().GetURL())};
187 history::DeletionInfo deletion_info =
188 history::DeletionInfo::ForUrls(urls_to_delete, std::set<GURL>());
189 deletion_info.set_deleted_urls_origin_map({
190 {TestOrigin().GetURL(), {0, base::Time::Now()}},
191 {TestOrigin2().GetURL(), {0, base::Time::Now()}},
192 });
193
194 SiteDataCacheFacade data_cache_facade(profile());
195 data_cache_facade.WaitUntilCacheInitializedForTesting();
196
197 auto* mock_cache_raw = SetUpMockCache();
198 mock_cache_raw->SetClearSiteDataForOriginsExpectations(
199 {TestOrigin(), TestOrigin2()});
200 data_cache_facade.OnURLsDeleted(nullptr, deletion_info);
201 mock_cache_raw->WaitForExpectations();
202 }
203
204 // Verify that an origin is *not* removed from the data cache (in memory and on
205 // disk) when there remain references to it in the history, after the history is
206 // partially cleared.
TEST_F(SiteDataCacheFacadeTest,OnURLsDeleted_Partial_OriginStillReferenced)207 TEST_F(SiteDataCacheFacadeTest, OnURLsDeleted_Partial_OriginStillReferenced) {
208 history::URLRows urls_to_delete = {history::URLRow(TestOrigin().GetURL()),
209 history::URLRow(TestOrigin2().GetURL())};
210 history::DeletionInfo deletion_info =
211 history::DeletionInfo::ForUrls(urls_to_delete, std::set<GURL>());
212 deletion_info.set_deleted_urls_origin_map({
213 {TestOrigin().GetURL(), {0, base::Time::Now()}},
214 {TestOrigin2().GetURL(), {3, base::Time::Now()}},
215 });
216
217 SiteDataCacheFacade data_cache_facade(profile());
218 data_cache_facade.WaitUntilCacheInitializedForTesting();
219
220 auto* mock_cache_raw = SetUpMockCache();
221 // |TestOrigin2()| shouldn't be removed as there's still some references to it
222 // in the history.
223 mock_cache_raw->SetClearSiteDataForOriginsExpectations({TestOrigin()});
224 data_cache_facade.OnURLsDeleted(nullptr, deletion_info);
225 mock_cache_raw->WaitForExpectations();
226 }
227
228 // Verify that origins are removed from the data cache (in memory and on disk)
229 // when the history is completely cleared.
TEST_F(SiteDataCacheFacadeTest,OnURLsDeleted_Full)230 TEST_F(SiteDataCacheFacadeTest, OnURLsDeleted_Full) {
231 SiteDataCacheFacade data_cache_facade(profile());
232 data_cache_facade.WaitUntilCacheInitializedForTesting();
233
234 auto* mock_cache_raw = SetUpMockCache();
235 mock_cache_raw->SetClearAllSiteDataExpectations();
236 data_cache_facade.OnURLsDeleted(nullptr,
237 history::DeletionInfo::ForAllHistory());
238 mock_cache_raw->WaitForExpectations();
239 }
240
241 } // namespace performance_manager
242