OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <set> | 5 #include <set> |
6 #include <string> | 6 #include <string> |
7 | 7 |
8 #include "base/memory/scoped_vector.h" | 8 #include "base/memory/scoped_vector.h" |
| 9 #include "base/metrics/field_trial.h" |
9 #include "base/strings/string16.h" | 10 #include "base/strings/string16.h" |
10 #include "base/strings/stringprintf.h" | 11 #include "base/strings/stringprintf.h" |
11 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
| 13 #include "base/test/mock_entropy_provider.h" |
12 #include "testing/gtest/include/gtest/gtest.h" | 14 #include "testing/gtest/include/gtest/gtest.h" |
13 #include "ui/app_list/app_list_model.h" | 15 #include "ui/app_list/app_list_model.h" |
14 #include "ui/app_list/search/history_types.h" | 16 #include "ui/app_list/search/history_types.h" |
15 #include "ui/app_list/search/mixer.h" | 17 #include "ui/app_list/search/mixer.h" |
16 #include "ui/app_list/search_provider.h" | 18 #include "ui/app_list/search_provider.h" |
17 #include "ui/app_list/search_result.h" | 19 #include "ui/app_list/search_result.h" |
18 | 20 |
19 namespace app_list { | 21 namespace app_list { |
20 namespace test { | 22 namespace test { |
21 | 23 |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
94 private: | 96 private: |
95 std::string prefix_; | 97 std::string prefix_; |
96 size_t count_; | 98 size_t count_; |
97 bool bad_relevance_range_; | 99 bool bad_relevance_range_; |
98 // Indices of results that will have the |voice_result| flag set. | 100 // Indices of results that will have the |voice_result| flag set. |
99 std::set<size_t> voice_result_indices; | 101 std::set<size_t> voice_result_indices; |
100 | 102 |
101 DISALLOW_COPY_AND_ASSIGN(TestSearchProvider); | 103 DISALLOW_COPY_AND_ASSIGN(TestSearchProvider); |
102 }; | 104 }; |
103 | 105 |
104 // TODO(mgiuca): Parameterize this test so it tests both the default and | 106 // Test is parameterized with bool. True enables the "Blended" field trial. |
105 // "Blended" states for the AppListMixer field trial. | 107 class MixerTest : public testing::Test, |
106 class MixerTest : public testing::Test { | 108 public testing::WithParamInterface<bool> { |
107 public: | 109 public: |
108 MixerTest() : is_voice_query_(false) {} | 110 MixerTest() |
| 111 : is_voice_query_(false), |
| 112 field_trial_list_(new base::MockEntropyProvider()) {} |
109 ~MixerTest() override {} | 113 ~MixerTest() override {} |
110 | 114 |
111 // testing::Test overrides: | 115 // testing::Test overrides: |
112 void SetUp() override { | 116 void SetUp() override { |
| 117 // If the parameter is true, enable the field trial. |
| 118 const char* field_trial_name = GetParam() ? "Blended" : "default"; |
| 119 base::FieldTrialList::CreateFieldTrial("AppListMixer", field_trial_name); |
| 120 |
113 results_.reset(new AppListModel::SearchResults); | 121 results_.reset(new AppListModel::SearchResults); |
114 | 122 |
115 providers_.push_back(new TestSearchProvider("app")); | 123 providers_.push_back(new TestSearchProvider("app")); |
116 providers_.push_back(new TestSearchProvider("omnibox")); | 124 providers_.push_back(new TestSearchProvider("omnibox")); |
117 providers_.push_back(new TestSearchProvider("webstore")); | 125 providers_.push_back(new TestSearchProvider("webstore")); |
118 providers_.push_back(new TestSearchProvider("people")); | 126 providers_.push_back(new TestSearchProvider("people")); |
119 | 127 |
120 is_voice_query_ = false; | 128 is_voice_query_ = false; |
121 | 129 |
122 mixer_.reset(new Mixer(results_.get())); | 130 mixer_.reset(new Mixer(results_.get())); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 | 181 |
174 private: | 182 private: |
175 scoped_ptr<Mixer> mixer_; | 183 scoped_ptr<Mixer> mixer_; |
176 scoped_ptr<AppListModel::SearchResults> results_; | 184 scoped_ptr<AppListModel::SearchResults> results_; |
177 KnownResults known_results_; | 185 KnownResults known_results_; |
178 | 186 |
179 bool is_voice_query_; | 187 bool is_voice_query_; |
180 | 188 |
181 ScopedVector<TestSearchProvider> providers_; | 189 ScopedVector<TestSearchProvider> providers_; |
182 | 190 |
| 191 base::FieldTrialList field_trial_list_; |
| 192 |
183 DISALLOW_COPY_AND_ASSIGN(MixerTest); | 193 DISALLOW_COPY_AND_ASSIGN(MixerTest); |
184 }; | 194 }; |
185 | 195 |
186 TEST_F(MixerTest, Basic) { | 196 TEST_P(MixerTest, Basic) { |
| 197 // Note: Some cases in |expected_blended| have vastly more results than |
| 198 // others, due to the "at least 6" mechanism. If it gets at least 6 results |
| 199 // from all providers, it stops at 6. If not, it fetches potentially many more |
| 200 // results from all providers. Not ideal, but currently by design. |
187 struct TestCase { | 201 struct TestCase { |
188 const size_t app_results; | 202 const size_t app_results; |
189 const size_t omnibox_results; | 203 const size_t omnibox_results; |
190 const size_t webstore_results; | 204 const size_t webstore_results; |
191 const size_t people_results; | 205 const size_t people_results; |
192 const char* expected; | 206 const char* expected_default; // Expected results with trial off. |
| 207 const char* expected_blended; // Expected results with trial on. |
193 } kTestCases[] = { | 208 } kTestCases[] = { |
194 {0, 0, 0, 0, ""}, | 209 {0, 0, 0, 0, "", ""}, |
195 {10, 0, 0, 0, "app0,app1,app2,app3"}, | 210 {10, |
196 {0, 0, 10, 0, "webstore0,webstore1"}, | 211 0, |
197 {0, 0, 0, 10, "people0,people1"}, | 212 0, |
198 {4, 6, 0, 0, "app0,app1,app2,app3,omnibox0,omnibox1"}, | 213 0, |
199 {4, 6, 2, 0, "app0,app1,app2,app3,omnibox0,webstore0"}, | 214 "app0,app1,app2,app3", |
200 {4, 6, 0, 2, "app0,app1,app2,app3,omnibox0,people0"}, | 215 "app0,app1,app2,app3,app4,app5,app6,app7,app8,app9"}, |
201 {10, 10, 10, 0, "app0,app1,app2,app3,omnibox0,webstore0"}, | 216 {0, |
202 {0, 10, 0, 0, "omnibox0,omnibox1,omnibox2,omnibox3,omnibox4,omnibox5"}, | 217 0, |
203 {0, 10, 1, 0, "omnibox0,omnibox1,omnibox2,omnibox3,omnibox4,webstore0"}, | 218 10, |
204 {0, 10, 2, 0, "omnibox0,omnibox1,omnibox2,omnibox3,webstore0,webstore1"}, | 219 0, |
205 {1, 10, 0, 0, "app0,omnibox0,omnibox1,omnibox2,omnibox3,omnibox4"}, | 220 "webstore0,webstore1", |
206 {2, 10, 0, 0, "app0,app1,omnibox0,omnibox1,omnibox2,omnibox3"}, | 221 "webstore0,webstore1,webstore2,webstore3,webstore4,webstore5,webstore6," |
207 {2, 10, 1, 0, "app0,app1,omnibox0,omnibox1,omnibox2,webstore0"}, | 222 "webstore7,webstore8,webstore9"}, |
208 {2, 10, 2, 0, "app0,app1,omnibox0,omnibox1,webstore0,webstore1"}, | 223 {0, |
209 {2, 0, 2, 0, "app0,app1,webstore0,webstore1"}, | 224 0, |
210 {10, 0, 10, 10, "app0,app1,app2,app3,webstore0,webstore1"}, | 225 0, |
211 {10, 10, 10, 10, "app0,app1,app2,app3,omnibox0,webstore0"}, | 226 10, |
212 {0, 0, 0, 0, ""}, | 227 "people0,people1", |
| 228 "people0,people1,people2,people3,people4,people5,people6,people7," |
| 229 "people8,people9"}, |
| 230 {4, |
| 231 6, |
| 232 0, |
| 233 0, |
| 234 "app0,app1,app2,app3,omnibox0,omnibox1", |
| 235 "app0,omnibox0,app1,omnibox1,app2,omnibox2,app3,omnibox3"}, |
| 236 {4, |
| 237 6, |
| 238 2, |
| 239 0, |
| 240 "app0,app1,app2,app3,omnibox0,webstore0", |
| 241 "app0,omnibox0,app1,omnibox1,app2,omnibox2,app3,omnibox3,webstore0," |
| 242 "webstore1"}, |
| 243 {4, |
| 244 6, |
| 245 0, |
| 246 2, |
| 247 "app0,app1,app2,app3,omnibox0,people0", |
| 248 "app0,omnibox0,people0,app1,omnibox1,people1,app2,omnibox2,app3," |
| 249 "omnibox3"}, |
| 250 {10, |
| 251 10, |
| 252 10, |
| 253 0, |
| 254 "app0,app1,app2,app3,omnibox0,webstore0", |
| 255 "app0,omnibox0,app1,omnibox1,app2,omnibox2,app3,omnibox3,webstore0," |
| 256 "webstore1"}, |
| 257 {0, |
| 258 10, |
| 259 0, |
| 260 0, |
| 261 "omnibox0,omnibox1,omnibox2,omnibox3,omnibox4,omnibox5", |
| 262 "omnibox0,omnibox1,omnibox2,omnibox3,omnibox4,omnibox5,omnibox6," |
| 263 "omnibox7,omnibox8,omnibox9"}, |
| 264 {0, |
| 265 10, |
| 266 1, |
| 267 0, |
| 268 "omnibox0,omnibox1,omnibox2,omnibox3,omnibox4,webstore0", |
| 269 "omnibox0,omnibox1,omnibox2,omnibox3,webstore0,omnibox4,omnibox5," |
| 270 "omnibox6,omnibox7,omnibox8,omnibox9"}, |
| 271 {0, |
| 272 10, |
| 273 2, |
| 274 0, |
| 275 "omnibox0,omnibox1,omnibox2,omnibox3,webstore0,webstore1", |
| 276 "omnibox0,omnibox1,omnibox2,omnibox3,webstore0,webstore1"}, |
| 277 {1, |
| 278 10, |
| 279 0, |
| 280 0, |
| 281 "app0,omnibox0,omnibox1,omnibox2,omnibox3,omnibox4", |
| 282 "app0,omnibox0,omnibox1,omnibox2,omnibox3,omnibox4,omnibox5,omnibox6," |
| 283 "omnibox7,omnibox8,omnibox9"}, |
| 284 {2, |
| 285 10, |
| 286 0, |
| 287 0, |
| 288 "app0,app1,omnibox0,omnibox1,omnibox2,omnibox3", |
| 289 "app0,omnibox0,app1,omnibox1,omnibox2,omnibox3"}, |
| 290 {2, |
| 291 10, |
| 292 1, |
| 293 0, |
| 294 "app0,app1,omnibox0,omnibox1,omnibox2,webstore0", |
| 295 "app0,omnibox0,app1,omnibox1,omnibox2,omnibox3,webstore0"}, |
| 296 {2, |
| 297 10, |
| 298 2, |
| 299 0, |
| 300 "app0,app1,omnibox0,omnibox1,webstore0,webstore1", |
| 301 "app0,omnibox0,app1,omnibox1,omnibox2,omnibox3,webstore0,webstore1"}, |
| 302 {2, |
| 303 0, |
| 304 2, |
| 305 0, |
| 306 "app0,app1,webstore0,webstore1", |
| 307 "app0,app1,webstore0,webstore1"}, |
| 308 {10, |
| 309 0, |
| 310 10, |
| 311 10, |
| 312 "app0,app1,app2,app3,webstore0,webstore1", |
| 313 "app0,people0,app1,people1,app2,app3,webstore0,webstore1"}, |
| 314 {10, |
| 315 10, |
| 316 10, |
| 317 10, |
| 318 "app0,app1,app2,app3,omnibox0,webstore0", |
| 319 "app0,omnibox0,people0,app1,omnibox1,people1,app2,omnibox2,app3," |
| 320 "omnibox3,webstore0,webstore1"}, |
| 321 {0, 0, 0, 0, "", ""}, |
213 }; | 322 }; |
214 | 323 |
215 for (size_t i = 0; i < arraysize(kTestCases); ++i) { | 324 for (size_t i = 0; i < arraysize(kTestCases); ++i) { |
216 app_provider()->set_count(kTestCases[i].app_results); | 325 app_provider()->set_count(kTestCases[i].app_results); |
217 omnibox_provider()->set_count(kTestCases[i].omnibox_results); | 326 omnibox_provider()->set_count(kTestCases[i].omnibox_results); |
218 webstore_provider()->set_count(kTestCases[i].webstore_results); | 327 webstore_provider()->set_count(kTestCases[i].webstore_results); |
219 people_provider()->set_count(kTestCases[i].people_results); | 328 people_provider()->set_count(kTestCases[i].people_results); |
220 RunQuery(); | 329 RunQuery(); |
221 | 330 |
222 EXPECT_EQ(kTestCases[i].expected, GetResults()) << "Case " << i; | 331 const char* expected = GetParam() ? kTestCases[i].expected_blended |
| 332 : kTestCases[i].expected_default; |
| 333 EXPECT_EQ(expected, GetResults()) << "Case " << i; |
223 } | 334 } |
224 } | 335 } |
225 | 336 |
226 TEST_F(MixerTest, RemoveDuplicates) { | 337 TEST_P(MixerTest, RemoveDuplicates) { |
227 const std::string dup = "dup"; | 338 const std::string dup = "dup"; |
228 | 339 |
229 // This gives "dup0,dup1,dup2". | 340 // This gives "dup0,dup1,dup2". |
230 app_provider()->set_prefix(dup); | 341 app_provider()->set_prefix(dup); |
231 app_provider()->set_count(3); | 342 app_provider()->set_count(3); |
232 | 343 |
233 // This gives "dup0,dup1". | 344 // This gives "dup0,dup1". |
234 omnibox_provider()->set_prefix(dup); | 345 omnibox_provider()->set_prefix(dup); |
235 omnibox_provider()->set_count(2); | 346 omnibox_provider()->set_count(2); |
236 | 347 |
237 // This gives "dup0". | 348 // This gives "dup0". |
238 webstore_provider()->set_prefix(dup); | 349 webstore_provider()->set_prefix(dup); |
239 webstore_provider()->set_count(1); | 350 webstore_provider()->set_count(1); |
240 | 351 |
241 RunQuery(); | 352 RunQuery(); |
242 | 353 |
243 // Only three results with unique id are kept. | 354 // Only three results with unique id are kept. |
244 EXPECT_EQ("dup0,dup1,dup2", GetResults()); | 355 EXPECT_EQ("dup0,dup1,dup2", GetResults()); |
245 } | 356 } |
246 | 357 |
247 // Tests that "known results" have priority over others. | 358 // Tests that "known results" have priority over others. |
248 TEST_F(MixerTest, KnownResultsPriority) { | 359 TEST_P(MixerTest, KnownResultsPriority) { |
249 // This gives omnibox 0 -- 5. | 360 // This gives omnibox 0 -- 5. |
250 omnibox_provider()->set_count(6); | 361 omnibox_provider()->set_count(6); |
251 | 362 |
252 // omnibox 1 -- 4 are "known results". | 363 // omnibox 1 -- 4 are "known results". |
253 AddKnownResult("omnibox1", PREFIX_SECONDARY); | 364 AddKnownResult("omnibox1", PREFIX_SECONDARY); |
254 AddKnownResult("omnibox2", PERFECT_SECONDARY); | 365 AddKnownResult("omnibox2", PERFECT_SECONDARY); |
255 AddKnownResult("omnibox3", PREFIX_PRIMARY); | 366 AddKnownResult("omnibox3", PREFIX_PRIMARY); |
256 AddKnownResult("omnibox4", PERFECT_PRIMARY); | 367 AddKnownResult("omnibox4", PERFECT_PRIMARY); |
257 | 368 |
258 RunQuery(); | 369 RunQuery(); |
259 | 370 |
260 // omnibox 1 -- 4 should be prioritised over the others. They should be | 371 // omnibox 1 -- 4 should be prioritised over the others. They should be |
261 // ordered 4, 3, 2, 1 (in order of match quality). | 372 // ordered 4, 3, 2, 1 (in order of match quality). |
262 EXPECT_EQ("omnibox4,omnibox3,omnibox2,omnibox1,omnibox0,omnibox5", | 373 EXPECT_EQ("omnibox4,omnibox3,omnibox2,omnibox1,omnibox0,omnibox5", |
263 GetResults()); | 374 GetResults()); |
264 } | 375 } |
265 | 376 |
266 TEST_F(MixerTest, VoiceQuery) { | 377 TEST_P(MixerTest, VoiceQuery) { |
267 omnibox_provider()->set_count(3); | 378 omnibox_provider()->set_count(3); |
268 RunQuery(); | 379 RunQuery(); |
269 EXPECT_EQ("omnibox0,omnibox1,omnibox2", GetResults()); | 380 EXPECT_EQ("omnibox0,omnibox1,omnibox2", GetResults()); |
270 | 381 |
271 // Set "omnibox1" as a voice result. Do not expect any changes (as this is not | 382 // Set "omnibox1" as a voice result. Do not expect any changes (as this is not |
272 // a voice query). | 383 // a voice query). |
273 omnibox_provider()->set_as_voice_result(1); | 384 omnibox_provider()->set_as_voice_result(1); |
274 RunQuery(); | 385 RunQuery(); |
275 EXPECT_EQ("omnibox0,omnibox1,omnibox2", GetResults()); | 386 EXPECT_EQ("omnibox0,omnibox1,omnibox2", GetResults()); |
276 | 387 |
277 // Perform a voice query. Expect voice result first. | 388 // Perform a voice query. Expect voice result first. |
278 set_is_voice_query(true); | 389 set_is_voice_query(true); |
279 RunQuery(); | 390 RunQuery(); |
280 EXPECT_EQ("omnibox1,omnibox0,omnibox2", GetResults()); | 391 EXPECT_EQ("omnibox1,omnibox0,omnibox2", GetResults()); |
281 | 392 |
282 // All voice results should appear before non-voice results. | 393 // All voice results should appear before non-voice results. |
283 omnibox_provider()->set_as_voice_result(2); | 394 omnibox_provider()->set_as_voice_result(2); |
284 RunQuery(); | 395 RunQuery(); |
285 EXPECT_EQ("omnibox1,omnibox2,omnibox0", GetResults()); | 396 EXPECT_EQ("omnibox1,omnibox2,omnibox0", GetResults()); |
286 } | 397 } |
287 | 398 |
288 TEST_F(MixerTest, BadRelevanceRange) { | 399 TEST_P(MixerTest, BadRelevanceRange) { |
289 // This gives relevance scores: (10.0, 0.0). Even though providers are | 400 // This gives relevance scores: (10.0, 0.0). Even though providers are |
290 // supposed to give scores within the range [0.0, 1.0], we cannot rely on | 401 // supposed to give scores within the range [0.0, 1.0], we cannot rely on |
291 // providers to do this, since they retrieve results from disparate and | 402 // providers to do this, since they retrieve results from disparate and |
292 // unreliable sources (like the Google+ API). | 403 // unreliable sources (like the Google+ API). |
293 people_provider()->set_bad_relevance_range(); | 404 people_provider()->set_bad_relevance_range(); |
294 people_provider()->set_count(2); | 405 people_provider()->set_count(2); |
295 | 406 |
296 // Give a massive boost to the second result. | 407 // Give a massive boost to the second result. |
297 AddKnownResult("people1", PERFECT_PRIMARY); | 408 AddKnownResult("people1", PERFECT_PRIMARY); |
298 | 409 |
299 RunQuery(); | 410 RunQuery(); |
300 | 411 |
301 // If the results are correctly clamped to the range [0.0, 1.0], the boost to | 412 // If the results are correctly clamped to the range [0.0, 1.0], the boost to |
302 // "people1" will push it over the first result. If not, the massive base | 413 // "people1" will push it over the first result. If not, the massive base |
303 // score of "people0" will erroneously keep it on top. | 414 // score of "people0" will erroneously keep it on top. |
304 EXPECT_EQ("people1,people0", GetResults()); | 415 EXPECT_EQ("people1,people0", GetResults()); |
305 } | 416 } |
306 | 417 |
307 TEST_F(MixerTest, Publish) { | 418 TEST_P(MixerTest, Publish) { |
308 scoped_ptr<SearchResult> result1(new TestSearchResult("app1", 0)); | 419 scoped_ptr<SearchResult> result1(new TestSearchResult("app1", 0)); |
309 scoped_ptr<SearchResult> result2(new TestSearchResult("app2", 0)); | 420 scoped_ptr<SearchResult> result2(new TestSearchResult("app2", 0)); |
310 scoped_ptr<SearchResult> result3(new TestSearchResult("app3", 0)); | 421 scoped_ptr<SearchResult> result3(new TestSearchResult("app3", 0)); |
311 scoped_ptr<SearchResult> result3_copy = result3->Duplicate(); | 422 scoped_ptr<SearchResult> result3_copy = result3->Duplicate(); |
312 scoped_ptr<SearchResult> result4(new TestSearchResult("app4", 0)); | 423 scoped_ptr<SearchResult> result4(new TestSearchResult("app4", 0)); |
313 scoped_ptr<SearchResult> result5(new TestSearchResult("app5", 0)); | 424 scoped_ptr<SearchResult> result5(new TestSearchResult("app5", 0)); |
314 | 425 |
315 AppListModel::SearchResults ui_results; | 426 AppListModel::SearchResults ui_results; |
316 | 427 |
317 // Publish the first three results to |ui_results|. | 428 // Publish the first three results to |ui_results|. |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
385 | 496 |
386 // The reordered results should use the original objects. | 497 // The reordered results should use the original objects. |
387 EXPECT_EQ(old_ui_result_ids[0], | 498 EXPECT_EQ(old_ui_result_ids[0], |
388 TestSearchResult::GetInstanceId(ui_results.GetItemAt(3))); | 499 TestSearchResult::GetInstanceId(ui_results.GetItemAt(3))); |
389 EXPECT_EQ(old_ui_result_ids[1], | 500 EXPECT_EQ(old_ui_result_ids[1], |
390 TestSearchResult::GetInstanceId(ui_results.GetItemAt(0))); | 501 TestSearchResult::GetInstanceId(ui_results.GetItemAt(0))); |
391 EXPECT_EQ(old_ui_result_ids[2], | 502 EXPECT_EQ(old_ui_result_ids[2], |
392 TestSearchResult::GetInstanceId(ui_results.GetItemAt(2))); | 503 TestSearchResult::GetInstanceId(ui_results.GetItemAt(2))); |
393 } | 504 } |
394 | 505 |
| 506 INSTANTIATE_TEST_CASE_P(MixerTestInstance, MixerTest, testing::Bool()); |
| 507 |
395 } // namespace test | 508 } // namespace test |
396 } // namespace app_list | 509 } // namespace app_list |
OLD | NEW |