MD Downloads: UI review feedback
[chromium-blink-merge.git] / chrome / browser / predictors / autocomplete_action_predictor_unittest.cc
blobffa1257534294ff5052e8e8e31f217964198780d
1 // Copyright (c) 2012 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.
5 #include "chrome/browser/predictors/autocomplete_action_predictor.h"
7 #include "base/auto_reset.h"
8 #include "base/command_line.h"
9 #include "base/guid.h"
10 #include "base/memory/ref_counted.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/time/time.h"
15 #include "chrome/browser/history/history_service_factory.h"
16 #include "chrome/browser/prerender/prerender_field_trial.h"
17 #include "chrome/common/chrome_switches.h"
18 #include "chrome/test/base/testing_profile.h"
19 #include "components/history/core/browser/history_service.h"
20 #include "components/history/core/browser/in_memory_database.h"
21 #include "components/history/core/browser/url_database.h"
22 #include "components/omnibox/browser/autocomplete_match.h"
23 #include "content/public/test/test_browser_thread.h"
24 #include "testing/gtest/include/gtest/gtest.h"
26 using base::ASCIIToUTF16;
27 using content::BrowserThread;
28 using predictors::AutocompleteActionPredictor;
30 namespace {
32 struct TestUrlInfo {
33 GURL url;
34 base::string16 title;
35 int days_from_now;
36 base::string16 user_text;
37 int number_of_hits;
38 int number_of_misses;
39 AutocompleteActionPredictor::Action expected_action;
40 } test_url_db[] = {
41 { GURL("http://www.testsite.com/a.html"),
42 ASCIIToUTF16("Test - site - just a test"), 1,
43 ASCIIToUTF16("j"), 5, 0,
44 AutocompleteActionPredictor::ACTION_PRERENDER },
45 { GURL("http://www.testsite.com/b.html"),
46 ASCIIToUTF16("Test - site - just a test"), 1,
47 ASCIIToUTF16("ju"), 3, 0,
48 AutocompleteActionPredictor::ACTION_PRERENDER },
49 { GURL("http://www.testsite.com/c.html"),
50 ASCIIToUTF16("Test - site - just a test"), 5,
51 ASCIIToUTF16("just"), 3, 1,
52 AutocompleteActionPredictor::ACTION_PRECONNECT },
53 { GURL("http://www.testsite.com/d.html"),
54 ASCIIToUTF16("Test - site - just a test"), 5,
55 ASCIIToUTF16("just"), 3, 0,
56 AutocompleteActionPredictor::ACTION_PRERENDER },
57 { GURL("http://www.testsite.com/e.html"),
58 ASCIIToUTF16("Test - site - just a test"), 8,
59 ASCIIToUTF16("just"), 3, 1,
60 AutocompleteActionPredictor::ACTION_PRECONNECT },
61 { GURL("http://www.testsite.com/f.html"),
62 ASCIIToUTF16("Test - site - just a test"), 8,
63 ASCIIToUTF16("just"), 3, 0,
64 AutocompleteActionPredictor::ACTION_PRERENDER },
65 { GURL("http://www.testsite.com/g.html"),
66 ASCIIToUTF16("Test - site - just a test"), 12,
67 base::string16(), 5, 0,
68 AutocompleteActionPredictor::ACTION_NONE },
69 { GURL("http://www.testsite.com/h.html"),
70 ASCIIToUTF16("Test - site - just a test"), 21,
71 ASCIIToUTF16("just a test"), 2, 0,
72 AutocompleteActionPredictor::ACTION_NONE },
73 { GURL("http://www.testsite.com/i.html"),
74 ASCIIToUTF16("Test - site - just a test"), 28,
75 ASCIIToUTF16("just a test"), 2, 0,
76 AutocompleteActionPredictor::ACTION_NONE }
79 } // end namespace
81 namespace predictors {
83 class AutocompleteActionPredictorTest : public testing::Test {
84 public:
85 AutocompleteActionPredictorTest()
86 : ui_thread_(BrowserThread::UI, &loop_),
87 db_thread_(BrowserThread::DB, &loop_),
88 file_thread_(BrowserThread::FILE, &loop_),
89 profile_(new TestingProfile()),
90 predictor_(new AutocompleteActionPredictor(profile_.get())) {
93 ~AutocompleteActionPredictorTest() override {
94 predictor_.reset(NULL);
95 profile_.reset(NULL);
96 loop_.RunUntilIdle();
99 void SetUp() override {
100 base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
101 switches::kPrerenderFromOmnibox,
102 switches::kPrerenderFromOmniboxSwitchValueEnabled);
104 predictor_->CreateLocalCachesFromDatabase();
105 ASSERT_TRUE(profile_->CreateHistoryService(true, false));
106 profile_->BlockUntilHistoryProcessesPendingRequests();
108 ASSERT_TRUE(predictor_->initialized_);
109 ASSERT_TRUE(db_cache()->empty());
110 ASSERT_TRUE(db_id_cache()->empty());
113 void TearDown() override {
114 profile_->DestroyHistoryService();
115 predictor_->Shutdown();
118 protected:
119 typedef AutocompleteActionPredictor::DBCacheKey DBCacheKey;
120 typedef AutocompleteActionPredictor::DBCacheValue DBCacheValue;
121 typedef AutocompleteActionPredictor::DBCacheMap DBCacheMap;
122 typedef AutocompleteActionPredictor::DBIdCacheMap DBIdCacheMap;
124 void AddAllRowsToHistory() {
125 for (size_t i = 0; i < arraysize(test_url_db); ++i)
126 ASSERT_TRUE(AddRowToHistory(test_url_db[i]));
129 history::URLID AddRowToHistory(const TestUrlInfo& test_row) {
130 history::HistoryService* history = HistoryServiceFactory::GetForProfile(
131 profile_.get(), ServiceAccessType::EXPLICIT_ACCESS);
132 CHECK(history);
133 history::URLDatabase* url_db = history->InMemoryDatabase();
134 CHECK(url_db);
136 const base::Time visit_time =
137 base::Time::Now() - base::TimeDelta::FromDays(
138 test_row.days_from_now);
140 history::URLRow row(test_row.url);
141 row.set_title(test_row.title);
142 row.set_last_visit(visit_time);
144 return url_db->AddURL(row);
147 AutocompleteActionPredictorTable::Row CreateRowFromTestUrlInfo(
148 const TestUrlInfo& test_row) const {
149 AutocompleteActionPredictorTable::Row row;
150 row.id = base::GenerateGUID();
151 row.user_text = test_row.user_text;
152 row.url = test_row.url;
153 row.number_of_hits = test_row.number_of_hits;
154 row.number_of_misses = test_row.number_of_misses;
155 return row;
158 void AddAllRows() {
159 for (size_t i = 0; i < arraysize(test_url_db); ++i)
160 AddRow(test_url_db[i]);
163 std::string AddRow(const TestUrlInfo& test_row) {
164 AutocompleteActionPredictorTable::Row row =
165 CreateRowFromTestUrlInfo(test_row);
166 predictor_->AddAndUpdateRows(
167 AutocompleteActionPredictorTable::Rows(1, row),
168 AutocompleteActionPredictorTable::Rows());
170 return row.id;
173 void UpdateRow(const AutocompleteActionPredictorTable::Row& row) {
174 AutocompleteActionPredictor::DBCacheKey key = { row.user_text, row.url };
175 ASSERT_TRUE(db_cache()->find(key) != db_cache()->end());
176 predictor_->AddAndUpdateRows(
177 AutocompleteActionPredictorTable::Rows(),
178 AutocompleteActionPredictorTable::Rows(1, row));
181 void DeleteAllRows() {
182 predictor_->DeleteAllRows();
185 void DeleteRowsWithURLs(const history::URLRows& rows) {
186 predictor_->DeleteRowsWithURLs(rows);
189 void DeleteOldIdsFromCaches(
190 std::vector<AutocompleteActionPredictorTable::Row::Id>* id_list) {
191 history::HistoryService* history_service =
192 HistoryServiceFactory::GetForProfile(
193 profile_.get(), ServiceAccessType::EXPLICIT_ACCESS);
194 ASSERT_TRUE(history_service);
196 history::URLDatabase* url_db = history_service->InMemoryDatabase();
197 ASSERT_TRUE(url_db);
199 // Reset the predictor's |initialized_| flag for the life of this call,
200 // since outside of testing this function is only supposed to be reached
201 // before initialization is completed.
202 base::AutoReset<bool> initialized_reset(&predictor_->initialized_, false);
203 predictor_->DeleteOldIdsFromCaches(url_db, id_list);
206 AutocompleteActionPredictor* predictor() { return predictor_.get(); }
208 DBCacheMap* db_cache() { return &predictor_->db_cache_; }
209 DBIdCacheMap* db_id_cache() { return &predictor_->db_id_cache_; }
211 static int maximum_days_to_keep_entry() {
212 return AutocompleteActionPredictor::kMaximumDaysToKeepEntry;
215 private:
216 base::MessageLoop loop_;
217 content::TestBrowserThread ui_thread_;
218 content::TestBrowserThread db_thread_;
219 content::TestBrowserThread file_thread_;
220 scoped_ptr<TestingProfile> profile_;
221 scoped_ptr<AutocompleteActionPredictor> predictor_;
225 TEST_F(AutocompleteActionPredictorTest, AddRow) {
226 // Add a test entry to the predictor.
227 std::string guid = AddRow(test_url_db[0]);
229 // Get the data back out of the cache.
230 const DBCacheKey key = { test_url_db[0].user_text, test_url_db[0].url };
231 DBCacheMap::const_iterator it = db_cache()->find(key);
232 EXPECT_TRUE(it != db_cache()->end());
234 const DBCacheValue value = { test_url_db[0].number_of_hits,
235 test_url_db[0].number_of_misses };
236 EXPECT_EQ(value.number_of_hits, it->second.number_of_hits);
237 EXPECT_EQ(value.number_of_misses, it->second.number_of_misses);
239 DBIdCacheMap::const_iterator id_it = db_id_cache()->find(key);
240 EXPECT_TRUE(id_it != db_id_cache()->end());
241 EXPECT_EQ(guid, id_it->second);
244 TEST_F(AutocompleteActionPredictorTest, UpdateRow) {
245 ASSERT_NO_FATAL_FAILURE(AddAllRows());
247 EXPECT_EQ(arraysize(test_url_db), db_cache()->size());
248 EXPECT_EQ(arraysize(test_url_db), db_id_cache()->size());
250 // Get the data back out of the cache.
251 const DBCacheKey key = { test_url_db[0].user_text, test_url_db[0].url };
252 DBCacheMap::const_iterator it = db_cache()->find(key);
253 EXPECT_TRUE(it != db_cache()->end());
255 DBIdCacheMap::const_iterator id_it = db_id_cache()->find(key);
256 EXPECT_TRUE(id_it != db_id_cache()->end());
258 AutocompleteActionPredictorTable::Row update_row;
259 update_row.id = id_it->second;
260 update_row.user_text = key.user_text;
261 update_row.url = key.url;
262 update_row.number_of_hits = it->second.number_of_hits + 1;
263 update_row.number_of_misses = it->second.number_of_misses + 2;
265 UpdateRow(update_row);
267 // Get the updated version.
268 DBCacheMap::const_iterator update_it = db_cache()->find(key);
269 EXPECT_TRUE(update_it != db_cache()->end());
271 EXPECT_EQ(update_row.number_of_hits, update_it->second.number_of_hits);
272 EXPECT_EQ(update_row.number_of_misses, update_it->second.number_of_misses);
274 DBIdCacheMap::const_iterator update_id_it = db_id_cache()->find(key);
275 EXPECT_TRUE(update_id_it != db_id_cache()->end());
277 EXPECT_EQ(id_it->second, update_id_it->second);
280 TEST_F(AutocompleteActionPredictorTest, DeleteAllRows) {
281 ASSERT_NO_FATAL_FAILURE(AddAllRows());
283 EXPECT_EQ(arraysize(test_url_db), db_cache()->size());
284 EXPECT_EQ(arraysize(test_url_db), db_id_cache()->size());
286 DeleteAllRows();
288 EXPECT_TRUE(db_cache()->empty());
289 EXPECT_TRUE(db_id_cache()->empty());
292 TEST_F(AutocompleteActionPredictorTest, DeleteRowsWithURLs) {
293 ASSERT_NO_FATAL_FAILURE(AddAllRows());
295 EXPECT_EQ(arraysize(test_url_db), db_cache()->size());
296 EXPECT_EQ(arraysize(test_url_db), db_id_cache()->size());
298 history::URLRows rows;
299 for (size_t i = 0; i < 2; ++i)
300 rows.push_back(history::URLRow(test_url_db[i].url));
302 DeleteRowsWithURLs(rows);
304 EXPECT_EQ(arraysize(test_url_db) - 2, db_cache()->size());
305 EXPECT_EQ(arraysize(test_url_db) - 2, db_id_cache()->size());
307 for (size_t i = 0; i < arraysize(test_url_db); ++i) {
308 DBCacheKey key = { test_url_db[i].user_text, test_url_db[i].url };
310 bool deleted = (i < 2);
311 EXPECT_EQ(deleted, db_cache()->find(key) == db_cache()->end());
312 EXPECT_EQ(deleted, db_id_cache()->find(key) == db_id_cache()->end());
316 TEST_F(AutocompleteActionPredictorTest, DeleteOldIdsFromCaches) {
317 std::vector<AutocompleteActionPredictorTable::Row::Id> expected;
318 std::vector<AutocompleteActionPredictorTable::Row::Id> all_ids;
320 for (size_t i = 0; i < arraysize(test_url_db); ++i) {
321 std::string row_id = AddRow(test_url_db[i]);
322 all_ids.push_back(row_id);
324 bool exclude_url =
325 base::StartsWith(test_url_db[i].url.path(), "/d",
326 base::CompareCase::SENSITIVE) ||
327 (test_url_db[i].days_from_now > maximum_days_to_keep_entry());
329 if (exclude_url)
330 expected.push_back(row_id);
331 else
332 ASSERT_TRUE(AddRowToHistory(test_url_db[i]));
335 std::vector<AutocompleteActionPredictorTable::Row::Id> id_list;
336 DeleteOldIdsFromCaches(&id_list);
337 EXPECT_EQ(expected.size(), id_list.size());
338 EXPECT_EQ(all_ids.size() - expected.size(), db_cache()->size());
339 EXPECT_EQ(all_ids.size() - expected.size(), db_id_cache()->size());
341 for (std::vector<AutocompleteActionPredictorTable::Row::Id>::iterator it =
342 all_ids.begin();
343 it != all_ids.end(); ++it) {
344 bool in_expected =
345 (std::find(expected.begin(), expected.end(), *it) != expected.end());
346 bool in_list =
347 (std::find(id_list.begin(), id_list.end(), *it) != id_list.end());
348 EXPECT_EQ(in_expected, in_list);
352 TEST_F(AutocompleteActionPredictorTest, RecommendActionURL) {
353 ASSERT_NO_FATAL_FAILURE(AddAllRows());
355 AutocompleteMatch match;
356 match.type = AutocompleteMatchType::HISTORY_URL;
358 for (size_t i = 0; i < arraysize(test_url_db); ++i) {
359 match.destination_url = GURL(test_url_db[i].url);
360 EXPECT_EQ(test_url_db[i].expected_action,
361 predictor()->RecommendAction(test_url_db[i].user_text, match))
362 << "Unexpected action for " << match.destination_url;
366 TEST_F(AutocompleteActionPredictorTest, RecommendActionSearch) {
367 ASSERT_NO_FATAL_FAILURE(AddAllRows());
369 AutocompleteMatch match;
370 match.type = AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED;
372 for (size_t i = 0; i < arraysize(test_url_db); ++i) {
373 match.destination_url = GURL(test_url_db[i].url);
374 AutocompleteActionPredictor::Action expected_action =
375 (test_url_db[i].expected_action ==
376 AutocompleteActionPredictor::ACTION_PRERENDER) ?
377 AutocompleteActionPredictor::ACTION_PRECONNECT :
378 test_url_db[i].expected_action;
379 EXPECT_EQ(expected_action,
380 predictor()->RecommendAction(test_url_db[i].user_text, match))
381 << "Unexpected action for " << match.destination_url;
385 } // namespace predictors