OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "components/variations/study_filtering.h" | 5 #include "components/variations/study_filtering.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 #include <string.h> | 9 #include <string.h> |
10 | 10 |
11 #include <vector> | 11 #include <vector> |
12 | 12 |
13 #include "base/macros.h" | 13 #include "base/macros.h" |
14 #include "base/strings/string_split.h" | 14 #include "base/strings/string_split.h" |
| 15 #include "components/variations/client_filterable_state.h" |
15 #include "components/variations/processed_study.h" | 16 #include "components/variations/processed_study.h" |
16 #include "testing/gtest/include/gtest/gtest.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
17 | 18 |
18 namespace variations { | 19 namespace variations { |
19 | 20 |
20 namespace { | 21 namespace { |
21 | 22 |
22 // Converts |time| to Study proto format. | 23 // Converts |time| to Study proto format. |
23 int64_t TimeToProtoTime(const base::Time& time) { | 24 int64_t TimeToProtoTime(const base::Time& time) { |
24 return (time - base::Time::UnixEpoch()).InSeconds(); | 25 return (time - base::Time::UnixEpoch()).InSeconds(); |
25 } | 26 } |
26 | 27 |
27 // Adds an experiment to |study| with the specified |name| and |probability|. | 28 // Adds an experiment to |study| with the specified |name| and |probability|. |
28 Study_Experiment* AddExperiment(const std::string& name, int probability, | 29 Study::Experiment* AddExperiment(const std::string& name, |
29 Study* study) { | 30 int probability, |
30 Study_Experiment* experiment = study->add_experiment(); | 31 Study* study) { |
| 32 Study::Experiment* experiment = study->add_experiment(); |
31 experiment->set_name(name); | 33 experiment->set_name(name); |
32 experiment->set_probability_weight(probability); | 34 experiment->set_probability_weight(probability); |
33 return experiment; | 35 return experiment; |
34 } | 36 } |
35 | 37 |
36 } // namespace | 38 } // namespace |
37 | 39 |
38 TEST(VariationsStudyFilteringTest, CheckStudyChannel) { | 40 TEST(VariationsStudyFilteringTest, CheckStudyChannel) { |
39 const Study_Channel channels[] = { | 41 const Study::Channel channels[] = { |
40 Study_Channel_CANARY, | 42 Study::CANARY, Study::DEV, Study::BETA, Study::STABLE, |
41 Study_Channel_DEV, | |
42 Study_Channel_BETA, | |
43 Study_Channel_STABLE, | |
44 }; | 43 }; |
45 bool channel_added[arraysize(channels)] = { 0 }; | 44 bool channel_added[arraysize(channels)] = { 0 }; |
46 | 45 |
47 Study_Filter filter; | 46 Study::Filter filter; |
48 | 47 |
49 // Check in the forwarded order. The loop cond is <= arraysize(channels) | 48 // Check in the forwarded order. The loop cond is <= arraysize(channels) |
50 // instead of < so that the result of adding the last channel gets checked. | 49 // instead of < so that the result of adding the last channel gets checked. |
51 for (size_t i = 0; i <= arraysize(channels); ++i) { | 50 for (size_t i = 0; i <= arraysize(channels); ++i) { |
52 for (size_t j = 0; j < arraysize(channels); ++j) { | 51 for (size_t j = 0; j < arraysize(channels); ++j) { |
53 const bool expected = channel_added[j] || filter.channel_size() == 0; | 52 const bool expected = channel_added[j] || filter.channel_size() == 0; |
54 const bool result = internal::CheckStudyChannel(filter, channels[j]); | 53 const bool result = internal::CheckStudyChannel(filter, channels[j]); |
55 EXPECT_EQ(expected, result) << "Case " << i << "," << j << " failed!"; | 54 EXPECT_EQ(expected, result) << "Case " << i << "," << j << " failed!"; |
56 } | 55 } |
57 | 56 |
(...skipping 15 matching lines...) Expand all Loading... |
73 | 72 |
74 if (i < arraysize(channels)) { | 73 if (i < arraysize(channels)) { |
75 const int index = arraysize(channels) - i - 1; | 74 const int index = arraysize(channels) - i - 1; |
76 filter.add_channel(channels[index]); | 75 filter.add_channel(channels[index]); |
77 channel_added[index] = true; | 76 channel_added[index] = true; |
78 } | 77 } |
79 } | 78 } |
80 } | 79 } |
81 | 80 |
82 TEST(VariationsStudyFilteringTest, CheckStudyFormFactor) { | 81 TEST(VariationsStudyFilteringTest, CheckStudyFormFactor) { |
83 const Study_FormFactor form_factors[] = { | 82 const Study::FormFactor form_factors[] = { |
84 Study_FormFactor_DESKTOP, | 83 Study::DESKTOP, Study::PHONE, Study::TABLET, Study::KIOSK, |
85 Study_FormFactor_PHONE, | |
86 Study_FormFactor_TABLET, | |
87 Study_FormFactor_KIOSK, | |
88 }; | 84 }; |
89 | 85 |
90 ASSERT_EQ(Study_FormFactor_FormFactor_ARRAYSIZE, | 86 ASSERT_EQ(Study::FormFactor_ARRAYSIZE, |
91 static_cast<int>(arraysize(form_factors))); | 87 static_cast<int>(arraysize(form_factors))); |
92 | 88 |
93 bool form_factor_added[arraysize(form_factors)] = { 0 }; | 89 bool form_factor_added[arraysize(form_factors)] = { 0 }; |
94 Study_Filter filter; | 90 Study::Filter filter; |
95 | 91 |
96 for (size_t i = 0; i <= arraysize(form_factors); ++i) { | 92 for (size_t i = 0; i <= arraysize(form_factors); ++i) { |
97 for (size_t j = 0; j < arraysize(form_factors); ++j) { | 93 for (size_t j = 0; j < arraysize(form_factors); ++j) { |
98 const bool expected = form_factor_added[j] || | 94 const bool expected = form_factor_added[j] || |
99 filter.form_factor_size() == 0; | 95 filter.form_factor_size() == 0; |
100 const bool result = internal::CheckStudyFormFactor(filter, | 96 const bool result = internal::CheckStudyFormFactor(filter, |
101 form_factors[j]); | 97 form_factors[j]); |
102 EXPECT_EQ(expected, result) << "form_factor: case " << i << "," << j | 98 EXPECT_EQ(expected, result) << "form_factor: case " << i << "," << j |
103 << " failed!"; | 99 << " failed!"; |
104 } | 100 } |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
189 {"", "", true, true, true}, | 185 {"", "", true, true, true}, |
190 {"", "en-US", false, true, true}, | 186 {"", "en-US", false, true, true}, |
191 {"", "en-US,en-CA,fr", false, false, false}, | 187 {"", "en-US,en-CA,fr", false, false, false}, |
192 {"", "en-US,en-CA,en-GB", false, false, true}, | 188 {"", "en-US,en-CA,en-GB", false, false, true}, |
193 {"", "en-GB,en-CA,en-US", false, false, true}, | 189 {"", "en-GB,en-CA,en-US", false, false, true}, |
194 {"", "ja,kr,vi", true, true, true}, | 190 {"", "ja,kr,vi", true, true, true}, |
195 {"", "fr-CA", true, true, true}, | 191 {"", "fr-CA", true, true, true}, |
196 }; | 192 }; |
197 | 193 |
198 for (size_t i = 0; i < arraysize(test_cases); ++i) { | 194 for (size_t i = 0; i < arraysize(test_cases); ++i) { |
199 Study_Filter filter; | 195 Study::Filter filter; |
200 for (const std::string& locale : base::SplitString( | 196 for (const std::string& locale : base::SplitString( |
201 test_cases[i].filter_locales, ",", | 197 test_cases[i].filter_locales, ",", |
202 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) | 198 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) |
203 filter.add_locale(locale); | 199 filter.add_locale(locale); |
204 for (const std::string& exclude_locale : | 200 for (const std::string& exclude_locale : |
205 base::SplitString(test_cases[i].exclude_locales, ",", | 201 base::SplitString(test_cases[i].exclude_locales, ",", |
206 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) | 202 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) |
207 filter.add_exclude_locale(exclude_locale); | 203 filter.add_exclude_locale(exclude_locale); |
208 EXPECT_EQ(test_cases[i].en_us_result, | 204 EXPECT_EQ(test_cases[i].en_us_result, |
209 internal::CheckStudyLocale(filter, "en-US")); | 205 internal::CheckStudyLocale(filter, "en-US")); |
210 EXPECT_EQ(test_cases[i].en_ca_result, | 206 EXPECT_EQ(test_cases[i].en_ca_result, |
211 internal::CheckStudyLocale(filter, "en-CA")); | 207 internal::CheckStudyLocale(filter, "en-CA")); |
212 EXPECT_EQ(test_cases[i].fr_result, | 208 EXPECT_EQ(test_cases[i].fr_result, |
213 internal::CheckStudyLocale(filter, "fr")); | 209 internal::CheckStudyLocale(filter, "fr")); |
214 } | 210 } |
215 } | 211 } |
216 | 212 |
217 TEST(VariationsStudyFilteringTest, CheckStudyPlatform) { | 213 TEST(VariationsStudyFilteringTest, CheckStudyPlatform) { |
218 const Study_Platform platforms[] = { | 214 const Study::Platform platforms[] = { |
219 Study_Platform_PLATFORM_WINDOWS, | 215 Study::PLATFORM_WINDOWS, Study::PLATFORM_MAC, Study::PLATFORM_LINUX, |
220 Study_Platform_PLATFORM_MAC, | 216 Study::PLATFORM_CHROMEOS, Study::PLATFORM_ANDROID, Study::PLATFORM_IOS, |
221 Study_Platform_PLATFORM_LINUX, | |
222 Study_Platform_PLATFORM_CHROMEOS, | |
223 Study_Platform_PLATFORM_ANDROID, | |
224 Study_Platform_PLATFORM_IOS, | |
225 }; | 217 }; |
226 ASSERT_EQ(Study_Platform_Platform_ARRAYSIZE, | 218 ASSERT_EQ(Study::Platform_ARRAYSIZE, static_cast<int>(arraysize(platforms))); |
227 static_cast<int>(arraysize(platforms))); | |
228 bool platform_added[arraysize(platforms)] = { 0 }; | 219 bool platform_added[arraysize(platforms)] = { 0 }; |
229 | 220 |
230 Study_Filter filter; | 221 Study::Filter filter; |
231 | 222 |
232 // Check in the forwarded order. The loop cond is <= arraysize(platforms) | 223 // Check in the forwarded order. The loop cond is <= arraysize(platforms) |
233 // instead of < so that the result of adding the last channel gets checked. | 224 // instead of < so that the result of adding the last channel gets checked. |
234 for (size_t i = 0; i <= arraysize(platforms); ++i) { | 225 for (size_t i = 0; i <= arraysize(platforms); ++i) { |
235 for (size_t j = 0; j < arraysize(platforms); ++j) { | 226 for (size_t j = 0; j < arraysize(platforms); ++j) { |
236 const bool expected = platform_added[j] || filter.platform_size() == 0; | 227 const bool expected = platform_added[j] || filter.platform_size() == 0; |
237 const bool result = internal::CheckStudyPlatform(filter, platforms[j]); | 228 const bool result = internal::CheckStudyPlatform(filter, platforms[j]); |
238 EXPECT_EQ(expected, result) << "Case " << i << "," << j << " failed!"; | 229 EXPECT_EQ(expected, result) << "Case " << i << "," << j << " failed!"; |
239 } | 230 } |
240 | 231 |
(...skipping 28 matching lines...) Expand all Loading... |
269 const base::Time start_date; | 260 const base::Time start_date; |
270 bool expected_result; | 261 bool expected_result; |
271 } start_test_cases[] = { | 262 } start_test_cases[] = { |
272 {now - delta, true}, | 263 {now - delta, true}, |
273 // Note, the proto start_date is truncated to seconds, but the reference | 264 // Note, the proto start_date is truncated to seconds, but the reference |
274 // date isn't. | 265 // date isn't. |
275 {now, true}, | 266 {now, true}, |
276 {now + delta, false}, | 267 {now + delta, false}, |
277 }; | 268 }; |
278 | 269 |
279 Study_Filter filter; | 270 Study::Filter filter; |
280 | 271 |
281 // Start date not set should result in true. | 272 // Start date not set should result in true. |
282 EXPECT_TRUE(internal::CheckStudyStartDate(filter, now)); | 273 EXPECT_TRUE(internal::CheckStudyStartDate(filter, now)); |
283 | 274 |
284 for (size_t i = 0; i < arraysize(start_test_cases); ++i) { | 275 for (size_t i = 0; i < arraysize(start_test_cases); ++i) { |
285 filter.set_start_date(TimeToProtoTime(start_test_cases[i].start_date)); | 276 filter.set_start_date(TimeToProtoTime(start_test_cases[i].start_date)); |
286 const bool result = internal::CheckStudyStartDate(filter, now); | 277 const bool result = internal::CheckStudyStartDate(filter, now); |
287 EXPECT_EQ(start_test_cases[i].expected_result, result) | 278 EXPECT_EQ(start_test_cases[i].expected_result, result) |
288 << "Case " << i << " failed!"; | 279 << "Case " << i << " failed!"; |
289 } | 280 } |
290 } | 281 } |
291 | 282 |
292 TEST(VariationsStudyFilteringTest, CheckStudyEndDate) { | 283 TEST(VariationsStudyFilteringTest, CheckStudyEndDate) { |
293 const base::Time now = base::Time::Now(); | 284 const base::Time now = base::Time::Now(); |
294 const base::TimeDelta delta = base::TimeDelta::FromHours(1); | 285 const base::TimeDelta delta = base::TimeDelta::FromHours(1); |
295 const struct { | 286 const struct { |
296 const base::Time end_date; | 287 const base::Time end_date; |
297 bool expected_result; | 288 bool expected_result; |
298 } start_test_cases[] = { | 289 } start_test_cases[] = { |
299 {now - delta, false}, {now + delta, true}, | 290 {now - delta, false}, {now + delta, true}, |
300 }; | 291 }; |
301 | 292 |
302 Study_Filter filter; | 293 Study::Filter filter; |
303 | 294 |
304 // End date not set should result in true. | 295 // End date not set should result in true. |
305 EXPECT_TRUE(internal::CheckStudyEndDate(filter, now)); | 296 EXPECT_TRUE(internal::CheckStudyEndDate(filter, now)); |
306 | 297 |
307 for (size_t i = 0; i < arraysize(start_test_cases); ++i) { | 298 for (size_t i = 0; i < arraysize(start_test_cases); ++i) { |
308 filter.set_end_date(TimeToProtoTime(start_test_cases[i].end_date)); | 299 filter.set_end_date(TimeToProtoTime(start_test_cases[i].end_date)); |
309 const bool result = internal::CheckStudyEndDate(filter, now); | 300 const bool result = internal::CheckStudyEndDate(filter, now); |
310 EXPECT_EQ(start_test_cases[i].expected_result, result) << "Case " << i | 301 EXPECT_EQ(start_test_cases[i].expected_result, result) << "Case " << i |
311 << " failed!"; | 302 << " failed!"; |
312 } | 303 } |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
347 { "2.1.*", "2.3.4", false }, | 338 { "2.1.*", "2.3.4", false }, |
348 { "2.*", "2.3.4", true }, | 339 { "2.*", "2.3.4", true }, |
349 { "2.3.*", "2.3.4", true }, | 340 { "2.3.*", "2.3.4", true }, |
350 { "2.3.4.*", "2.3.4", true }, | 341 { "2.3.4.*", "2.3.4", true }, |
351 { "2.3.4.0.*", "2.3.4", true }, | 342 { "2.3.4.0.*", "2.3.4", true }, |
352 { "2.4.*", "2.3.4", true }, | 343 { "2.4.*", "2.3.4", true }, |
353 { "1.3.*", "2.3.4", false }, | 344 { "1.3.*", "2.3.4", false }, |
354 { "1.*", "2.3.4", false }, | 345 { "1.*", "2.3.4", false }, |
355 }; | 346 }; |
356 | 347 |
357 Study_Filter filter; | 348 Study::Filter filter; |
358 | 349 |
359 // Min/max version not set should result in true. | 350 // Min/max version not set should result in true. |
360 EXPECT_TRUE(internal::CheckStudyVersion(filter, base::Version("1.2.3"))); | 351 EXPECT_TRUE(internal::CheckStudyVersion(filter, base::Version("1.2.3"))); |
361 | 352 |
362 for (size_t i = 0; i < arraysize(min_test_cases); ++i) { | 353 for (size_t i = 0; i < arraysize(min_test_cases); ++i) { |
363 filter.set_min_version(min_test_cases[i].min_version); | 354 filter.set_min_version(min_test_cases[i].min_version); |
364 const bool result = internal::CheckStudyVersion( | 355 const bool result = internal::CheckStudyVersion( |
365 filter, base::Version(min_test_cases[i].version)); | 356 filter, base::Version(min_test_cases[i].version)); |
366 EXPECT_EQ(min_test_cases[i].expected_result, result) << | 357 EXPECT_EQ(min_test_cases[i].expected_result, result) << |
367 "Min. version case " << i << " failed!"; | 358 "Min. version case " << i << " failed!"; |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
431 // Substring, so still invalid. | 422 // Substring, so still invalid. |
432 {"", "apple,pear,orange", "fancy INTEL SNapple device", false}, | 423 {"", "apple,pear,orange", "fancy INTEL SNapple device", false}, |
433 // Empty. | 424 // Empty. |
434 {"", "apple,pear,orange", "", true}, | 425 {"", "apple,pear,orange", "", true}, |
435 | 426 |
436 // Not testing when both are set as it should never occur and should be | 427 // Not testing when both are set as it should never occur and should be |
437 // considered undefined. | 428 // considered undefined. |
438 }; | 429 }; |
439 | 430 |
440 for (size_t i = 0; i < arraysize(test_cases); ++i) { | 431 for (size_t i = 0; i < arraysize(test_cases); ++i) { |
441 Study_Filter filter; | 432 Study::Filter filter; |
442 for (const std::string& cur : base::SplitString( | 433 for (const std::string& cur : base::SplitString( |
443 test_cases[i].hardware_class, ",", | 434 test_cases[i].hardware_class, ",", |
444 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) | 435 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) |
445 filter.add_hardware_class(cur); | 436 filter.add_hardware_class(cur); |
446 | 437 |
447 for (const std::string& cur : base::SplitString( | 438 for (const std::string& cur : base::SplitString( |
448 test_cases[i].exclude_hardware_class, ",", | 439 test_cases[i].exclude_hardware_class, ",", |
449 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) | 440 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) |
450 filter.add_exclude_hardware_class(cur); | 441 filter.add_exclude_hardware_class(cur); |
451 | 442 |
(...skipping 29 matching lines...) Expand all Loading... |
481 {"", "br,ca,us", "in", true}, | 472 {"", "br,ca,us", "in", true}, |
482 // Empty, which is what would happen if no country was returned from the | 473 // Empty, which is what would happen if no country was returned from the |
483 // server. | 474 // server. |
484 {"", "br,ca,us", "", true}, | 475 {"", "br,ca,us", "", true}, |
485 | 476 |
486 // Not testing when both are set as it should never occur and should be | 477 // Not testing when both are set as it should never occur and should be |
487 // considered undefined. | 478 // considered undefined. |
488 }; | 479 }; |
489 | 480 |
490 for (const auto& test : test_cases) { | 481 for (const auto& test : test_cases) { |
491 Study_Filter filter; | 482 Study::Filter filter; |
492 for (const std::string& country : base::SplitString( | 483 for (const std::string& country : base::SplitString( |
493 test.country, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) | 484 test.country, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) |
494 filter.add_country(country); | 485 filter.add_country(country); |
495 | 486 |
496 for (const std::string& exclude_country : base::SplitString( | 487 for (const std::string& exclude_country : base::SplitString( |
497 test.exclude_country, ",", | 488 test.exclude_country, ",", |
498 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) | 489 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) |
499 filter.add_exclude_country(exclude_country); | 490 filter.add_exclude_country(exclude_country); |
500 | 491 |
501 EXPECT_EQ(test.expected_result, | 492 EXPECT_EQ(test.expected_result, |
(...skipping 17 matching lines...) Expand all Loading... |
519 *study2 = *study1; | 510 *study2 = *study1; |
520 study2->mutable_experiment(0)->set_name("Bam"); | 511 study2->mutable_experiment(0)->set_name("Bam"); |
521 ASSERT_EQ(seed.study(0).name(), seed.study(1).name()); | 512 ASSERT_EQ(seed.study(0).name(), seed.study(1).name()); |
522 | 513 |
523 Study* study3 = seed.add_study(); | 514 Study* study3 = seed.add_study(); |
524 study3->set_name(kTrial3Name); | 515 study3->set_name(kTrial3Name); |
525 study3->set_default_experiment_name("Default"); | 516 study3->set_default_experiment_name("Default"); |
526 AddExperiment("A", 10, study3); | 517 AddExperiment("A", 10, study3); |
527 AddExperiment("Default", 25, study3); | 518 AddExperiment("Default", 25, study3); |
528 | 519 |
| 520 ClientFilterableState client_state; |
| 521 client_state.locale = "en-CA"; |
| 522 client_state.reference_date = base::Time::Now(); |
| 523 client_state.version = base::Version("20.0.0.0"); |
| 524 client_state.channel = Study::STABLE; |
| 525 client_state.form_factor = Study::DESKTOP; |
| 526 client_state.platform = Study::PLATFORM_ANDROID; |
| 527 |
529 std::vector<ProcessedStudy> processed_studies; | 528 std::vector<ProcessedStudy> processed_studies; |
530 FilterAndValidateStudies(seed, "en-CA", base::Time::Now(), | 529 FilterAndValidateStudies(seed, client_state, &processed_studies); |
531 base::Version("20.0.0.0"), Study_Channel_STABLE, | |
532 Study_FormFactor_DESKTOP, "", "", "", | |
533 &processed_studies); | |
534 | 530 |
535 // Check that only the first kTrial1Name study was kept. | 531 // Check that only the first kTrial1Name study was kept. |
536 ASSERT_EQ(2U, processed_studies.size()); | 532 ASSERT_EQ(2U, processed_studies.size()); |
537 EXPECT_EQ(kTrial1Name, processed_studies[0].study()->name()); | 533 EXPECT_EQ(kTrial1Name, processed_studies[0].study()->name()); |
538 EXPECT_EQ(kGroup1Name, processed_studies[0].study()->experiment(0).name()); | 534 EXPECT_EQ(kGroup1Name, processed_studies[0].study()->experiment(0).name()); |
539 EXPECT_EQ(kTrial3Name, processed_studies[1].study()->name()); | 535 EXPECT_EQ(kTrial3Name, processed_studies[1].study()->name()); |
540 } | 536 } |
541 | 537 |
542 TEST(VariationsStudyFilteringTest, FilterAndValidateStudiesWithCountry) { | 538 TEST(VariationsStudyFilteringTest, FilterAndValidateStudiesWithCountry) { |
543 const char kSessionCountry[] = "ca"; | 539 const char kSessionCountry[] = "ca"; |
544 const char kPermanentCountry[] = "us"; | 540 const char kPermanentCountry[] = "us"; |
545 | 541 |
546 struct { | 542 struct { |
547 Study_Consistency consistency; | 543 Study::Consistency consistency; |
548 const char* filter_country; | 544 const char* filter_country; |
549 const char* filter_exclude_country; | 545 const char* filter_exclude_country; |
550 bool expect_study_kept; | 546 bool expect_study_kept; |
551 } test_cases[] = { | 547 } test_cases[] = { |
552 // Country-agnostic studies should be kept regardless of country. | 548 // Country-agnostic studies should be kept regardless of country. |
553 {Study_Consistency_SESSION, nullptr, nullptr, true}, | 549 {Study::SESSION, nullptr, nullptr, true}, |
554 {Study_Consistency_PERMANENT, nullptr, nullptr, true}, | 550 {Study::PERMANENT, nullptr, nullptr, true}, |
555 | 551 |
556 // Session-consistency studies should obey the country code in the seed. | 552 // Session-consistency studies should obey the country code in the seed. |
557 {Study_Consistency_SESSION, kSessionCountry, nullptr, true}, | 553 {Study::SESSION, kSessionCountry, nullptr, true}, |
558 {Study_Consistency_SESSION, nullptr, kSessionCountry, false}, | 554 {Study::SESSION, nullptr, kSessionCountry, false}, |
559 {Study_Consistency_SESSION, kPermanentCountry, nullptr, false}, | 555 {Study::SESSION, kPermanentCountry, nullptr, false}, |
560 {Study_Consistency_SESSION, nullptr, kPermanentCountry, true}, | 556 {Study::SESSION, nullptr, kPermanentCountry, true}, |
561 | 557 |
562 // Permanent-consistency studies should obey the permanent-consistency | 558 // Permanent-consistency studies should obey the permanent-consistency |
563 // country code. | 559 // country code. |
564 {Study_Consistency_PERMANENT, kPermanentCountry, nullptr, true}, | 560 {Study::PERMANENT, kPermanentCountry, nullptr, true}, |
565 {Study_Consistency_PERMANENT, nullptr, kPermanentCountry, false}, | 561 {Study::PERMANENT, nullptr, kPermanentCountry, false}, |
566 {Study_Consistency_PERMANENT, kSessionCountry, nullptr, false}, | 562 {Study::PERMANENT, kSessionCountry, nullptr, false}, |
567 {Study_Consistency_PERMANENT, nullptr, kSessionCountry, true}, | 563 {Study::PERMANENT, nullptr, kSessionCountry, true}, |
568 }; | 564 }; |
569 | 565 |
570 for (const auto& test : test_cases) { | 566 for (const auto& test : test_cases) { |
571 VariationsSeed seed; | 567 VariationsSeed seed; |
572 Study* study = seed.add_study(); | 568 Study* study = seed.add_study(); |
573 study->set_name("study"); | 569 study->set_name("study"); |
574 study->set_default_experiment_name("Default"); | 570 study->set_default_experiment_name("Default"); |
575 AddExperiment("Default", 100, study); | 571 AddExperiment("Default", 100, study); |
576 study->set_consistency(test.consistency); | 572 study->set_consistency(test.consistency); |
577 if (test.filter_country) | 573 if (test.filter_country) |
578 study->mutable_filter()->add_country(test.filter_country); | 574 study->mutable_filter()->add_country(test.filter_country); |
579 if (test.filter_exclude_country) | 575 if (test.filter_exclude_country) |
580 study->mutable_filter()->add_exclude_country(test.filter_exclude_country); | 576 study->mutable_filter()->add_exclude_country(test.filter_exclude_country); |
581 | 577 |
| 578 ClientFilterableState client_state; |
| 579 client_state.locale = "en-CA"; |
| 580 client_state.reference_date = base::Time::Now(); |
| 581 client_state.version = base::Version("20.0.0.0"); |
| 582 client_state.channel = Study::STABLE; |
| 583 client_state.form_factor = Study::DESKTOP; |
| 584 client_state.platform = Study::PLATFORM_ANDROID; |
| 585 client_state.session_consistency_country = kSessionCountry; |
| 586 client_state.permanent_consistency_country = kPermanentCountry; |
| 587 |
582 std::vector<ProcessedStudy> processed_studies; | 588 std::vector<ProcessedStudy> processed_studies; |
583 FilterAndValidateStudies(seed, "en-CA", base::Time::Now(), | 589 FilterAndValidateStudies(seed, client_state, &processed_studies); |
584 base::Version("20.0.0.0"), Study_Channel_STABLE, | |
585 Study_FormFactor_DESKTOP, "", kSessionCountry, | |
586 kPermanentCountry, &processed_studies); | |
587 | 590 |
588 EXPECT_EQ(test.expect_study_kept, !processed_studies.empty()); | 591 EXPECT_EQ(test.expect_study_kept, !processed_studies.empty()); |
589 } | 592 } |
590 } | 593 } |
591 | 594 |
| 595 TEST(VariationsStudyFilteringTest, GetClientCountryForStudy_Session) { |
| 596 ClientFilterableState client_state; |
| 597 client_state.session_consistency_country = "session_country"; |
| 598 client_state.permanent_consistency_country = "permanent_country"; |
| 599 |
| 600 Study study; |
| 601 study.set_consistency(Study::SESSION); |
| 602 EXPECT_EQ("session_country", |
| 603 internal::GetClientCountryForStudy(study, client_state)); |
| 604 } |
| 605 |
| 606 TEST(VariationsStudyFilteringTest, GetClientCountryForStudy_Permanent) { |
| 607 ClientFilterableState client_state; |
| 608 client_state.session_consistency_country = "session_country"; |
| 609 client_state.permanent_consistency_country = "permanent_country"; |
| 610 |
| 611 Study study; |
| 612 study.set_consistency(Study::PERMANENT); |
| 613 EXPECT_EQ("permanent_country", |
| 614 internal::GetClientCountryForStudy(study, client_state)); |
| 615 } |
| 616 |
592 TEST(VariationsStudyFilteringTest, IsStudyExpired) { | 617 TEST(VariationsStudyFilteringTest, IsStudyExpired) { |
593 const base::Time now = base::Time::Now(); | 618 const base::Time now = base::Time::Now(); |
594 const base::TimeDelta delta = base::TimeDelta::FromHours(1); | 619 const base::TimeDelta delta = base::TimeDelta::FromHours(1); |
595 const struct { | 620 const struct { |
596 const base::Time expiry_date; | 621 const base::Time expiry_date; |
597 bool expected_result; | 622 bool expected_result; |
598 } expiry_test_cases[] = { | 623 } expiry_test_cases[] = { |
599 { now - delta, true }, | 624 { now - delta, true }, |
600 { now, true }, | 625 { now, true }, |
601 { now + delta, false }, | 626 { now + delta, false }, |
602 }; | 627 }; |
603 | 628 |
604 Study study; | 629 Study study; |
605 | 630 |
606 // Expiry date not set should result in false. | 631 // Expiry date not set should result in false. |
607 EXPECT_FALSE(internal::IsStudyExpired(study, now)); | 632 EXPECT_FALSE(internal::IsStudyExpired(study, now)); |
608 | 633 |
609 for (size_t i = 0; i < arraysize(expiry_test_cases); ++i) { | 634 for (size_t i = 0; i < arraysize(expiry_test_cases); ++i) { |
610 study.set_expiry_date(TimeToProtoTime(expiry_test_cases[i].expiry_date)); | 635 study.set_expiry_date(TimeToProtoTime(expiry_test_cases[i].expiry_date)); |
611 const bool result = internal::IsStudyExpired(study, now); | 636 const bool result = internal::IsStudyExpired(study, now); |
612 EXPECT_EQ(expiry_test_cases[i].expected_result, result) | 637 EXPECT_EQ(expiry_test_cases[i].expected_result, result) |
613 << "Case " << i << " failed!"; | 638 << "Case " << i << " failed!"; |
614 } | 639 } |
615 } | 640 } |
616 | 641 |
617 TEST(VariationsStudyFilteringTest, ValidateStudy) { | 642 TEST(VariationsStudyFilteringTest, ValidateStudy) { |
618 Study study; | 643 Study study; |
619 study.set_default_experiment_name("def"); | 644 study.set_default_experiment_name("def"); |
620 AddExperiment("abc", 100, &study); | 645 AddExperiment("abc", 100, &study); |
621 Study_Experiment* default_group = AddExperiment("def", 200, &study); | 646 Study::Experiment* default_group = AddExperiment("def", 200, &study); |
622 | 647 |
623 ProcessedStudy processed_study; | 648 ProcessedStudy processed_study; |
624 EXPECT_TRUE(processed_study.Init(&study, false)); | 649 EXPECT_TRUE(processed_study.Init(&study, false)); |
625 EXPECT_EQ(300, processed_study.total_probability()); | 650 EXPECT_EQ(300, processed_study.total_probability()); |
626 | 651 |
627 // Min version checks. | 652 // Min version checks. |
628 study.mutable_filter()->set_min_version("1.2.3.*"); | 653 study.mutable_filter()->set_min_version("1.2.3.*"); |
629 EXPECT_TRUE(processed_study.Init(&study, false)); | 654 EXPECT_TRUE(processed_study.Init(&study, false)); |
630 study.mutable_filter()->set_min_version("1.*.3"); | 655 study.mutable_filter()->set_min_version("1.*.3"); |
631 EXPECT_FALSE(processed_study.Init(&study, false)); | 656 EXPECT_FALSE(processed_study.Init(&study, false)); |
(...skipping 14 matching lines...) Expand all Loading... |
646 | 671 |
647 study.set_default_experiment_name("xyz"); | 672 study.set_default_experiment_name("xyz"); |
648 EXPECT_FALSE(processed_study.Init(&study, false)); | 673 EXPECT_FALSE(processed_study.Init(&study, false)); |
649 | 674 |
650 study.set_default_experiment_name("def"); | 675 study.set_default_experiment_name("def"); |
651 default_group->clear_name(); | 676 default_group->clear_name(); |
652 EXPECT_FALSE(processed_study.Init(&study, false)); | 677 EXPECT_FALSE(processed_study.Init(&study, false)); |
653 | 678 |
654 default_group->set_name("def"); | 679 default_group->set_name("def"); |
655 EXPECT_TRUE(processed_study.Init(&study, false)); | 680 EXPECT_TRUE(processed_study.Init(&study, false)); |
656 Study_Experiment* repeated_group = study.add_experiment(); | 681 Study::Experiment* repeated_group = study.add_experiment(); |
657 repeated_group->set_name("abc"); | 682 repeated_group->set_name("abc"); |
658 repeated_group->set_probability_weight(1); | 683 repeated_group->set_probability_weight(1); |
659 EXPECT_FALSE(processed_study.Init(&study, false)); | 684 EXPECT_FALSE(processed_study.Init(&study, false)); |
660 } | 685 } |
661 | 686 |
662 } // namespace variations | 687 } // namespace variations |
OLD | NEW |