OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 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 "ios/chrome/browser/ui/history/history_service_facade.h" |
| 6 |
| 7 #include <memory> |
| 8 |
| 9 #import "base/mac/scoped_nsobject.h" |
| 10 #include "base/run_loop.h" |
| 11 #include "base/strings/string16.h" |
| 12 #include "components/history/core/browser/history_service.h" |
| 13 #include "components/history/core/browser/history_service_observer.h" |
| 14 #include "components/keyed_service/core/service_access_type.h" |
| 15 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" |
| 16 #include "ios/chrome/browser/history/history_service_factory.h" |
| 17 #import "ios/chrome/browser/ui/history/history_entry.h" |
| 18 #import "ios/chrome/browser/ui/history/history_service_facade_delegate.h" |
| 19 #include "ios/web/public/test/test_web_thread.h" |
| 20 #include "ios/web/public/test/test_web_thread_bundle.h" |
| 21 #include "testing/gtest/include/gtest/gtest.h" |
| 22 #include "testing/platform_test.h" |
| 23 #import "third_party/ocmock/OCMock/OCMock.h" |
| 24 #include "third_party/ocmock/gtest_support.h" |
| 25 |
| 26 namespace { |
| 27 |
| 28 struct TestResult { |
| 29 GURL url; |
| 30 int64_t hour_offset; // Visit time in hours past the baseline time. |
| 31 }; |
| 32 |
| 33 // Duplicates on the same day in the local timezone are removed, so set a |
| 34 // baseline time in local time. |
| 35 const base::Time baseline_time = base::Time::UnixEpoch().LocalMidnight(); |
| 36 |
| 37 // Returns true if |result| matches the test data given by |correct_result|, |
| 38 // otherwise returns false. |
| 39 bool ResultEquals(const history::HistoryEntry& result, |
| 40 const TestResult& correct_result) { |
| 41 base::Time correct_time = |
| 42 baseline_time + base::TimeDelta::FromHours(correct_result.hour_offset); |
| 43 |
| 44 return result.time == correct_time && result.url == correct_result.url; |
| 45 } |
| 46 |
| 47 // Returns RemovedEntry using |time_offset| |
| 48 HistoryServiceFacade::RemovedEntry EntryForRemoval(const GURL& url, |
| 49 int64_t time_offset) { |
| 50 return HistoryServiceFacade::RemovedEntry( |
| 51 url, baseline_time + base::TimeDelta::FromHours(time_offset)); |
| 52 } |
| 53 } // namespace |
| 54 |
| 55 // Mock delegate for verifying callback behavior. |
| 56 @interface MockHistoryServiceFacadeDelegate |
| 57 : NSObject<HistoryServiceFacadeDelegate> { |
| 58 std::vector<history::HistoryEntry> _received_entries; |
| 59 } |
| 60 @property BOOL didCompleteRemoval; |
| 61 @property BOOL didReceiveOtherBrowsingHistoryCallback; |
| 62 - (BOOL)delegateDidReceiveResult:(const TestResult&)expected_result; |
| 63 @end |
| 64 |
| 65 @implementation MockHistoryServiceFacadeDelegate |
| 66 @synthesize didCompleteRemoval = _didCompleteRemoval; |
| 67 @synthesize didReceiveOtherBrowsingHistoryCallback = |
| 68 _didReceiveOtherBrowsingHistoryCallback; |
| 69 |
| 70 - (void)historyServiceFacade:(HistoryServiceFacade*)facade |
| 71 didReceiveQueryResult:(HistoryServiceFacade::QueryResult)result { |
| 72 _received_entries = result.entries; |
| 73 } |
| 74 |
| 75 - (void)historyServiceFacade:(HistoryServiceFacade*)facade |
| 76 shouldShowNoticeAboutOtherFormsOfBrowsingHistory:(BOOL)shouldShowNotice { |
| 77 _didReceiveOtherBrowsingHistoryCallback = YES; |
| 78 } |
| 79 |
| 80 // Notifies the delegate that history entry deletion has completed. |
| 81 - (void)historyServiceFacadeDidCompleteEntryRemoval: |
| 82 (HistoryServiceFacade*)facade { |
| 83 _didCompleteRemoval = YES; |
| 84 } |
| 85 |
| 86 - (BOOL)delegateDidReceiveResult:(const TestResult&)expected_result { |
| 87 for (history::HistoryEntry entry : _received_entries) { |
| 88 if (ResultEquals(entry, expected_result)) |
| 89 return YES; |
| 90 } |
| 91 return NO; |
| 92 } |
| 93 |
| 94 @end |
| 95 |
| 96 class HistoryServiceFacadeTest : public PlatformTest, |
| 97 public history::HistoryServiceObserver { |
| 98 public: |
| 99 HistoryServiceFacadeTest() {} |
| 100 ~HistoryServiceFacadeTest() override {} |
| 101 |
| 102 void SetUp() override { |
| 103 DCHECK_CURRENTLY_ON(web::WebThread::UI); |
| 104 TestChromeBrowserState::Builder builder; |
| 105 browser_state_ = builder.Build(); |
| 106 bool success = browser_state_->CreateHistoryService(true); |
| 107 EXPECT_TRUE(success); |
| 108 |
| 109 mock_delegate_.reset([[MockHistoryServiceFacadeDelegate alloc] init]); |
| 110 history_service_facade_.reset( |
| 111 new HistoryServiceFacade(browser_state_.get(), mock_delegate_)); |
| 112 } |
| 113 |
| 114 // Cycles the runloop until the condition is met (up to 10 seconds). |
| 115 typedef base::Callback<bool(void)> WaitCondition; |
| 116 bool WaitUntilLoop(WaitCondition condition) { |
| 117 DCHECK_CURRENTLY_ON(web::WebThread::UI); |
| 118 base::Time maxDate = base::Time::Now() + base::TimeDelta::FromSeconds(10); |
| 119 while (!condition.Run()) { |
| 120 if (base::Time::Now() > maxDate) |
| 121 return false; |
| 122 base::RunLoop().RunUntilIdle(); |
| 123 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1)); |
| 124 } |
| 125 return true; |
| 126 } |
| 127 |
| 128 // Adds a visit to history. |
| 129 void AddVisit(const GURL& url, int64_t time_offset) { |
| 130 history::HistoryService* history_service = |
| 131 ios::HistoryServiceFactory::GetForBrowserStateIfExists( |
| 132 browser_state_.get(), ServiceAccessType::EXPLICIT_ACCESS); |
| 133 EXPECT_TRUE(history_service); |
| 134 |
| 135 history_service->AddObserver(this); |
| 136 base::Time time = baseline_time + base::TimeDelta::FromHours(time_offset); |
| 137 history_service->AddPage(url, time, history::VisitSource::SOURCE_BROWSED); |
| 138 |
| 139 // Wait until the data is in the db. |
| 140 EXPECT_TRUE(WaitUntilLoop(base::Bind(&HistoryServiceFacadeTest::VerifyVisit, |
| 141 base::Unretained(this), url, time))); |
| 142 |
| 143 history_service->RemoveObserver(this); |
| 144 } |
| 145 |
| 146 // history::HistoryServiceObserver |
| 147 void OnURLVisited(history::HistoryService* history_service, |
| 148 ui::PageTransition transition, |
| 149 const history::URLRow& row, |
| 150 const history::RedirectList& redirects, |
| 151 base::Time visit_time) override { |
| 152 visited_url_ = row.url(); |
| 153 visited_time_ = row.last_visit(); |
| 154 } |
| 155 |
| 156 // Verify visit to |url| at |time| was observed. |
| 157 bool VerifyVisit(const GURL& url, const base::Time& time) { |
| 158 return visited_url_ == url && visited_time_ == time; |
| 159 } |
| 160 |
| 161 // Verify that a query result was received by delegate callback. |
| 162 bool VerifyQueryResult(const TestResult& result) { |
| 163 return [mock_delegate_ delegateDidReceiveResult:result]; |
| 164 } |
| 165 |
| 166 // Verify that entry removal completion delegate callback was called. |
| 167 bool VerifyEntryRemoval() { return [mock_delegate_ didCompleteRemoval]; } |
| 168 |
| 169 // Verify that the |
| 170 // historyServiceFacade:shouldShowNoticeAboutOtherFormsOfBrowsingHistory |
| 171 // delegate callback was called. |
| 172 bool VerifyOtherHistoryCallback() { |
| 173 return [mock_delegate_ didReceiveOtherBrowsingHistoryCallback]; |
| 174 } |
| 175 |
| 176 protected: |
| 177 web::TestWebThreadBundle thread_bundle_; |
| 178 std::unique_ptr<TestChromeBrowserState> browser_state_; |
| 179 base::scoped_nsobject<MockHistoryServiceFacadeDelegate> mock_delegate_; |
| 180 std::unique_ptr<HistoryServiceFacade> history_service_facade_; |
| 181 GURL visited_url_; |
| 182 base::Time visited_time_; |
| 183 DISALLOW_COPY_AND_ASSIGN(HistoryServiceFacadeTest); |
| 184 }; |
| 185 |
| 186 // Tests that invoking QueryHistory results in the delegate receiving an added |
| 187 // history entry. |
| 188 TEST_F(HistoryServiceFacadeTest, TestQueryHistory) { |
| 189 GURL url("http://www.testurl.com"); |
| 190 AddVisit(url, 0); |
| 191 |
| 192 base::string16 query = base::string16(); |
| 193 history::QueryOptions options; |
| 194 history_service_facade_->QueryHistory(query, options); |
| 195 |
| 196 TestResult expected_result = {url, 0}; |
| 197 EXPECT_TRUE( |
| 198 WaitUntilLoop(base::Bind(&HistoryServiceFacadeTest::VerifyQueryResult, |
| 199 base::Unretained(this), expected_result))); |
| 200 } |
| 201 |
| 202 // Tests that invoking RemoveHistoryEntries completes with callback to delegate |
| 203 // method historyServiceFacadeDidCompleteEntryRemoval. |
| 204 TEST_F(HistoryServiceFacadeTest, TestRemoveHistoryEntries) { |
| 205 GURL url("http://www.testurl.com"); |
| 206 AddVisit(url, 0); |
| 207 |
| 208 std::vector<HistoryServiceFacade::RemovedEntry> entries_to_remove{ |
| 209 EntryForRemoval(url, 0)}; |
| 210 history_service_facade_->RemoveHistoryEntries(entries_to_remove); |
| 211 EXPECT_TRUE(WaitUntilLoop(base::Bind( |
| 212 &HistoryServiceFacadeTest::VerifyEntryRemoval, base::Unretained(this)))); |
| 213 } |
| 214 |
| 215 // Tests that invoking QueryOtherFormsOfBrowsingHistory completes with callback |
| 216 // to delegate method |
| 217 // historyServiceFacade:shouldShowNoticeAboutOtherFormsOfBrowsingHistory:. |
| 218 TEST_F(HistoryServiceFacadeTest, TestQueryOtherFormsOfBrowsingHistory) { |
| 219 history_service_facade_->QueryOtherFormsOfBrowsingHistory(); |
| 220 EXPECT_TRUE(WaitUntilLoop( |
| 221 base::Bind(&HistoryServiceFacadeTest::VerifyOtherHistoryCallback, |
| 222 base::Unretained(this)))); |
| 223 } |
OLD | NEW |