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

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

Powered by Google App Engine
This is Rietveld 408576698