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