| 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 |