Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Side by Side Diff: chrome/browser/ui/app_list/search/history_unittest.cc

Issue 15875007: app_list: Search result launch history and boost. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: for comments in #3 Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2013 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 "base/basictypes.h"
6 #include "base/bind.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/message_loop.h"
9 #include "base/run_loop.h"
10 #include "base/stringprintf.h"
11 #include "base/timer.h"
12 #include "chrome/browser/ui/app_list/search/history.h"
13 #include "chrome/browser/ui/app_list/search/history_data.h"
14 #include "chrome/browser/ui/app_list/search/history_data_observer.h"
15 #include "chrome/browser/ui/app_list/search/history_data_store.h"
16 #include "chrome/test/base/testing_profile.h"
17 #include "content/public/test/test_browser_thread.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 namespace app_list {
21 namespace test {
22
23 namespace {
24
25 const size_t kMaxEntry = 3;
26 const size_t kMaxSecondary = 2;
27
28 // HistoryDataLoadWaiter waits for give |data| to be loaded from underlying
29 // store on the blocking pool. The waiter waits on the main message loop until
30 // OnHistoryDataLoadedFromStore() is invoked or the maximum allowed wait time
31 // has passed.
32 class HistoryDataLoadWaiter : public HistoryDataObserver {
33 public:
34 explicit HistoryDataLoadWaiter(HistoryData* data) : data_(data) {}
35 virtual ~HistoryDataLoadWaiter() {}
36
37 void Wait(int wait_time_ms) {
James Cook 2013/05/24 03:57:05 nit: I think changing |wait_time_ms| to |max_wait_
xiyuan 2013/05/24 16:33:02 Done.
38 data_->AddObserver(this);
39
40 timer_.Start(FROM_HERE,
41 base::TimeDelta::FromMilliseconds(wait_time_ms),
42 this,
43 &HistoryDataLoadWaiter::OnTimeOut);
44
45 run_loop_.reset(new base::RunLoop);
46 run_loop_->Run();
47
48 data_->RemoveObserver(this);
49 }
50
51 private:
52 void OnTimeOut() {
53 run_loop_->Quit();
54 }
55
56 // HistoryDataObserver overrides:
57 virtual void OnHistoryDataLoadedFromStore() OVERRIDE {
58 run_loop_->Quit();
59 }
60
61 HistoryData* data_; // Not owned.
62 scoped_ptr<base::RunLoop> run_loop_;
63 base::OneShotTimer<HistoryDataLoadWaiter> timer_;
64
65 DISALLOW_COPY_AND_ASSIGN(HistoryDataLoadWaiter);
66 };
67
68 // StoreFlushWaiter waits for the given |store| to flush its data to disk.
69 // The flush and disk write happens on the blocking pool. The waiter waits
70 // on the main message loop until the OnFlushed() is invoked or the maximum
71 // allowed wait time has passed.
72 class StoreFlushWaiter {
73 public:
74 explicit StoreFlushWaiter(HistoryDataStore* store) : store_(store) {}
75 ~StoreFlushWaiter() {}
76
77 void Wait(int wait_time_ms) {
James Cook 2013/05/24 03:57:05 ditto, max_wait_time_ms or timeout_ms
xiyuan 2013/05/24 16:33:02 Done.
78 store_->Flush(
79 base::Bind(&StoreFlushWaiter::OnFlushed, base::Unretained(this)));
80
81 timer_.Start(FROM_HERE,
82 base::TimeDelta::FromMilliseconds(wait_time_ms),
83 this,
84 &StoreFlushWaiter::OnTimeOut);
85
86 run_loop_.reset(new base::RunLoop);
87 run_loop_->Run();
88 }
89
90 private:
91 void OnTimeOut() {
92 run_loop_->Quit();
93 }
94
95 void OnFlushed() {
96 run_loop_->Quit();
97 }
98
99 HistoryDataStore* store_; // Not owned.
100 scoped_ptr<base::RunLoop> run_loop_;
101 base::OneShotTimer<StoreFlushWaiter> timer_;
102
103 DISALLOW_COPY_AND_ASSIGN(StoreFlushWaiter);
104 };
105
106 } // namespace
107
108 class SearchHistoryTest : public testing::Test {
109 public:
110 SearchHistoryTest()
111 : ui_thread_(content::BrowserThread::UI, &message_loop_) {}
112 virtual ~SearchHistoryTest() {}
113
114 // testing::Test overrides:
115 virtual void SetUp() OVERRIDE {
116 profile_.reset(new TestingProfile);
117 CreateHistory();
118 }
119 virtual void TearDown() OVERRIDE {
120 Flush();
121 }
122
123 void CreateHistory() {
124 history_.reset(new History(profile_.get()));
125
126 // Replace |data_| with test params.
127 history_->data_->RemoveObserver(history_.get());
128 history_->data_.reset(new HistoryData(history_->store_,
129 kMaxEntry,
130 kMaxSecondary));
131 history_->data_->AddObserver(history_.get());
132
133 HistoryDataLoadWaiter waiter(history_->data_.get());
134 waiter.Wait(1000);
135 ASSERT_TRUE(history_->IsReady());
136 }
137
138 void Flush() {
139 StoreFlushWaiter waiter(history_->store_.get());
140 waiter.Wait(1000);
141 }
142
143 size_t GetKnownResults(const std::string& query) {
144 known_results_ = history()->GetKnownResults(query).Pass();
145 return known_results_->size();
146 }
147
148 KnownResultType GetResultType(const std::string& result_id) {
149 return known_results_->find(result_id) != known_results_->end()
150 ? (*known_results_.get())[result_id]
151 : UNKNOWN_RESULT;
152 }
153
154 History* history() { return history_.get(); }
155 const HistoryData::Associations& associations() const {
156 return history_->data_->associations();
157 }
158
159 private:
160 MessageLoopForUI message_loop_;
161 content::TestBrowserThread ui_thread_;
162 scoped_ptr<TestingProfile> profile_;
163
164 scoped_ptr<History> history_;
165 scoped_ptr<KnownResults> known_results_;
166
167 DISALLOW_COPY_AND_ASSIGN(SearchHistoryTest);
168 };
169
170 TEST_F(SearchHistoryTest, Persistence) {
171 // Ensure it's empty.
172 EXPECT_EQ(0u, GetKnownResults("cal"));
173
174 // Add one launch event.
175 history()->AddLaunchEvent("cal", "calendar");
176 EXPECT_EQ(1u, GetKnownResults("cal"));
177
178 // Flush and recreate the history object.
179 Flush();
180 CreateHistory();
181
182 // History should be initialized with data just added.
183 EXPECT_EQ(1u, GetKnownResults("cal"));
184 }
185
186 TEST_F(SearchHistoryTest, PerfectAndPrefixMatch) {
187 const char kQuery[] = "cal";
188 const char kQueryPrefix[] = "c";
189 const char kPrimary[] = "calendar";
190 const char kSecondary[] = "calculator";
191
192 history()->AddLaunchEvent(kQuery, kPrimary);
193 history()->AddLaunchEvent(kQuery, kSecondary);
194
195 EXPECT_EQ(2u, GetKnownResults(kQuery));
196 EXPECT_EQ(PERFECT_PRIMARY, GetResultType(kPrimary));
197 EXPECT_EQ(PERFECT_SECONDARY, GetResultType(kSecondary));
198
199 EXPECT_EQ(2u, GetKnownResults(kQueryPrefix));
200 EXPECT_EQ(PREFIX_PRIMARY, GetResultType(kPrimary));
201 EXPECT_EQ(PREFIX_SECONDARY, GetResultType(kSecondary));
202 }
203
204 TEST_F(SearchHistoryTest, StickyPrimary) {
205 const char kQuery[] = "cal";
206 const char kPrimary[] = "calendar";
207 const char kSecondary[] = "calculator";
208 const char kOther[] = "other";
209
210 // Add two launch events. kPrimary becomes primary.
211 history()->AddLaunchEvent(kQuery, kPrimary);
212 history()->AddLaunchEvent(kQuery, kSecondary);
213
214 EXPECT_EQ(2u, GetKnownResults(kQuery));
215 EXPECT_EQ(PERFECT_PRIMARY, GetResultType(kPrimary));
216 EXPECT_EQ(PERFECT_SECONDARY, GetResultType(kSecondary));
217
218 // These launch events should not change primary.
219 history()->AddLaunchEvent(kQuery, kPrimary);
220 history()->AddLaunchEvent(kQuery, kSecondary);
221 history()->AddLaunchEvent(kQuery, kPrimary);
222 history()->AddLaunchEvent(kQuery, kSecondary);
223 history()->AddLaunchEvent(kQuery, kPrimary);
224 history()->AddLaunchEvent(kQuery, kSecondary);
225 history()->AddLaunchEvent(kQuery, kOther);
226 history()->AddLaunchEvent(kQuery, kSecondary);
227 history()->AddLaunchEvent(kQuery, kOther);
228 history()->AddLaunchEvent(kQuery, kSecondary);
229 history()->AddLaunchEvent(kQuery, kOther);
230
231 EXPECT_EQ(3u, GetKnownResults(kQuery));
232 EXPECT_EQ(PERFECT_PRIMARY, GetResultType(kPrimary));
233 EXPECT_EQ(PERFECT_SECONDARY, GetResultType(kSecondary));
234 EXPECT_EQ(PERFECT_SECONDARY, GetResultType(kOther));
235 }
236
237 TEST_F(SearchHistoryTest, PromoteSecondary) {
238 const char kQuery[] = "cal";
239 const char kPrimary[] = "calendar";
240 const char kSecondary[] = "calculator";
241
242 history()->AddLaunchEvent(kQuery, kPrimary);
243 history()->AddLaunchEvent(kQuery, kSecondary);
244
245 EXPECT_EQ(2u, GetKnownResults(kQuery));
246 EXPECT_EQ(PERFECT_PRIMARY, GetResultType(kPrimary));
247 EXPECT_EQ(PERFECT_SECONDARY, GetResultType(kSecondary));
248
249 // The 2nd launch in a row promotes it to be primary.
250 history()->AddLaunchEvent(kQuery, kSecondary);
251
252 EXPECT_EQ(2u, GetKnownResults(kQuery));
253 EXPECT_EQ(PERFECT_PRIMARY, GetResultType(kSecondary));
254 EXPECT_EQ(PERFECT_SECONDARY, GetResultType(kPrimary));
255 }
256
257 TEST_F(SearchHistoryTest, MaxEntry) {
258 for (size_t i = 0; i < kMaxEntry; ++i) {
259 std::string query = base::StringPrintf("%d", static_cast<int>(i));
260 history()->AddLaunchEvent(query, "app");
261 }
262 EXPECT_EQ(kMaxEntry, associations().size());
263
264 // Oldest entries still exists.
265 EXPECT_TRUE(associations().find("0") != associations().end());
266 EXPECT_TRUE(associations().find("1") != associations().end());
267
268 // Touches the oldest and 2nd oldest becomes oldest now..
James Cook 2013/05/24 03:57:05 nit: one . at end
xiyuan 2013/05/24 16:33:02 Done.
269 history()->AddLaunchEvent("0", "app");
270
271 // Adds one more
272 history()->AddLaunchEvent("extra", "app");
273
274 // Number of entries are capped to kMaxEntry.
275 EXPECT_EQ(kMaxEntry, associations().size());
276
277 // Oldest entry is trimmed.
278 EXPECT_FALSE(associations().find("1") != associations().end());
279
280 // The touched oldest survived.
281 EXPECT_TRUE(associations().find("0") != associations().end());
282 }
283
284 TEST_F(SearchHistoryTest, MaxSecondary) {
285 const char kQuery[] = "query";
286 history()->AddLaunchEvent(kQuery, "primary");
287 for (size_t i = 0; i < kMaxSecondary; ++i) {
288 std::string result_id = base::StringPrintf("%d", static_cast<int>(i));
289 history()->AddLaunchEvent(kQuery, result_id);
290 }
291
292 EXPECT_EQ(kMaxSecondary + 1, GetKnownResults(kQuery));
293 EXPECT_EQ(PERFECT_SECONDARY, GetResultType("0"));
294 EXPECT_EQ(PERFECT_SECONDARY, GetResultType("1"));
295
296 // Touches the oldest secondary.
297 history()->AddLaunchEvent(kQuery, "0");
298
299 // Adds one more.
300 history()->AddLaunchEvent(kQuery, "extra");
301
302 // Total number of results is capped.
303 EXPECT_EQ(kMaxSecondary + 1, GetKnownResults(kQuery));
304
305 // The oldest secondary is gone.
306 EXPECT_EQ(UNKNOWN_RESULT, GetResultType("1"));
307
308 // Touched oldest survived.
309 EXPECT_EQ(PERFECT_SECONDARY, GetResultType("0"));
310 }
311
312 } // namespace test
313 } // namespace app_list
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698